【问题标题】:Symfony onFlush Doctrine ListenerSymfony onFlush 学说监听器
【发布时间】:2016-10-16 08:32:11
【问题描述】:

您好,我有一个 onFlush 监听器:

<?php

namespace FM\AppBundle\EventListener;

use FM\AdminBundle\Entity\Address\DeliveryAddress;
use Doctrine\ORM\Event\OnFlushEventArgs;

class DeliveryAddressListener
{
    /**
     * @param OnFlushEventArgs $args
     */
    public function onFlush(OnFlushEventArgs $args)
    {
        $em = $args->getEntityManager();
        $uow = $em->getUnitOfWork();

        foreach ($uow->getScheduledEntityUpdates() as $entity) {
            if ($entity instanceof DeliveryAddress) {
                $this->addPostalToUser($entity, $args);
            }
        }
    }

    /**
     * @param DeliveryAddress  $deliveryAddress
     * @param OnFlushEventArgs $args
     */
    public function addPostalToUser(DeliveryAddress $deliveryAddress, OnFlushEventArgs $args)
    {
        $em = $args->getEntityManager();
        $user = $deliveryAddress->getOwner();

        $user->setPostalCode($deliveryAddress->getZipCode());
    }
}

service.yml:

delivery_address.listener:
    class: FM\AppBundle\EventListener\DeliveryAddressListener
    tags:
        - { name: doctrine.event_listener, event: onFlush }

我正在尝试为用户设置新的邮政编码。但它似乎不起作用。

即使我添加了$em-&gt;persist($user)

我正在查看此文档:http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html#onflush

但我不明白我如何使它与这个解释一起工作:

If you create and persist a new entity in onFlush, then calling EntityManager#persist() is not enough. You have to execute an additional call to $unitOfWork-&gt;computeChangeSet($classMetadata, $entity).

【问题讨论】:

    标签: php symfony doctrine-orm


    【解决方案1】:

    如果您需要在侦听器中创建一个对象,将其持久化并刷新,那么 tlorens 的回答将不起作用,因为 Doctrine 文档提到这必须通过 onFlush 事件来完成。

    最初的问题是如何按照文档建议使其工作: If you create and persist a new entity in onFlush, then calling EntityManager#persist() is not enough. You have to execute an additional call to $unitOfWork-&gt;computeChangeSet($classMetadata, $entity).

    这是实现此目的的一种方法:

    /**
     * @param OnFlushEventArgs $eventArgs
     */
    public function onFlush(OnFlushEventArgs  $eventArgs)
    {
        $em = $eventArgs->getEntityManager();
        $uow = $em->getUnitOfWork();
    
        foreach ($uow->getScheduledEntityUpdates() as $entity) {
            if ($entity instanceof User) {
                $uow->computeChangeSets();
                $changeSet = $uow->getEntityChangeSet($entity);
                // In this exemple, User has a boolean property 'enabled' and a log will be created if it is passed to 'false'
                if ($changeSet && isset($changeSet['enabled']) && $changeSet['enabled'][1] === false) {
                    $log = new Log();
                    $em->persist($log);
                    $uow->computeChangeSet($em->getClassMetadata(get_class($log)), $log);
                }
            }
        }
    

    【讨论】:

    • 有些组件使用我的解决方案完全相同的逻辑。我的答案是正确地将对象操作放置在正确的事件中。不知道为什么要在 onFlush 中执行此操作的复杂性,因为它可以在其他地方完美完成。
    【解决方案2】:

    在操作字段时,应该在 preUpdaet/prePersist 中完成。

    AppBundle/EventSubscriber/EntitySubscriber.php

    namespace AppBundle\EventSubscriber;
    
    use Doctrine\Common\EventSubscriber;
    use Doctrine\ORM\Event\LifecycleEventArgs;
    use Doctrine\ORM\Event\OnFlushEventArgs;
    
    class EntitySubscriber implements EventSubscriber
    {
        private $now;
    
        public function __construct()
        {
            $this->now = \DateTime::createFromFormat('Y-m-d h:i:s', date('Y-m-d h:i:s'));
        }
    
        public function getSubscribedEvents()
        {
            return [
                'prePersist',
                'preUpdate'
            ];
        }
    
        public function prePersist(LifecycleEventArgs $args)
        {
            $entity        = $args->getEntity();
            $entityManager = $args->getEntityManager();
    
            if (method_exists($entity, 'setCreatedAt')) {
                $entity->setUpdatedAt($this->now);
            }
    
            if (method_exists($entity, 'setUpdatedAt')) {
                $entity->setUpdatedAt($this->now);
            }
        }
    
        public function preUpdate(LifecycleEventArgs $args)
        {
            $entity        = $args->getEntity();
            $entityManager = $args->getEntityManager();
    
            if (method_exists($entity, 'setUpdatedAt')) {
                $entity->setUpdatedAt($this->now);
            }
        }
    }
    

    services.yml

        app.entity_subscriber:
            class: AppBundle\EventSubscriber\EntitySubscriber
            tags:
                - { name: doctrine.event_subscriber, connection: default }
    

    【讨论】:

      【解决方案3】:

      当我使用它时它会起作用:

      // Remove event, if we call $this->em->flush() now there is no infinite recursion loop!
      $eventManager->removeEventListener('onFlush', $this);
      

      我的听众

      namespace FM\AppBundle\EventListener;
      
      use FM\AdminBundle\Entity\Address\DeliveryAddress;
      use Doctrine\ORM\Event\OnFlushEventArgs;
      
      class DeliveryAddressListener
      {
          /**
           * @param OnFlushEventArgs $args
           */
          public function onFlush(OnFlushEventArgs $args)
          {
              $em = $args->getEntityManager();
              $uow = $em->getUnitOfWork();
              $eventManager = $em->getEventManager();
      
              // Remove event, if we call $this->em->flush() now there is no infinite recursion loop!
              $eventManager->removeEventListener('onFlush', $this);
      
              foreach ($uow->getScheduledEntityUpdates() as $entity) {
                  if ($entity instanceof DeliveryAddress) {
                      $this->addPostalToUser($entity, $args);
                  }
              }
          }
      
          /**
           * @param DeliveryAddress  $deliveryAddress
           * @param OnFlushEventArgs $args
           */
          public function addPostalToUser(DeliveryAddress $deliveryAddress, OnFlushEventArgs $args)
          {
              $em = $args->getEntityManager();
              $user = $deliveryAddress->getOwner();
      
              $user->setPostalCode($deliveryAddress->getZipCode());
              $em->flush();
          }
      }
      

      【讨论】:

      • 你不应该冲洗。您应该改为使用 UOW 函数调用重新计算。请参阅此答案中的示例:stackoverflow.com/questions/34342324/… - 问题是您的刷新调用了刷新,它调用了侦听器等
      • 即使我使用它? $eventManager-&gt;removeEventListener('onFlush', $this);
      猜你喜欢
      • 1970-01-01
      • 2021-07-14
      • 2018-06-21
      • 2016-02-09
      • 2014-06-29
      • 1970-01-01
      • 2012-06-11
      • 2015-12-19
      • 1970-01-01
      相关资源
      最近更新 更多