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