2014-10-18 103 views
6

我有一個onFlush()事件,它工作正常,但我需要做的是將其轉換爲preFlush()或preUpdate()都可接受。我做了preFlush(),但由於某種原因它沒有做任何事情。甚至沒有錯誤。我錯過了什麼?使用事件監聽器創建preUpdate或preFlush事件

測試:我把exit放在preFlush()看看它是否被調用。結果是:因此foreach()永遠不會運行!這是一個空陣列。我還測試了preUpdate()以及所有的行,但沒有插入數據。

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

我在閱讀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 } 

工作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); 
      } 
     } 
    } 
} 

不工作預沖洗()的例子:

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

不工作更新前的()例如

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); 
     } 
    } 
} 
+0

您可以添加服務配置部分嗎? – devsheeep 2014-10-18 11:56:06

+0

@devsheeep - 更新了它的帖子。 – BentCoder 2014-10-18 11:58:14

+0

你可以顯示你調用的代碼持久化和刷新方法嗎? – aimar 2014-10-19 19:31:08

回答

8

SOLUTION:

的訣竅是,preUpdate()postFlush()事件之後持續。

注:雖然這可能不是最佳的解決方案,它回答了這個問題但它可能與事件訂戶或簡單onFlush()做 - 在事件監聽器>$uow->getScheduledEntityUpdates()

服務。陽明海運

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 } 

事件監聽器

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

不要這樣做。在'postFlush'事件中調用'EntityManager#flush()'是** NOT SAFE **。比照[學說文件](http://doctrine-orm.readthedocs.io/en/latest/reference/events.html#postflush) – 2017-07-28 08:42:46

2

閱讀文檔,

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

它沒有提到preFlush大約有變化Infor的(我指的是EntityManager的)

如果您查看Doctrine\ORM\UnitOfWork,您會看到在preFlush事件之後計算更改集,因此如果您使用onFlush希望與改變的實體

互動
// 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); 
    } 
} 
+1

如果某些條件在'onFlush()'監聽器函數中失敗,如何中止flush操作? – jitendra 2015-10-20 22:10:57

0

親愛BentCoder
我使用Symfony的2.7版本。當使用$ EM->在事件監聽器就像您的文章沖洗,在發生這樣的錯誤: click-here-to-see-bug-description

而且,這是我的解決方案:

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

希望這會幫助別人!