Бесконечный цикл PostPersist и PostFlush в Symfony

Я пытаюсь связать профиль кофе с пользователем после того, как пользователь находится в базе данных. Эти данные профиля кофе находятся в сеансе, и я использую этот сеанс в 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 }

Что вызывает этот цикл и как его исправить?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Symfony Station Communiqué - 17 февраля 2023 г
Symfony Station Communiqué - 17 февраля 2023 г
Это коммюнике первоначально появилось на Symfony Station , вашем источнике передовых новостей Symfony, PHP и кибербезопасности.
Управление ответами api для исключений на Symfony с помощью KernelEvents
Управление ответами api для исключений на Symfony с помощью KernelEvents
Много раз при создании api нам нужно возвращать клиентам разные ответы в зависимости от возникшего исключения.
0
0
2 329
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы вызываете $em->flush() внутри своего события postPersist, в документы указано, что:

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

Вам следует использовать другие события, такие как prePersist или postPersist.

По возможности старайтесь избегать использования нескольких flush() в одном запросе.

кстати, в этом нет необходимости, потому что ваш пользовательский объект уже содержится внутри вашей переменной $ user.

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

Если я не использую flush () в postPersist, он не помещает профиль кофе в базу данных. Но если я использую flush () в postPersist, я получаю сообщение об ошибке ..

Marco Koopman 31.05.2018 11:55
Ответ принят как подходящий

В вашем событии postFlush вы снова промываетесь. Это то, что вызывает бесконечный цикл, потому что событие postFlush запускается каждый раз, когда вы вызываете метод flush.

Я не уверен, чего вы пытаетесь достичь, но ваша цель - создавать потребление кофе каждый раз, когда вы спасаете пользователя, вы можете добавить тест, подобный этому, в начале вашего метода:

$entity = $args->getObject();

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

Это предотвратит бесконечный цикл.

И еще несколько вещей:

  • Ваш метод postPersist кажется бесполезным. Он будет вызываться каждый раз, когда объект сохраняется, поэтому ваш $this->user не обязательно будет объектом User.
  • Если вам нужен пользователь, вам не нужно извлекать его из своей базы данных. Просто используйте $args->getObject(), чтобы получить сброшенный объект. В дополнение к приведенному выше тесту вы будете уверены, что метод вернет вам объект User.
  • Это не очень хорошая практика, проверять, вошел ли пользователь в ваш слушатель Doctrine. Это не то, что должен делать класс.
  • Не вставляйте контейнер в свой конструктор. Вводите только то, что вам нужно (в данном случае ... ничего?)

Postflush использует PostFlushEventArgs вместо LifecycleEventArgs. PostFlushEventArgs не содержит пользовательского объекта. Должен ли я использовать postflush для моего случая postpersist? И как мне очистить профиль кофе, который должен быть связан с пользователем, если я не могу использовать flush ()?

Marco Koopman 31.05.2018 11:50

@MarcoKoopman Хорошее замечание. Вместо этого вы должны использовать postUpdate. Вы можете использовать метод flush в своем мероприятии, но вы не можете использовать его для объекта User, если вам не нужен бесконечный цикл.

fxbt 31.05.2018 14:04

Я изменил его на postUpdate, и теперь он работает как шарм! Большое спасибо! Я уже некоторое время борюсь с этой проблемой!

Marco Koopman 31.05.2018 14:46

Другие вопросы по теме