Creating a preUpdate or preFlush event using the Event Listener

I have an onFlush () event that works fine, but I need to do this to turn this into preFlush () or preUpdate () as acceptable. I did preFlush (), but for some reason does nothing. Even a mistake. What am I missing?

TEST: I placed exit in preFlush() to see if it would be called at all or not. Result: 1 , so foreach() never starts! This is an empty array. I also tested preUpdate () and all the lines in which data is started but not inserted.

 public function preFlush(PreFlushEventArgs $args) { $em = $args->getEntityManager(); $uow = $em->getUnitOfWork(); echo '1'; foreach ($uow->getScheduledEntityUpdates() as $entity) { echo '2'; if ($entity instanceof User) { echo '3'; } } exit; } 

I created them after reading the documentation .

service.yml

 services: entity.event_listener.user: class: Site\FrontBundle\EventListener\Entity\UserListener tags: - { name: doctrine.event_listener, event: preUpdate } - { name: doctrine.event_listener, event: onFlush } - { name: doctrine.event_listener, event: preFlush } 

Working example onFlush ():

 class UserListener { public function onFlush(OnFlushEventArgs $args) { $em = $args->getEntityManager(); $uow = $em->getUnitOfWork(); foreach ($uow->getScheduledEntityUpdates() as $entity) { if ($entity instanceof User) { $userLog = new UserLog(); $userLog->setDescription($entity->getId() . ' being updated.'); $em->persist($userLog); // Instead of $em->flush() cos we're already in flush process $userLogMetadata = $em->getClassMetadata(get_class($userLog)); $uow->computeChangeSet($userLogMetadata, $userLog); } } } } 

The preFlush () example does not work:

 class UserListener { public function preFlush(PreFlushEventArgs $args) { $em = $args->getEntityManager(); $uow = $em->getUnitOfWork(); foreach ($uow->getScheduledEntityUpdates() as $entity) { if ($entity instanceof User) { $userLog = new UserLog(); $userLog->setDescription($entity->getId() . ' being updated.'); $em->persist($userLog); // Instead of $em->flush() cos we're already in flush process $userLogMetadata = $em->getClassMetadata(get_class($userLog)); $uow->computeChangeSet($userLogMetadata, $userLog); } } } } 

The preUpdate () example does not work

 class UserListener { public function preUpdate(LifecycleEventArgs $args) { $entity = $args->getEntity(); $em = $args->getEntityManager(); $uow = $em->getUnitOfWork(); if ($entity instanceof User) { $userLog = new UserLog(); $userLog->setDescription($entity->getId() . ') been updated.'); $em = $args->getEntityManager(); $em->persist($userLog); $userLogMetadata = $em->getClassMetadata(get_class($userLog)); $uow->computeChangeSet($userLogMetadata, $userLog); } } } 
+6
source share
3 answers

DECISION:

The trick is saved after preUpdate() inside the postFlush() event.

Note. . Although this may not be the best solution, it answers the question, however it can be done with the event subscriber or by simple onFlush() $uow->getScheduledEntityUpdates() in the event listener.

Service.yml

 services: entity.event_listener.user_update: class: Site\FrontBundle\EventListener\Entity\UserUpdateListener tags: - { name: doctrine.event_listener, event: preUpdate } - { name: doctrine.event_listener, event: postFlush } 

Event listener

 <?php namespace Site\FrontBundle\EventListener\Entity; use Doctrine\ORM\Event\LifecycleEventArgs; use Doctrine\ORM\Event\PostFlushEventArgs; use Site\FrontBundle\Entity\User; use Site\FrontBundle\Entity\UserLog; class UserUpdateListener { private $log = array(); public function preUpdate(LifecycleEventArgs $args) { $entity = $args->getEntity(); // False check is compulsory otherwise duplication occurs if (($entity instanceof User) === false) { $userLog = new UserLog(); $userLog->setDescription($entity->getId() . ' being updated.'); $this->log[] = $userLog; } } public function postFlush(PostFlushEventArgs $args) { if (! empty($this->log)) { $em = $args->getEntityManager(); foreach ($this->log as $log) { $em->persist($log); } $em->flush(); } } } 
+8
source

Reading documents

http://doctrine-orm.readthedocs.org/en/latest/reference/events.html#onflush

it does not mention that preFlush has change information (I mean entityManager)

if you look at Doctrine\ORM\UnitOfWork , you will see that change sets are computed after the preFlush event, so you should use onFlush if you want to interact with the changed objects

 // Raise preFlush if ($this->evm->hasListeners(Events::preFlush)) { $this->evm->dispatchEvent(Events::preFlush, new PreFlushEventArgs($this->em)); } // Compute changes done since last commit. if ($entity === null) { $this->computeChangeSets(); } elseif (is_object($entity)) { $this->computeSingleEntityChangeSet($entity); } elseif (is_array($entity)) { foreach ($entity as $object) { $this->computeSingleEntityChangeSet($object); } } 
+2
source

Dear BentCoder :
I am using Symfony version 2.7. When using $ em-> flush in an event listener such as your post, this error occurred: click-here-to-see-bug-description

And this is my solution:

Service.yml

 services: app.listener: class: AppBundle\EventListener\DoctrineListener arguments: ["@service_container"] tags: - { name: doctrine.event_listener, event: preUpdate, method: preUpdate } - { name: doctrine.event_listener, event: postUpdate, method: postUpdate } 

Event listener

 namespace AppBundle\EventListener; use Symfony\Component\DependencyInjection\ContainerInterface; use Doctrine\ORM\Event\LifecycleEventArgs; use AppBundle\Entity; /** * Log activity on website * Class DoctrineListener * @package AppBundle\EventListener */ class DoctrineListener { /** * @var ContainerInterface */ private $_container; /** * @var Array */ private $_activities; /** * DoctrineListener constructor. * @param ContainerInterface $container */ public function __construct(ContainerInterface $container) { $this->_container = $container; } /** * @param LifecycleEventArgs $args */ public function preUpdate(LifecycleEventArgs $args) { $entityManager = $args->getEntityManager(); $entity = $args->getEntity(); $activityEntity = new Entity\Activity(); $activityEntity->setAction(Entity\Activity::ACTION_EDIT); $activityEntity->setActionAt(new \DateTime()); $activityEntity->setIpAddress($this->_container->get('request')->getClientIp()); switch (true) { case $entity instanceof Entity\Goods: $repository = $entityManager->getRepository('AppBundle:Goods'); $activityEntity->setType(Entity\Activity::TYPE_GOODS); $message = 'User: <strong>%s</strong> sửa mẫu hàng hóa <strong>%s</strong>'; break; default: return; } if (isset($repository) && $args->getEntityChangeSet()) { $user = $this->_container->get('security.context')->getToken()->getUser(); $recordBefore = clone $entity; foreach ($args->getEntityChangeSet() as $key => $value) { $method = 'set'.ucfirst($key); $recordBefore->$method($value[0]); } $activityEntity->setFosUser($user); $activityEntity->setRecordBefore(serialize($recordBefore)); $activityEntity->setRecordAfter(serialize($entity)); $activityEntity->setMessage( sprintf( $message, $user->getUserProfile()->getFullName(), (string) $recordBefore ) ); $this->_activities[] = $activityEntity; } return; } /** * @param LifecycleEventArgs $args */ public function postUpdate(LifecycleEventArgs $args) { if (sizeof($this->_activities)) { $entityManager = $args->getEntityManager(); foreach ($this->_activities as $activity) { $entityManager->persist($activity); } $entityManager->flush(); } } } 

Hope this helps someone!

0
source

Source: https://habr.com/ru/post/976905/


All Articles