Symfony onFlush Doctrine Listener

时间:2016-06-15 09:46:43

标签: php symfony doctrine-orm

您好我有一个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 }

我正在尝试将新的zipCode设置为User。但它似乎没有用。

即使我正在添加$em->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->computeChangeSet($classMetadata, $entity).

3 个答案:

答案 0 :(得分:4)

操作字段时,应该在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 }

答案 1 :(得分:3)

如果您需要创建一个对象,将其保存并刷新在您的监听器中,则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->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);
            }
        }
    }

答案 2 :(得分:0)

当我使用它时它很有效:

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