2

我有事件监听器preUpdate

public function preUpdate(PreUpdateEventArgs $args) {        
    $user = $args->getEntity();
    if($user instanceof \iTracker\UserBundle\Entity\User) {
        if($args->hasChangedField('userGroup')) {

            $old = $args->getOldValue('userGroup');
            $new = $args->getNewValue('userGroup');

            $em = $args->getEntityManager();

            $old->setAmount($old->getAmount() - 1);
            $em->persist($old);

            $new->setAmount($new->getAmount() + 1);
            $em->persist($new);
            $em->flush();
        }
    }
}

提交表格后,我得到FatalErrorException: Error: Maximum function nesting level of '100' reached, aborting! in /var/www/issue/app/cache/dev/classes.php line 6123

在 /var/www/issue/app/cache/dev/classes.php 第 6123 行中的 ErrorHandler->handleFatal() 在 /var/www/issue/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Debug/ ErrorHandler.php 第 0 行 NormalizerFormatter->normalize() in /var/www/issue/app/cache/dev/classes.php LineFormatter->normalize() in /var/www/issue/app/cache/ 第 6198 行dev/classes.php 第 6112 行 NormalizerFormatter->format() in /var/www/issue/app/cache/dev/classes.php LineFormatter->format() in /var/www/issue/app/ 第 6172 行cache/dev/classes.php 6320 行 AbstractProcessingHandler->handle() in /var/www/issue/app/cache/dev/classes.php 6646 行 Logger->addRecord() in /var/www/issue/ app/cache/dev/classes.php 第 6710 行,位于 /var/www/issue/vendor/symfony/symfony/src/Symfony/Bridge/Doctrine/Logger/DbalLogger 中的 Logger->debug()。php 第 72 行 DbalLogger->log() in /var/www/issue/vendor/symfony/symfony/src/Symfony/Bridge/Doctrine/Logger/DbalLogger.php 第 50 行 DbalLogger->startQuery() in /var/ www/issue/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/LoggerChain.php 第 50 行 LoggerChain->startQuery() 在 /var/www/issue/vendor/doctrine/dbal/lib/Doctrine/DBAL/ Connection.php 第 774 行 Connection->executeUpdate() in /var/www/issue/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php 第 447 行 BasicEntityPersister->_updateTable() in /var/ www/issue/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php 357 行 BasicEntityPersister->update() in /var/www/issue/vendor/doctrine/orm/lib/Doctrine/ORM/ UnitOfWork.php 第 984 行 UnitOfWork->/var/www/issue/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php 中的 executeUpdates() 在 /var/www/issue/vendor/doctrine/orm/lib 中 UnitOfWork->commit() 的第 317 行/Doctrine/ORM/EntityManager.php 第 355 行在 /var/www/issue/src/iTracker/UserBundle/Listener/UserGroupAmount.php 第 41 行的 EntityManager->flush() 和这个

  • 在 /var/www/issue/vendor/symfony/symfony/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php 第 61 行中的 UserGroupAmount->preUpdate()
  • 在 /var/www/issue/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php 第 980 行中的 ContainerAwareEventManager->dispatchEvent()
  • 在 /var/www/issue/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php 第 317 行中的 UnitOfWork->executeUpdates()
  • 在 /var/www/issue/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php 第 355 行中的 UnitOfWork->commit()
  • 在 /var/www/issue/src/iTracker/UserBundle/Listener/UserGroupAmount.php 第 41 行中的 EntityManager->flush()

并且这5个错误被循环,这导致了这个异常

4

2 回答 2

3

@meze 是对的,在*Flush*事件中使用刷新会导致循环。

但是有一个快速的解决方法可以让你仍然这样做: $eventManager = $this -> em -> getEventManager();

// Remove event, if we call $this->em->flush() now there is no infinite recursion loop!
$eventManager -> removeEventListener('onFlush', $this); 

// ...

// Re-attach since we're done
$eventManager -> addEventListener('onFlush', $this); 

参见:Doctrine2 事件监听器:坚持 onFlush() | 本尼迪克特·沃尔特斯

于 2015-07-17T09:16:24.117 回答
2

作者建议的调用flush不是正确的解决方案。它将触发 onFLush 两次并在事务中创建不需要的保存点。

computeChangeSet可以使用和方法在事件recomputeSingleEntityChangeSet中安排所有其他更改。scheduleExtraUpdate

如果有不同的实体:

public function preUpdate(PreUpdateEventArgs $args) {        
    $user = $args->getEntity();
    if($user instanceof \iTracker\UserBundle\Entity\User) {
        if($args->hasChangedField('userGroup')) {
            $old = $args->getOldValue('userGroup');
            $new = $args->getNewValue('userGroup');

            $oldOriginAmount = $old->getAmount();
            $newOriginAmount = $new->getAmount();

            $old->setAmount($old->getAmount() - 1);
            $uow->scheduleExtraUpdate($old, array(
                'amount' => array($oldOriginAmount, $old->getAmount())
            ));

            $new->setAmount($new->getAmount() + 1);
            $uow->scheduleExtraUpdate($new, array(
                'amount' => array($newOriginAmount, $new->getAmount())
            ));
        }
    }
}

不需要调用persist(因为在任何情况下都不会创建关联的实体,它们应该已经是持久的)。

于 2013-06-07T09:09:46.530 回答