symfony2达到'100'的最大函数嵌套级别,正在中止!与学说eventlistener

时间:2013-06-07 09:02:09

标签: symfony doctrine-orm

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

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

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

2 个答案:

答案 0 :(得分:2)

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

可以使用computeChangeSetrecomputeSingleEntityChangeSetscheduleExtraUpdate方法在活动中安排所有其他更改。

如果是不同的实体:

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(因为在任何情况下都不会创建关联的entites,它们应该已经持久)。

答案 1 :(得分:2)

@meze是对的,在 * Flush * 事件中使用 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 Event Listener: persisting in onFlush() | Benedikt Wolters