Use integer Id to persist relation #6301

Closed
opened 2026-01-22 15:30:24 +01:00 by admin · 2 comments
Owner

Originally created by @PaulCombal on GitHub (Sep 22, 2019).

Originally assigned to: @Ocramius on GitHub.

Q A
Version 2.6.3

Support Question

I'm implementing a REST API, and I would like to implement a quick and easy way to create and persist entities.

Therefore, I created an entity like so, where $plain is a basic associative array:

    public function __construct($plain = null)
    {
        if ($plain != null) {
            foreach ($plain as $k => $v) {
                if (property_exists($this, $k))
                    $this->{$k} = $v;
                else
                    throw new Exception("Property $k does not exist in " . self::class);
            }
        }
    }

    /**
     * @ORM\ManyToOne(targetEntity="Category", inversedBy="children")
     */
    private $parent;

My frontend input will look something like this, and then decoded into the $plain array from above:

{
	"name": "FooBar",
	"parent": 1
}

When flushing, I'm greeted by a totally understandable Doctrine error, telling me that $parent is an integer and is not an entity as expected.

I'd like to mention that here, the "parent" will never be used by the framework, as I'm creating a new entity, all I want to do is write 1 in the parent_id column of my database.

Regarding the foreign key constraints, it's ok if I get an Exception from the database driver or anything else.

Is there any way I can do this, or what would be the best approach to this problem? Thanks

Originally created by @PaulCombal on GitHub (Sep 22, 2019). Originally assigned to: @Ocramius on GitHub. <!-- Fill in the relevant information below to help triage your issue. --> | Q | A |------------ | ----- | Version | 2.6.3 <!-- Before asking question here, please try asking on Gitter or Slack first. Find out more about Doctrine support channels here: https://www.doctrine-project.org/community/ Keep in mind that GitHub is primarily an issue tracker. --> ### Support Question <!-- Describe the issue you are facing here. --> I'm implementing a REST API, and I would like to implement a quick and easy way to create and persist entities. Therefore, I created an entity like so, where `$plain` is a basic associative array: ```php public function __construct($plain = null) { if ($plain != null) { foreach ($plain as $k => $v) { if (property_exists($this, $k)) $this->{$k} = $v; else throw new Exception("Property $k does not exist in " . self::class); } } } /** * @ORM\ManyToOne(targetEntity="Category", inversedBy="children") */ private $parent; ``` My frontend input will look something like this, and then decoded into the `$plain` array from above: ```json { "name": "FooBar", "parent": 1 } ``` When flushing, I'm greeted by a totally understandable Doctrine error, telling me that `$parent` is an integer and is not an entity as expected. I'd like to mention that here, the "parent" will never be used by the framework, as I'm creating a new entity, all I want to do is write `1` in the `parent_id` column of my database. Regarding the foreign key constraints, it's ok if I get an Exception from the database driver or anything else. Is there any way I can do this, or what would be the best approach to this problem? Thanks
admin added the Question label 2026-01-22 15:30:24 +01:00
admin closed this issue 2026-01-22 15:30:24 +01:00
Author
Owner

@Ocramius commented on GitHub (Sep 23, 2019):

Is there any way I can do this, or what would be the best approach to this problem? Thanks

Assuming you already know parent to be a valid foreign key (that respects constraints), you can pass a Parent reference to your constructor after having called EntityManager#getReference() with ['id' =>1] as identifier.

The ORM will work with that proxy (usually without trying to initialize it).

You must pass an object that is an instance of the referenced class though: in this case, the proxy would fulfill that role.

@Ocramius commented on GitHub (Sep 23, 2019): > Is there any way I can do this, or what would be the best approach to this problem? Thanks Assuming you already know `parent` to be a valid foreign key (that respects constraints), you can pass a `Parent` reference to your constructor after having called `EntityManager#getReference()` with `['id' =>1]` as identifier. The ORM will work with that proxy (usually without trying to initialize it). You must pass an object that is an instance of the referenced class though: in this case, the proxy would fulfill that role.
Author
Owner

@PaulCombal commented on GitHub (Sep 23, 2019):

Lord forgive my sins:

    public function createCategory(Req $request, EntityManagerInterface $em, Map $map) {
        $plain = $request->getJSON();
        $category = $map->newEntity($plain, Category::class);

        $em->persist($category);
        $em->flush();
        return $this->json($category->toArray());
    }
abstract class SuperEntity
{
    public function __set($name, $value)
    {
        if (property_exists($this, $name))
            $this->{$name} = $value;
        else
            throw new Exception("Property $name does not exist in " . self::class);

        return $this;
    }
}
/**
 * @ORM\Entity
 */
class Category extends SuperEntity
use Doctrine\Common\Annotations\AnnotationReader as DocReader;
...
    public function newEntity($plain, string $class): SuperEntity
    {
        $reader = new DocReader();
        $entity = new $class();

        foreach ($plain as $k => $v) {
            $entity->{$k} = $v;

            $reflector = new ReflectionProperty($entity, $k);
            $annotationObjects = $reader->getPropertyAnnotations($reflector);
            foreach ($annotationObjects as $object) {
                if ($object instanceof ORM\ManyToOne or $object instanceof ORM\OneToOne) {
                    $ns = substr(SuperEntity::class, 0, strrpos(SuperEntity::class, '\\'));
                    $classname = $ns . '\\' . $object->targetEntity;
                    $related_entity = $this->em->getReference($classname, intval($v));
                    $entity->{$k} = $related_entity;
                    break;
                }
            }
        }

        return $entity;
    }

Thanks @Ocramius for setting me on tracks, yet I still feel like there must be a more elegant way to put it all together.

@PaulCombal commented on GitHub (Sep 23, 2019): Lord forgive my sins: ```php public function createCategory(Req $request, EntityManagerInterface $em, Map $map) { $plain = $request->getJSON(); $category = $map->newEntity($plain, Category::class); $em->persist($category); $em->flush(); return $this->json($category->toArray()); } ``` ```php abstract class SuperEntity { public function __set($name, $value) { if (property_exists($this, $name)) $this->{$name} = $value; else throw new Exception("Property $name does not exist in " . self::class); return $this; } } ``` ```php /** * @ORM\Entity */ class Category extends SuperEntity ``` ```php use Doctrine\Common\Annotations\AnnotationReader as DocReader; ... public function newEntity($plain, string $class): SuperEntity { $reader = new DocReader(); $entity = new $class(); foreach ($plain as $k => $v) { $entity->{$k} = $v; $reflector = new ReflectionProperty($entity, $k); $annotationObjects = $reader->getPropertyAnnotations($reflector); foreach ($annotationObjects as $object) { if ($object instanceof ORM\ManyToOne or $object instanceof ORM\OneToOne) { $ns = substr(SuperEntity::class, 0, strrpos(SuperEntity::class, '\\')); $classname = $ns . '\\' . $object->targetEntity; $related_entity = $this->em->getReference($classname, intval($v)); $entity->{$k} = $related_entity; break; } } } return $entity; } ``` Thanks @Ocramius for setting me on tracks, yet I still feel like there must be a more elegant way to put it all together.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#6301