orm
orm copied to clipboard
Incorrect / lost cloning of an associated entity with LazyGhosts
Bug Report
| Q | A |
|---|---|
| Version | 2.19.3 / 3.x |
Summary
When you clone an entity with an associated entity that is loaded as a Lazy Ghost Proxy, in certain circumstances, you lose the previous cloning functionality.
In most cases, with a clone, it is just a reference to the associated entity.
However, in oneToOne relationships, orm cannot keep the reference. You would have to duplicate the entity properties.
Preivous
With enable_lazy_ghost_objects: false, we used to have \Doctrine\ORM\Proxy\ProxyFactory::createCloner() to finalize proxy entities when cloned. This was deprecated. I would assume its functionality should be preserved.
Current
With enable_lazy_ghost_objects: true, we rely on \Doctrine\ORM\Proxy\ProxyFactory::getProxyFactory(). This has an initializer that will initialize identifiers correctly. However all other data is lost.
Current behavior
Lets say we have a Parent $parent entity with a Child $child entity with a OneToOne relationship.
And Child has a required property $name. and a auto generated ID property $id.
class Parent {
#[ORM\OneToOne(targetEntity: Child::class, cascade: ['persist'], inversedBy: 'parent')]
private ?Child $child = null;
}
class Child {
#[ORM\OneToOne(mappedBy: 'child', targetEntity: Parent::class)]
private Parent $parent;
#[ORM\Column(length: 255, nullable: false)]
private string $name;
....
}
$parent->getChild(); // Proxy of $child. Empty.
$clonedParent = clone $parent;
$clonedParent->getChild(); // Proxy of $child. Still Empty.
$entityManager->persist($clonedParent);
$entityManager->flush() // Error! $name is null.
Expected behavior
$parent->getChild(); // Proxy of $child. Empty.
$clonedParent = clone $parent;
$clonedParent->getChild(); // Proxy of $child. Still Empty.
$entityManager->persist($clonedParent);
$entityManager->flush() // New $clonedParent persisted. New $child persisted with different ID and same properties. (Same as before).
Current workaround
You can workaround this by forcing the Proxied entity to fully initialize before cloning
$parent->getChild(); // Proxy of $child. Empty.
$parent->getChild()->getName(); // Force orm to load Proxy.
$parent->getChild(); // Now a fully loaded Proxy;
$clonedParent = clone $parent;
$clonedParent->getChild(); // Proxy of $child. Fully loaded.
$entityManager->persist($clonedParent);
$entityManager->flush() // Persisted as expected
How to reproduce
Reproducer > https://github.com/jonnyeom/clone-lazy-ghost-proxy-reproducer
Possible solution
I honestly think all we need is to restore the __clone() on the Proxy entity.
Here is the reproducer > https://github.com/jonnyeom/clone-lazy-ghost-proxy-reproducer
This also happens in doctrine/mongodb-odm and data is lost completely on cloning.
@jonnyeom Could you find a better workaround?
@beberlei is cloning entities a valid and supported use case in the first place?
@jonnyeom Could you find a better workaround?
No I havent! I just have an extra line of code to ensure initialization. and commented this issue for now. Its a little tacky but its working for us!