Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect / lost cloning of an associated entity with LazyGhosts #11787

Open
jonnyeom opened this issue Jan 8, 2025 · 1 comment
Open

Incorrect / lost cloning of an associated entity with LazyGhosts #11787

jonnyeom opened this issue Jan 8, 2025 · 1 comment

Comments

@jonnyeom
Copy link
Contributor

jonnyeom commented Jan 8, 2025

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.

@jonnyeom
Copy link
Contributor Author

jonnyeom commented Jan 9, 2025

Here is the reproducer > https://github.com/jonnyeom/clone-lazy-ghost-proxy-reproducer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant