@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();
    }


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

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

И вопрос, как можно было бы сделать иначе или где у меня ошибка.
  • Вопрос задан
  • 59 просмотров
Решения вопроса 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 коду.

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

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

Похожие вопросы