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

Copy Entity with all its collections #15

Closed
knifesk opened this issue Jul 21, 2015 · 6 comments
Closed

Copy Entity with all its collections #15

knifesk opened this issue Jul 21, 2015 · 6 comments

Comments

@knifesk
Copy link

knifesk commented Jul 21, 2015

I have a parent entity named "Sitios" that haves 3 OneToMany associations: "Archivos", "Paginas" and "Hostings"... I am trying to clone the site including the files and pages, and resetting hostings to an empty collection and a "desarrollador" property that needs to be set to null.

this is my code:

$q = $this->entityManager
                ->createQuery('SELECT s,pg,fl FROM IDP:Sitios s
                                JOIN s.paginas pg
                                JOIN s.archivos fl
                                WHERE s.idSitio = :sid')
                ->setParameter('sid', $sid);

$s = $q->getSingleResult();

if ($s == null) {
    throw new EXP\NotFound('invalid_site');
}
$deepCopy = new DeepCopy();
$deepCopy->addFilter(new SetNullFilter(), new PropertyMatcher('Domain\Sitios', 'desarrollador'));
$deepCopy->addFilter(new DoctrineCollectionFilter(), new PropertyMatcher('Domain\Sitios', 'paginas'));
$deepCopy->addFilter(new DoctrineCollectionFilter(), new PropertyMatcher('Domain\Sitios', 'archivos'));
$deepCopy->addFilter(new DoctrineEmptyCollectionFilter(), new PropertyMatcher('Domain\Sitios', 'hostings'));
$sCopy = $deepCopy->copy($s);

$this->entityManager->persist($sCopy);

try {
    $this->entityManager->flush();
} catch (\Exception $e) {
    throw new EXP\InternalError($e->getMessage());
}

But only the Sitio class gets cloned and all the references remains to the original Paginas and Files objects... the desarrollador attribute is not set to null and hostings is alredy empty, so I cant tell if it is working or not...

I have also tried with the collections example

$deepCopy->addFilter(new DoctrineCollectionFilter(), new PropertyTypeMatcher('Doctrine\Common\Collections\Collection'));

but had no luck... can anyone give me a hand please?

@mnapoli
Copy link
Member

mnapoli commented Jul 22, 2015

Could you try debugging your code (with xdebug)?

@knifesk
Copy link
Author

knifesk commented Jul 22, 2015

Sadly I could not get xdebug to work in my centos server... I have not used it before, and I will have to setup a virtual machine for this specific task.. So, I'll need some time..

I've created a simplified version of the model using sqlite instead of mysql and everything worked as expected.. I guess the problem must be in my domain classes. They are quite complex, as Paginas have a Parent-Child relation and there are other relationships as each "Pagina" haves a "Contents" collection as well.. I don't see why it does't work, but I will keep loking into it..

A quick question, the $s variable it's a Proxy instance (not my actual class) I guess it has nothing to do with deepCopy, as the simplified version works.. but if I add "echos" to the copy method and other places around DeepCopy.php I dont see the expected output.. So, for example:

        foreach ($reflectedObject->getProperties() as $property) {
            echo $property->getName() . "\n";  //DEBUG
            $this->copyObjectProperty($newObject, $property);
        }

I get this output:

__initializer__
__cloner__
__isInitialized__
lazyPropertiesDefaults

And none of these properties are from my class, but from the Proxy

@knifesk
Copy link
Author

knifesk commented Jul 28, 2015

It seems that I have found the problem...

In my code I am getting a different object first from the database, which is related to the object I want to clone.. this class (Domain\Plantilla has a sitioDemo property).. doctrine is loading this, and when I want to clone this, what I actually have is a reference to the cached proxy for this object, so, when I do $deepCopy->copy($s) what I am actually cloning is a proxy, not the full object reference..

If I query the Sitio first, doctrine returns a pure \Domain\Sitio instance, not the proxy.. and copy works as expected.. I can solve this by cleaning the UnitOfWork, as the only thing I need from \Domain\Plantilla is the ID of Sitio:

This code works as excpected.

$p = $this->entityManager->find('Domain\Plantillas', $id_plant);
$sid = (int)$p->getSitioDemo()->getIdSitio();
$this->entityManager->getUnitOfWork()->clear();
$s = $this->entityManager->find('Domain\Sitios', $sid);

So, the problem is, if the entity is cached by the doctrine's UnitOfWork DeepCopy wont work.. and only will copy the "root" object and not it's "child" references..

Should I close this issue?

@mnapoli
Copy link
Member

mnapoli commented Jul 28, 2015

So to sum up (if I understood correctly), cloning a proxy object doesn't work? Maybe we could either make it work, or make it fail more explicitly? (e.g. throw an exception if the object is a proxy?)

@knifesk
Copy link
Author

knifesk commented Jul 29, 2015

Exactly.. but it should be analyzed better, because the proxy of Domain\Sitios that the class Domain\Plantilla returns is not working .. But the all the references in Domain\Sitios are proxies that gets cloned correctly.. It's like if the problem is in the "root" entity.

Let me test this further

@mnapoli
Copy link
Member

mnapoli commented Aug 28, 2015

I am merging this issue with #18 (same topic) so closing this one.

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

2 participants