Какое событие жизненного цикла доктрины необходимо обновить?

У меня есть класс Listener, который при создании объекта Post или Thread обновляет эти поля в таблице категорий:

last_post_thread_title

last_post_thread_slug

last_poster_username

last_post_body

last_post_created_at

is_last_post_op

и last_post_created_at в таблице потоков.

class LastPostListener
{
    public function postPersist(LifeCycleEventArgs $args) 
    {
        $entity = $args->getObject();
        $entityManager = $args->getObjectManager();

        $this->handleEvent($entityManager, $entity);
    }

    public function postUpdate(LifeCycleEventArgs $args) 
    {
        $entity = $args->getObject();
        $entityManager = $args->getObjectManager();

        $this->handleEvent($entityManager, $entity);
    }

    public function handleEvent($entityManager, $entity)
    {
        if (!$entity instanceof Post && !$entity instanceof Thread) {
            return;
    }

        $isPost = $entity instanceof Post;

        $thread = $isPost ? $entity->getThread() : $entity;

        $post = $isPost ? $entity : $thread;

        $category = $thread->getCategory();
        $category->setLastPostThreadTitle($thread->getTitle());
        $category->setLastPostThreadSlug($thread->getSlug());
        $category->setLastPostBody($post->getBody());
        $category->setLastPosterUsername($post->getUser()->getUsername());
        $category->setLastPostCreatedAt($post->getCreatedAt());
        $category->setIsLastPostOp(!$isPost);

        $thread->setLastPostCreatedAt($entity->getCreatedAt());

        $entityManager->persist($thread, $category);
        $entityManager->flush();
    }
}

Однако, когда редактируется СУЩЕСТВУЮЩАЯ тема или сообщение, ранее упомянутые поля таблицы категорий не обновляются.

То же самое с событиями prePersist() и preUpdate(), с очисткой или без нее.

Конечно, можно добавить все линии $category->set напрямую в функцию контроллера update, но это грязно.

Какое событие следует использовать здесь или, может быть, есть какое-то другое решение? Спасибо

Было бы хорошо, если бы вы обновили свой вопрос объяснениями того, что вы подразумеваете под «не работает». Что вы пытаетесь реализовать с помощью этого кода?

Flying 02.02.2019 09:45

Поскольку событие postUpdate вызывается внутри метода сброса, а изменения объекта не имеют значения, вы должны использовать другой способ обновления данных. См. doctrine-project.org/projects/doctrine-orm/en/2.6/reference/‌​… Это может быть хорошим подходом stackoverflow.com/a/25312851/3497902.

SilvioQ 02.02.2019 11:04
Стоит ли изучать 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 нам нужно возвращать клиентам разные ответы в зависимости от возникшего исключения.
1
2
73
1

Ответы 1

Причина такого поведения объясняется в Документация по доктрине с подробным описанием разрешенных операций в каждом из типов событий. Если вы посмотрите на эту статью, то увидите, что событие preUpdate очень ограничено, а postUpdate даже не имеет значения. Вообще говоря, основная причина вашей текущей проблемы - это попытка вызова flush(), когда flush() уже запущен.

Если вы хотите синхронизировать информацию - есть несколько способов:

  1. Вы можете использовать прослушиватель событий onFlush. Это событие дает вам доступ ко всем рассчитанным изменениям, запланированным для фиксации, и позволяет вам изучить эти изменения, чтобы решить, что нужно обновить. Однако это может быть не так просто, потому что вам придется иметь дело с методами UnitOfWork, которые раскрывают внутренние представления вычисляемых изменений, например. getScheduledEntityUpdates() и другие подобные методы. Также потребуется вручную пересчитать наборы изменений в случае, если вы будете вносить какие-либо изменения в сущности в рамках этого события.
  2. Вы можете реализовать отдельный класс, который будет предоставлять собственный метод flush(), который должен будет выглядеть примерно так:

    class CustomFlush {
        /**
         * @var EntityManager
         */
        private $em;
        /**
         * @var array
         */
        private $changes = [];
    
        public function flush($entity = null) {
            // Perform normal flushing operation
            $this->em->flush($entity);
            // If there was some changes collected - apply them
            if (!empty($this->changes)) {
                $categories = [];
                // Apply changes from $this->changes to Category entities,
                // collect them in $categories and flush separately
                if (!empty($categories)) {
                    $this->em->flush($categories);
                }
            }
        }
    
        public function preUpdate(LifeCycleEventArgs $args) {
            // Collect updates from Post and Thread and store it into $this->changes
        }
    }
    

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