Symfony 中的 PostPersist 和 PostFlush 无限循环

PostPersist & PostFlush infinite loop in Symfony

我正在尝试 link 在用户进入数据库后向用户提供咖啡配置文件。 此咖啡配置文件数据在一个会话中,我在 postFlush 中使用此会话。

但是这段代码正在创建一个无限循环,我不知道为什么:

UserListener.php:

<?php

namespace AppBundle\EventListener;

use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\FormEvent;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use AppBundle\Entity\Consumption;
use AppBundle\Entity\CoffeeOption;
use AppBundle\Entity\Consumeable;
use AppBundle\Entity\MomentPreference;

use Doctrine\ORM\Event\LifecycleEventArgs;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Doctrine\ORM\Event\PostFlushEventArgs;

class UserListener
{
    private $container;
    private $user;

    public function __construct(ContainerInterface $container = null)
    {
        $this->container = $container;
    }

    public function postPersist(LifecycleEventArgs $args)
    {
        $user = $args->getEntity();

        $this->user = $user;
    }

    public function postFlush(PostFlushEventArgs $args)
    {
        $session = new Session();

        if($session) {

            $em = $args->getEntityManager();

            $us = $em->getRepository('AppBundle:User')->findOneById($this->user->getId());

            $consumption = $session->get('consumption');
            $coffee = $session->get('coffee');
            $moment = $session->get('moment');

            $consumption->setUser($us);

            //dummy data for the day, later this needs to be turned into datetime
            $moment->setDay('monday');
            $moment->setConsumption($consumption);

            $em->persist($consumption);
            $em->persist($coffee);
            $em->persist($moment);

            $em->flush();        

        } else {
            return $this->redirectToRoute('fos_user_registration_register');
        }
    }

}

Services.yml:

    zpadmin.listener.user:
    class: AppBundle\EventListener\UserListener
    arguments: ['@service_container']
    tags:
        - { name: doctrine.event_listener, event: postPersist }
        - { name: doctrine.event_listener, event: postFlush }

是什么原因导致此循环,我该如何解决?

您在 postPersist 事件中调用 $em->flush(),在 docs 中声明:

postFlush is called at the end of EntityManager#flush(). EntityManager#flush() can NOT be called safely inside its listeners.

您应该使用其他事件,例如 prePersistpostPersist

如果可能,尽量避免在一个请求中出现多个 flush()

顺便说一句,没有必要这样做,因为您的用户对象已经包含在您的 $user 变量中。

$us = $em->getRepository('AppBundle:User')->findOneById($this->user->getId());

在你的 postFlush 事件中,你又在脸红了。这就是导致无限循环的原因,因为每次调用 flush 方法时都会触发 postFlush 事件。

我不确定你想要达到什么目的,但你的目标是在每次保存用户时创建一次咖啡消费,你可以在你的方法开始时添加这样的测试:

$entity = $args->getObject();

if (!$entity instanceof User) {
    return;
}

这将防止无限循环。

还有一些事情:

  • 你的postPersist方法好像没用。每次持久化对象时都会调用它,因此您的 $this->user 属性不一定是用户对象。
  • 如果您需要用户,则不必在数据库中获取它。只需使用 $args->getObject() 即可获取刷新的实体。除了上面的测试之外,您将确定该方法将 return 您是一个 User 对象。
  • 在你的 Doctrine 监听器中检查用户是否登录不是一个很好的做法。这不是 class 应该做的。
  • 不要在构造函数中注入容器。只注入你需要的东西(在这种情况下......什么都没有?)