哪个准则生命周期事件需要更新?

时间:2019-02-02 07:40:29

标签: symfony doctrine

我有一个Listener类其中当张贴或线程实体被建立,在类别表更新这些字段:

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()和更新前的()事件,有或没有冲洗相同。

当然,可以将所有$category->set行直接添加到Controller update函数中,但这很脏。

此处应使用哪个事件,或者还有其他解决方案?谢谢

1 个答案:

答案 0 :(得分:1)

Doctrine documentation中解释了这种行为的原因,并详细说明了每种事件类型中允许的操作。如果您看一下这篇文章,您会发现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
        }
    }