2014-10-18 3 views
6

Mam zdarzenie onFlush(), które działa poprawnie, ale muszę to zrobić, aby obrócić je do funkcji preFlush() lub preUpdate(), które są akceptowalne. Zrobiłem preFlush(), ale z jakiegoś powodu nic nie robi. Nawet nie błąd. czego mi brakuje?Tworzenie zdarzenia preUpdate lub preFlush za pomocą detektora zdarzeń

TEST: Umieściłem exit w preFlush(), aby sprawdzić, czy jest w ogóle wywoływany. Wynik: , więc foreach() nigdy nie jest uruchamiany! Jest to pusta tablica. Przetestowałem również preUpdate() i wszystkie linie w tym run got, ale nie dane wstawione.

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

Stworzyłem je po przeczytaniu 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 } 

robocza onFlush() przykład:

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

Nie działa preFlush() przykład:

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

Nie działa preUpdate() przykład

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

Czy możesz dodać część konfiguracji usługi? – devsheeep

+0

@devsheeep - Zaktualizowano wpis dla tego. – BentCoder

+0

Czy możesz pokazać kod, w którym nazywasz metody utrwalania i płukania? – aimar

Odpowiedz

8

ROZWIĄZANIE:

Sztuką jest, utrzymująca się po preUpdate() w postFlush() imprezy.

Uwaga: Choć to może nie być najlepszym rozwiązaniem, to odpowiedź na pytanie jednak można to zrobić za pomocą Abonenta wydarzenie lub prosty onFlush() ->$uow->getScheduledEntityUpdates() w detektor zdarzeń.

Usługa.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(); 
     } 
    } 
} 
+1

Nie rób tego. ** NIE jest BEZPIECZNIE **, aby wywołać 'EntityManager # flush()' wewnątrz zdarzenia 'postFlush'. cf. [Doctrine Documentation] (http://doctrine-orm.readthedocs.io/en/latest/reference/events.html#postflush) –

2

Czytając dokumenty,

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

nie wspomnieć, że preFlush ma INFOR o zmianach (mam na myśli ten EntityManager)

jeśli spojrzysz na Doctrine\ORM\UnitOfWork zobaczysz, że zestawy zmian są obliczane po preFlush zdarzeniu, więc powinieneś użyć onFlush, jeśli chce współpracować z podmiotami zmienionych

// 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

Jak przerwać operację płukania, jeśli jakiś warunek nie powiedzie się w funkcjach detektora 'onFlush()'? – jitendra

0

Drogi BentCoder:
Używam Symfony 2.7 wersję. Podczas korzystania $ em-> równo w wydarzeniu słuchacza niczym postu, błąd ten został wystąpić: click-here-to-see-bug-description

I to jest moje rozwiązanie:

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 } 

Odbiornik zdarzeń

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

Mam nadzieję, że to pomoże komuś!