Symfony2 Doctrine Event Listener preUpdate methodMaximum function nesting level错误

Symfony2 Doctrine Event Listener preUpdate methodMaximum function nesting level error

用户密码更改事件可以使用 Doctrine preUpdate 侦听器处理,但我无法执行另一个日志持久化过程,它会导致侦听器循环,因此错误跟踪如下:

Error: Maximum function nesting level of '5000' reached, aborting! in /var/www/my_project/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/LifecycleEventArgs.php line 85

我的 preUpdate 侦听器代码如下:

public function preUpdate(LifecycleEventArgs $args)
{
    if (php_sapi_name()!='cli') {

        $entity = $args->getEntity();
        $entityManager = $args->getEntityManager();

        // perhaps you only want to act on some "User" entity
        if ($entity instanceof User) {

            if($args->hasChangedField('password')){
                //log as eventlog
                $event = new \My_Project\UserBundle\Entity\EventLog();
                $event->setEventInfo(UserEventLogParams::$PASSWORD_CHANGE);
                $event->setIp($this->container->get('request')->getClientIp());
                $event->setUserId($entity->getId());
                $entityManager->persist($event);

                $entityManager->flush();
            }
        }
    }
}

这个问题在那里提到 Adding additional persist calls to preUpdate call in Symfony 2.1 但没有用有效的解决方案回答。

我如何记录(使用 Doctrine2 事件侦听器 mysql)密码更改事件?

我可以用 postUpdate 方法做到这一点吗?

Doctrine 事件系统文档。 http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html#preupdate

Restrictions for this event:

  1. Changes to associations of the passed entities are not recognized by the flush operation anymore.
  2. Changes to fields of the passed entities are not recognized by the flush operation anymore, use the computed change-set passed to the event to modify primitive field values, e.g. use $eventArgs->setNewValue($field, $value); as in the Alice to Bob example above.
  3. Any calls to EntityManager#persist() or EntityManager#remove(), even in combination with the UnitOfWork API are strongly discouraged and don’t work as expected outside the flush operation.

作为解决方案,您可以在 preUpdate 中获取 changeSet,但在 postUpdate 中调用 EntityManager#persist()EntityManager#flush()

此外,您需要使用监听器 $event 的私有 属性 来在 postUpdate 函数中获取它。

privat $event;

public function preUpdate(LifecycleEventArgs $args)
{
if (php_sapi_name()!='cli') {

    $entity = $args->getEntity();
    $entityManager = $args->getEntityManager();

    // perhaps you only want to act on some "User" entity
    if ($entity instanceof User) {

        if($args->hasChangedField('password')){
            //log as eventlog
            $this->event = new \My_Project\UserBundle\Entity\EventLog();
            $this->event->setEventInfo(UserEventLogParams::$PASSWORD_CHANGE);
            $this->event->setIp($this->container->get('request')->getClientIp());
            $this->event->setUserId($entity->getId());

        }
    }
}
}

public function postUpdate(LifecycleEventArgs $args)
{
    $entityManager = $args->getEntityManager();
    $entityManager->persist($this->event);
    $entityManager->flush();
}