[DDC-54] Trigger postLoad events and callbacks after associations have been initialized Created: 15/Oct/09  Updated: 03/Sep/13

Status: In Progress
Project: Doctrine 2 - ORM
Component/s: ORM
Affects Version/s: 2.0-ALPHA2
Fix Version/s: 2.x
Security Level: All

Type: Improvement Priority: Major
Reporter: Roman S. Borschel Assignee: Benjamin Eberlei
Resolution: Unresolved Votes: 7
Labels: None


 Description   

Currently the postLoad events and callbacks are triggered after the entity has been created and filled with its "primitive" state but before associations are available. The postLoad events and callbacks should be postponed so that they are triggered after associations have been initialized.



 Comments   
Comment by Roman S. Borschel [ 30/Aug/10 ]

If this is to be included in 2.0 it needs to happen for RC1. However, it is not clear yet whether it will be done in time.

Comment by Benjamin Eberlei [ 23/Sep/10 ]

How would you solve this Roman? I thought of adding a query hint so that the postLoad inside unit of work is not triggered and gathering all the entities that have a post load event in an array inside the object hydrator, then iterating it after taking the snapshots of all collections inside hydrateAll

Comment by Roman S. Borschel [ 24/Sep/10 ]

@Benjamin: Not sure what you would use the query hint for but in general that is the approach I had in mind, yes. You can't get around iterating over the entities after the actual hydration.

Comment by Benjamin Eberlei [ 27/Sep/10 ]

The query hint would do something like:

        //TODO: These should be invoked later, after hydration, because associations may not yet be loaded here.
        if (isset($class->lifecycleCallbacks[Events::postLoad]) && !isset($hints['hydrationPostLoad'])) {
            $class->invokeLifecycleCallbacks(Events::postLoad, $entity);
        }
        if ($this->evm->hasListeners(Events::postLoad) && !isset($hints['hydrationPostLoad'])) {
            $this->evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($entity, $this->em));
        }

another way would be to move that code out of UoW::createEntity completly and have the persisters call it when they use that method.

Comment by Roman S. Borschel [ 28/Sep/10 ]

Leaving that code in UoW does not make sense to me, if it is moved, it needs to be moved completely. Why do you think the persisters should do it? Initially I thought collecting the affected entities during hydration and then when hydration is done iterating over them and triggering the postLoad events.

Comment by Benjamin Eberlei [ 28/Sep/10 ]

Yes but postLoad has to be triggered for non Hydrated entities (i.e. Persister) also

Comment by Benjamin Eberlei [ 30/Oct/10 ]

Moved back

Comment by Kacper Gunia [ 15/Apr/12 ]

Hi Gyus, I need access to associations in postLoad or similar event, and my idea is to dispatch new event after full initialisation of object, what do You think about it? If I can help please let me know It's important for me.

Comment by Alexander Pasichnick [ 25/Sep/12 ]

Now in my PostLoad access to associations is work fine. Why this issue is still in Unresolved status?

Comment by Ɓukasz Cybula [ 11/Oct/12 ]

What do you (Roman and Benjamin) think about adding postHydrate event which would be called within ObjectHydrator::hydrateAllData() on every entity collected during hydration? I could prepare a patch for this. I personally think this would be better than adding a hint that changes behaviour of postLoad event.

Comment by Slavik Derevyanko [ 07/Jun/13 ]

Just stumbled upon this issue. Seems like my associated entities aren't yet loaded in PostLoad event handler.
Doctrine version "doctrine/orm": "2.3.1"

I've noticed that I have two different paths of execution:
1. When the find() method is used to retrieve the entity, SimpleObjectHydrator is used to perform a hydration and the associations are made available in PostLoad event:
bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php.Doctrine\ORM\Mapping\ClassMetadataInfo->invokeLifecycleCallbacks : lineno 2312() bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php at line 2312
bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php.Doctrine\ORM\UnitOfWork->createEntity : lineno 2610() bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php at line 2610
bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php.Doctrine\ORM\Internal\Hydration\SimpleObjectHydrator->hydrateRowData : lineno 135() bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php at line 135
bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php.Doctrine\ORM\Internal\Hydration\SimpleObjectHydrator->hydrateAllData : lineno 50() bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php at line 50
bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php.Doctrine\ORM\Internal\Hydration\AbstractHydrator->hydrateAll : lineno 111() bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php at line 111
bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php.Doctrine\ORM\Persisters\BasicEntityPersister->load : lineno 678() bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php at line 678
bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php.Doctrine\ORM\EntityManager->find : lineno 413() bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php at line 413
bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php.Doctrine\ORM\EntityRepository->find : lineno 131() bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php at line 131

2. When the DQL is used, ObjectHydrator is used to perform a hydration, and the associations aren't made ready in PostLoad event:
bvdpetroleum/src/BVD/PetroleumBundle/Entity/FuelCard.php.BVD\PetroleumBundle\Entity\FuelCard->retrieveNumbers : lineno 304() bvdpetroleum/src/BVD/PetroleumBundle/Entity/FuelCard.php at line 304
bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php.Doctrine\ORM\Mapping\ClassMetadataInfo->invokeLifecycleCallbacks : lineno 2312() bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php at line 2312
bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php.Doctrine\ORM\UnitOfWork->createEntity : lineno 2610() bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php at line 2610
bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php.Doctrine\ORM\Internal\Hydration\ObjectHydrator->_getEntity : lineno 245() bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php at line 245
bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php.Doctrine\ORM\Internal\Hydration\ObjectHydrator->hydrateRowData : lineno 478() bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php at line 478
bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php.Doctrine\ORM\Internal\Hydration\ObjectHydrator->hydrateAllData : lineno 149() bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php at line 149
bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php.Doctrine\ORM\Internal\Hydration\AbstractHydrator->hydrateAll : lineno 111() bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php at line 111
bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/AbstractQuery.php.Doctrine\ORM\AbstractQuery->execute : lineno 747() bvdpetroleum/vendor/doctrine/orm/lib/Doctrine/ORM/AbstractQuery.php at line 747

Hope this helps to solve the issue.

Comment by Valera Leontyev [ 03/Sep/13 ]

This issue is very important in my opinion. I can't come up with any workaround to resolve it. Only possible way to detect fully loaded state is to call entity method from outside which is too rude and dirty.

Generated at Sun Dec 21 10:52:26 UTC 2014 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.