Merge branch 'hotfix/#1001-DDC-3005-defer-postload-event-after-fully-populated-associations'
Close #1001
This commit is contained in:
commit
a906295c65
@ -184,13 +184,6 @@ the life-time of their registered entities.
|
||||
invoked, after all references to entities have been removed from the unit of
|
||||
work. This event is not a lifecycle callback.
|
||||
|
||||
.. warning::
|
||||
|
||||
Note that the postLoad event occurs for an entity
|
||||
before any associations have been initialized. Therefore it is not
|
||||
safe to access associations in a postLoad callback or event
|
||||
handler.
|
||||
|
||||
.. warning::
|
||||
|
||||
Note that the postRemove event or any events triggered after an entity removal
|
||||
|
@ -96,6 +96,8 @@ class DefaultCollectionHydrator implements CollectionHydrator
|
||||
$collection->hydrateSet($index, $entity);
|
||||
});
|
||||
|
||||
$this->uow->hydrationComplete();
|
||||
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
|
@ -151,6 +151,10 @@ class DefaultEntityHydrator implements EntityHydrator
|
||||
$this->uow->registerManaged($entity, $key->identifier, $data);
|
||||
}
|
||||
|
||||
return $this->uow->createEntity($entry->class, $data, $hints);
|
||||
$result = $this->uow->createEntity($entry->class, $data, $hints);
|
||||
|
||||
$this->uow->hydrationComplete();
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
@ -149,6 +149,8 @@ class DefaultQueryCache implements QueryCache
|
||||
$this->cacheLogger->entityCacheMiss($assocRegion->getName(), $assocKey);
|
||||
}
|
||||
|
||||
$this->uow->hydrationComplete();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -176,6 +178,8 @@ class DefaultQueryCache implements QueryCache
|
||||
$this->cacheLogger->entityCacheMiss($assocRegion->getName(), $assocKey);
|
||||
}
|
||||
|
||||
$this->uow->hydrationComplete();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -196,6 +200,8 @@ class DefaultQueryCache implements QueryCache
|
||||
$result[$index] = $this->uow->createEntity($entityEntry->class, $data, self::$hints);
|
||||
}
|
||||
|
||||
$this->uow->hydrationComplete();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
@ -145,8 +145,10 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$this->resultPointers = array();
|
||||
|
||||
if ($eagerLoad) {
|
||||
$this->_em->getUnitOfWork()->triggerEagerLoads();
|
||||
$this->_uow->triggerEagerLoads();
|
||||
}
|
||||
|
||||
$this->_uow->hydrationComplete();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -47,6 +47,17 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
$this->class = $this->getClassMetadata(reset($this->_rsm->aliasMap));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function cleanup()
|
||||
{
|
||||
parent::cleanup();
|
||||
|
||||
$this->_uow->triggerEagerLoads();
|
||||
$this->_uow->hydrationComplete();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -79,7 +90,7 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
if ($metaMappingDiscrColumnName = array_search($discrColumnName, $this->_rsm->metaMappings)) {
|
||||
$discrColumnName = $metaMappingDiscrColumnName;
|
||||
}
|
||||
|
||||
|
||||
if ( ! isset($sqlResult[$discrColumnName])) {
|
||||
throw HydrationException::missingDiscriminatorColumn($entityName, $discrColumnName, key($this->_rsm->aliasMap));
|
||||
}
|
||||
|
103
lib/Doctrine/ORM/Internal/HydrationCompleteHandler.php
Normal file
103
lib/Doctrine/ORM/Internal/HydrationCompleteHandler.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Internal;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Event\LifecycleEventArgs;
|
||||
use Doctrine\ORM\Event\ListenersInvoker;
|
||||
use Doctrine\ORM\Events;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
|
||||
/**
|
||||
* Class, which can handle completion of hydration cycle and produce some of tasks.
|
||||
* In current implementation triggers deferred postLoad event.
|
||||
*
|
||||
* @author Artur Eshenbrener <strate@yandex.ru>
|
||||
* @since 2.5
|
||||
*/
|
||||
final class HydrationCompleteHandler
|
||||
{
|
||||
/**
|
||||
* @var ListenersInvoker
|
||||
*/
|
||||
private $listenersInvoker;
|
||||
|
||||
/**
|
||||
* @var EntityManagerInterface
|
||||
*/
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* @var array[]
|
||||
*/
|
||||
private $deferredPostLoadInvocations = array();
|
||||
|
||||
/**
|
||||
* Constructor for this object
|
||||
*
|
||||
* @param ListenersInvoker $listenersInvoker
|
||||
* @param EntityManagerInterface $em
|
||||
*/
|
||||
public function __construct(ListenersInvoker $listenersInvoker, EntityManagerInterface $em)
|
||||
{
|
||||
$this->listenersInvoker = $listenersInvoker;
|
||||
$this->em = $em;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method schedules invoking of postLoad entity to the very end of current hydration cycle.
|
||||
*
|
||||
* @param ClassMetadata $class
|
||||
* @param object $entity
|
||||
*/
|
||||
public function deferPostLoadInvoking(ClassMetadata $class, $entity)
|
||||
{
|
||||
$invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::postLoad);
|
||||
|
||||
if ($invoke === ListenersInvoker::INVOKE_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->deferredPostLoadInvocations[] = array($class, $invoke, $entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should me called after any hydration cycle completed.
|
||||
*
|
||||
* Method fires all deferred invocations of postLoad events
|
||||
*/
|
||||
public function hydrationComplete()
|
||||
{
|
||||
$toInvoke = $this->deferredPostLoadInvocations;
|
||||
$this->deferredPostLoadInvocations = array();
|
||||
|
||||
foreach ($toInvoke as $classAndEntity) {
|
||||
list($class, $invoke, $entity) = $classAndEntity;
|
||||
|
||||
$this->listenersInvoker->invoke(
|
||||
$class,
|
||||
Events::postLoad,
|
||||
$entity,
|
||||
new LifecycleEventArgs($entity, $this->em),
|
||||
$invoke
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -20,6 +20,7 @@
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
use Doctrine\DBAL\LockMode;
|
||||
use Doctrine\ORM\Internal\HydrationCompleteHandler;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use UnexpectedValueException;
|
||||
@ -276,6 +277,13 @@ class UnitOfWork implements PropertyChangedListener
|
||||
*/
|
||||
protected $hasCache = false;
|
||||
|
||||
/**
|
||||
* Helper for handling completion of hydration
|
||||
*
|
||||
* @var HydrationCompleteHandler
|
||||
*/
|
||||
private $hydrationCompleteHandler;
|
||||
|
||||
/**
|
||||
* Initializes a new UnitOfWork instance, bound to the given EntityManager.
|
||||
*
|
||||
@ -283,11 +291,12 @@ class UnitOfWork implements PropertyChangedListener
|
||||
*/
|
||||
public function __construct(EntityManager $em)
|
||||
{
|
||||
$this->em = $em;
|
||||
$this->evm = $em->getEventManager();
|
||||
$this->listenersInvoker = new ListenersInvoker($em);
|
||||
$this->hasCache = $em->getConfiguration()->isSecondLevelCacheEnabled();
|
||||
$this->identifierFlattener = new IdentifierFlattener($this, $em->getMetadataFactory());
|
||||
$this->em = $em;
|
||||
$this->evm = $em->getEventManager();
|
||||
$this->listenersInvoker = new ListenersInvoker($em);
|
||||
$this->hasCache = $em->getConfiguration()->isSecondLevelCacheEnabled();
|
||||
$this->identifierFlattener = new IdentifierFlattener($this, $em->getMetadataFactory());
|
||||
$this->hydrationCompleteHandler = new HydrationCompleteHandler($this->listenersInvoker, $em);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2801,11 +2810,8 @@ class UnitOfWork implements PropertyChangedListener
|
||||
}
|
||||
|
||||
if ($overrideLocalValues) {
|
||||
$invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::postLoad);
|
||||
|
||||
if ($invoke !== ListenersInvoker::INVOKE_NONE) {
|
||||
$this->listenersInvoker->invoke($class, Events::postLoad, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
|
||||
}
|
||||
// defer invoking of postLoad event to hydration complete step
|
||||
$this->hydrationCompleteHandler->deferPostLoadInvoking($class, $entity);
|
||||
}
|
||||
|
||||
return $entity;
|
||||
@ -3379,4 +3385,15 @@ class UnitOfWork implements PropertyChangedListener
|
||||
|
||||
return $id1 === $id2 || implode(' ', $id1) === implode(' ', $id2);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method called by hydrators, and indicates that hydrator totally completed current hydration cycle.
|
||||
* Unit of work able to fire deferred events, related to loading events here.
|
||||
*
|
||||
* @internal should be called internally from object hydrators
|
||||
*/
|
||||
public function hydrationComplete()
|
||||
{
|
||||
$this->hydrationCompleteHandler->hydrationComplete();
|
||||
}
|
||||
}
|
||||
|
@ -236,6 +236,9 @@ class CmsUser
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CmsEmail
|
||||
*/
|
||||
public function getEmail() { return $this->email; }
|
||||
|
||||
public function setEmail(CmsEmail $email = null) {
|
||||
@ -387,7 +390,7 @@ class CmsUser
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
|
||||
$metadata->addSqlResultSetMapping(array(
|
||||
'name' => 'mappingMultipleJoinsEntityResults',
|
||||
'entities' => array(array(
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\Common\Util\ClassUtils;
|
||||
use Doctrine\Tests\Models\CMS\CmsUser;
|
||||
use Doctrine\Tests\Models\CMS\CmsPhonenumber;
|
||||
use Doctrine\Tests\Models\CMS\CmsAddress;
|
||||
@ -203,6 +204,37 @@ class PostLoadEventTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$phonenumbersCol->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-3005
|
||||
*/
|
||||
public function testAssociationsArePopulatedWhenEventIsFired()
|
||||
{
|
||||
$checkerListener = new PostLoadListenerCheckAssociationsArePopulated();
|
||||
$this->_em->getEventManager()->addEventListener(array(Events::postLoad), $checkerListener);
|
||||
|
||||
$qb = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser')->createQueryBuilder('u');
|
||||
$qb->leftJoin('u.email', 'email');
|
||||
$qb->addSelect('email');
|
||||
$qb->getQuery()->getSingleResult();
|
||||
|
||||
$this->assertTrue($checkerListener->checked, 'postLoad event is not invoked');
|
||||
$this->assertTrue($checkerListener->populated, 'Association of email is not populated in postLoad event');
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-3005
|
||||
*/
|
||||
public function testEventRaisedCorrectTimesWhenOtherEntityLoadedInEventHandler()
|
||||
{
|
||||
$eventManager = $this->_em->getEventManager();
|
||||
$listener = new PostLoadListenerLoadEntityInEventHandler();
|
||||
$eventManager->addEventListener(array(Events::postLoad), $listener);
|
||||
|
||||
$this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||
$this->assertSame(1, $listener->countHandledEvents('Doctrine\Tests\Models\CMS\CmsUser'), 'Doctrine\Tests\Models\CMS\CmsUser should be handled once!');
|
||||
$this->assertSame(1, $listener->countHandledEvents('Doctrine\Tests\Models\CMS\CmsEmail'), '\Doctrine\Tests\Models\CMS\CmsEmail should be handled once!');
|
||||
}
|
||||
|
||||
private function loadFixture()
|
||||
{
|
||||
$user = new CmsUser;
|
||||
@ -248,3 +280,46 @@ class PostLoadListener
|
||||
echo 'Should never be called!';
|
||||
}
|
||||
}
|
||||
|
||||
class PostLoadListenerCheckAssociationsArePopulated
|
||||
{
|
||||
public $checked = false;
|
||||
|
||||
public $populated = false;
|
||||
|
||||
public function postLoad(LifecycleEventArgs $event)
|
||||
{
|
||||
$object = $event->getObject();
|
||||
if ($object instanceof CmsUser) {
|
||||
if ($this->checked) {
|
||||
throw new \RuntimeException('Expected to be one user!');
|
||||
}
|
||||
$this->checked = true;
|
||||
$this->populated = null !== $object->getEmail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PostLoadListenerLoadEntityInEventHandler
|
||||
{
|
||||
private $firedByClasses = array();
|
||||
|
||||
public function postLoad(LifecycleEventArgs $event)
|
||||
{
|
||||
$object = $event->getObject();
|
||||
$class = ClassUtils::getClass($object);
|
||||
if (!isset($this->firedByClasses[$class])) {
|
||||
$this->firedByClasses[$class] = 1;
|
||||
} else {
|
||||
$this->firedByClasses[$class]++;
|
||||
}
|
||||
if ($object instanceof CmsUser) {
|
||||
$object->getEmail()->getEmail();
|
||||
}
|
||||
}
|
||||
|
||||
public function countHandledEvents($className)
|
||||
{
|
||||
return isset($this->firedByClasses[$className]) ? $this->firedByClasses[$className] : 0;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,199 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\ORM\Internal;
|
||||
|
||||
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
|
||||
use Doctrine\ORM\Event\ListenersInvoker;
|
||||
use Doctrine\ORM\Events;
|
||||
use Doctrine\ORM\Internal\HydrationCompleteHandler;
|
||||
use PHPUnit_Framework_TestCase;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Tests for {@see \Doctrine\ORM\Internal\HydrationCompleteHandler}
|
||||
*
|
||||
* @covers \Doctrine\ORM\Internal\HydrationCompleteHandler
|
||||
*/
|
||||
class HydrationCompleteHandlerTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var \Doctrine\ORM\Event\ListenersInvoker|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
private $listenersInvoker;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\EntityManagerInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
private $entityManager;
|
||||
|
||||
/**
|
||||
* @var HydrationCompleteHandler
|
||||
*/
|
||||
private $handler;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function setUp()
|
||||
{
|
||||
$this->listenersInvoker = $this->getMock('Doctrine\ORM\Event\ListenersInvoker', array(), array(), '', false);
|
||||
$this->entityManager = $this->getMock('Doctrine\ORM\EntityManagerInterface');
|
||||
$this->handler = new HydrationCompleteHandler($this->listenersInvoker, $this->entityManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider testGetValidListenerInvocationFlags
|
||||
*
|
||||
* @param int $listenersFlag
|
||||
*/
|
||||
public function testDefersPostLoadOfEntity($listenersFlag)
|
||||
{
|
||||
/* @var $metadata \Doctrine\ORM\Mapping\ClassMetadata */
|
||||
$metadata = $this->getMock('Doctrine\ORM\Mapping\ClassMetadata', array(), array(), '', false);
|
||||
$entity = new stdClass();
|
||||
$entityManager = $this->entityManager;
|
||||
|
||||
$this
|
||||
->listenersInvoker
|
||||
->expects($this->any())
|
||||
->method('getSubscribedSystems')
|
||||
->with($metadata)
|
||||
->will($this->returnValue($listenersFlag));
|
||||
|
||||
$this->handler->deferPostLoadInvoking($metadata, $entity);
|
||||
|
||||
$this
|
||||
->listenersInvoker
|
||||
->expects($this->once())
|
||||
->method('invoke')
|
||||
->with(
|
||||
$metadata,
|
||||
Events::postLoad,
|
||||
$entity,
|
||||
$this->callback(function (LifecycleEventArgs $args) use ($entityManager, $entity) {
|
||||
return $entity === $args->getEntity() && $entityManager === $args->getObjectManager();
|
||||
}),
|
||||
$listenersFlag
|
||||
);
|
||||
|
||||
$this->handler->hydrationComplete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider testGetValidListenerInvocationFlags
|
||||
*
|
||||
* @param int $listenersFlag
|
||||
*/
|
||||
public function testDefersPostLoadOfEntityOnlyOnce($listenersFlag)
|
||||
{
|
||||
/* @var $metadata \Doctrine\ORM\Mapping\ClassMetadata */
|
||||
$metadata = $this->getMock('Doctrine\ORM\Mapping\ClassMetadata', array(), array(), '', false);
|
||||
$entity = new stdClass();
|
||||
|
||||
$this
|
||||
->listenersInvoker
|
||||
->expects($this->any())
|
||||
->method('getSubscribedSystems')
|
||||
->with($metadata)
|
||||
->will($this->returnValue($listenersFlag));
|
||||
|
||||
$this->handler->deferPostLoadInvoking($metadata, $entity);
|
||||
|
||||
$this->listenersInvoker->expects($this->once())->method('invoke');
|
||||
|
||||
$this->handler->hydrationComplete();
|
||||
$this->handler->hydrationComplete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider testGetValidListenerInvocationFlags
|
||||
*
|
||||
* @param int $listenersFlag
|
||||
*/
|
||||
public function testDefersMultiplePostLoadOfEntity($listenersFlag)
|
||||
{
|
||||
/* @var $metadata1 \Doctrine\ORM\Mapping\ClassMetadata */
|
||||
/* @var $metadata2 \Doctrine\ORM\Mapping\ClassMetadata */
|
||||
$metadata1 = $this->getMock('Doctrine\ORM\Mapping\ClassMetadata', array(), array(), '', false);
|
||||
$metadata2 = $this->getMock('Doctrine\ORM\Mapping\ClassMetadata', array(), array(), '', false);
|
||||
$entity1 = new stdClass();
|
||||
$entity2 = new stdClass();
|
||||
$entityManager = $this->entityManager;
|
||||
|
||||
$this
|
||||
->listenersInvoker
|
||||
->expects($this->any())
|
||||
->method('getSubscribedSystems')
|
||||
->with($this->logicalOr($metadata1, $metadata2))
|
||||
->will($this->returnValue($listenersFlag));
|
||||
|
||||
$this->handler->deferPostLoadInvoking($metadata1, $entity1);
|
||||
$this->handler->deferPostLoadInvoking($metadata2, $entity2);
|
||||
|
||||
$this
|
||||
->listenersInvoker
|
||||
->expects($this->exactly(2))
|
||||
->method('invoke')
|
||||
->with(
|
||||
$this->logicalOr($metadata1, $metadata2),
|
||||
Events::postLoad,
|
||||
$this->logicalOr($entity1, $entity2),
|
||||
$this->callback(function (LifecycleEventArgs $args) use ($entityManager, $entity1, $entity2) {
|
||||
return in_array($args->getEntity(), array($entity1, $entity2), true)
|
||||
&& $entityManager === $args->getObjectManager();
|
||||
}),
|
||||
$listenersFlag
|
||||
);
|
||||
|
||||
$this->handler->hydrationComplete();
|
||||
}
|
||||
|
||||
public function testSkipsDeferredPostLoadOfMetadataWithNoInvokedListeners()
|
||||
{
|
||||
/* @var $metadata \Doctrine\ORM\Mapping\ClassMetadata */
|
||||
$metadata = $this->getMock('Doctrine\ORM\Mapping\ClassMetadata', array(), array(), '', false);
|
||||
$entity = new stdClass();
|
||||
|
||||
$this
|
||||
->listenersInvoker
|
||||
->expects($this->any())
|
||||
->method('getSubscribedSystems')
|
||||
->with($metadata)
|
||||
->will($this->returnValue(ListenersInvoker::INVOKE_NONE));
|
||||
|
||||
$this->handler->deferPostLoadInvoking($metadata, $entity);
|
||||
|
||||
$this->listenersInvoker->expects($this->never())->method('invoke');
|
||||
|
||||
$this->handler->hydrationComplete();
|
||||
}
|
||||
|
||||
public function testGetValidListenerInvocationFlags()
|
||||
{
|
||||
return array(
|
||||
array(ListenersInvoker::INVOKE_LISTENERS),
|
||||
array(ListenersInvoker::INVOKE_CALLBACKS),
|
||||
array(ListenersInvoker::INVOKE_MANAGER),
|
||||
array(ListenersInvoker::INVOKE_LISTENERS | ListenersInvoker::INVOKE_CALLBACKS),
|
||||
array(ListenersInvoker::INVOKE_LISTENERS | ListenersInvoker::INVOKE_MANAGER),
|
||||
array(ListenersInvoker::INVOKE_LISTENERS | ListenersInvoker::INVOKE_CALLBACKS | ListenersInvoker::INVOKE_MANAGER),
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user