使用Event Listener创建preUpdate或preFlush事件

Ben*_*der 6 symfony doctrine-orm

我有一个onFlush()事件工作正常,但我需要做的是将其转换为preFlush()或preUpdate()都可以接受.我做了preFlush()但由于某种原因它没有做任何事情.甚至没有错误.我错过了什么?

测试:我放入exit,preFlush()看它是否被调用.结果是:1因此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;
}
Run Code Online (Sandbox Code Playgroud)

我在阅读完文档后创建了它们.

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 }
Run Code Online (Sandbox Code Playgroud)

使用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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

不工作preFlush()示例:

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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

不工作的preUpdate()示例

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Ben*_*der 10

解:

诀窍是,preUpdate()postFlush()事件发生之后坚持下去.

注意:尽管这可能不是最佳解决方案,但它可以回答问题,但可以使用事件订阅者或简单onFlush()- >$uow->getScheduledEntityUpdates()在事件监听器中完成.

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 }
Run Code Online (Sandbox Code Playgroud)

事件监听器

<?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();
        }
    }
} 
Run Code Online (Sandbox Code Playgroud)

  • 不要这样做.在`postFlush`事件中调用`EntityManager#flush()`是不安全的**.比照 [Doctrine Documentation](http://doctrine-orm.readthedocs.io/en/latest/reference/events.html#postflush) (5认同)