@Kirill-Gorelov
С ума с IT

Symfony Eventlistener идет зацикливание?

Нужно сделать, историю изменения данных и записать, как было и как стало.

Создаю слушателя
App\EventListener\ArticleEntityEventListener:
        tags:
            - { name: 'doctrine.orm.entity_listener', lazy: true, event: 'preUpdate', entity: 'App\Entity\Article' }


И сам обработчик
public function preUpdate(Article $article, LifecycleEventArgs $event): void
    {
        $em = $event->getEntityManager();
        $version = $event->getEntityChangeSet()['name'];
        $history = new ArticleHistory();
        $history->setOld($version['0']);
        $history->setNew($version['1']);
        $history->setArticle($article);

        $em->persist($history);
        $em->flush();
    }


И у меня происходит зацикливание.

Нашел решение тут, но мне кажется, что оно не самое удачное.

И вопрос, как можно было бы сделать иначе или где у меня ошибка.
  • Вопрос задан
  • 50 просмотров
Решения вопроса 1
@Flying
Вы вызываете EntityManager::flush() внутри обработчика события, который сам вызывается в процессе работы
EntityManager::flush() (а точнее UnitOfWork::commit()), разумеется вы получаете бесконечный цикл.

Корректным подходом будет реализация, которая накапливает информацию об изменениях и передаёт их для дальнейшего сохранения. Это можно сделать с помощью Doctrine event listener'а, который содержит в себе обработчики следующих событий:
  1. preFlush
  2. postPersist, postUpdate, postRemove
  3. postFlush


Также, хотя механизмы сохранения изменений могут быть разными, с точки зрения уменьшения времени обработки запроса, логично отложить сохранение изменений "на потом", воспользовавшись поддержкой асинхронных очередей в Symfony Messenger.

Таким образом ваш обработчик должен действовать примерно следующим образом:
  1. На событие preFlush вы очищаете внутреннюю переменную (например private array $changes = []), в которой будет
    накапливаться информация об изменениях
  2. Обрабатывая события postPersist, postUpdate, postRemove вы сохраняете в $changes
    информацию об изменениях, которую хотите сохранить
  3. В обработчике postFlush вы передаёте накопленные изменения, формируя message, для которого настроен роутинг в async транспорт. Обработчик этого message сможет спокойно сохранить все накопленные изменения, не мешая runtime коду.

Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы