Symfony onFlush Doctrine Listener

Привет, у меня есть слушатель 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 для пользователя. Но это не похоже на работу.

Даже когда я добавляю $em->persist($user),

Я просматриваю этот документ: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html

Но я не понимаю, как я могу сделать это работает с этим объяснением:

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).

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 }

Если вам нужно создать объект, сохранить его и сбросить в свой слушатель, тогда ответ 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);
            }
        }
    }

Ну, это работает, когда я использую это:

// 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();
    }
}
Другие вопросы по тегам