Symfony2/Doctrine:获取"Loggable"实体更改后更改的字段

Ser*_*gri 3 symfony doctrine-orm doctrine-extensions

在Symfony2项目中,我正在使用Loggable Doctrine Extension.

看到有一个LoggableListener.

当可记录实体中的(可记录)字段发生变化时,确实会触发事件吗?如果是这样,有没有办法获得触发它的字段列表?

我想象一个实体的情况,比方说10个字段,其中3个可记录.对于3中的每一个,如果它们改变了值,我想执行一些操作,因此如果它们中的3个改变,将执行3个动作.

任何的想法?

谢谢!

编辑

阅读下面的评论并阅读关于学说的事件的文档,我理解有3个选项:

1)如果我使用的是doctrine> 2.4,那么即使使用参数,可以直接在实体级使用生命周期回调

2)我可以收听并订阅Lifecycle Events,但在这种情况下,文档会说"Lifecycle events are triggered for all entities. It is the responsibility of the listeners and subscribers to check if the entity is of a type it wants to handle."

3)做你建议的,使用实体监听器,你可以在实体级别定义哪个是将"附加"到类的监听器.

即使第一个解决方案看起来更容易,我也会读到"你也可以使用这个监听器来实现已经改变的所有字段的验证.当使用昂贵的验证来调用时,这比使用生命周期回调更有效".什么被认为是"昂贵的验证?".

在我的情况下,我必须执行的是"如果实体Y的字段X发生了变化,而不是在通知表上添加通知"用户Z将X(Y)的值从A更改为B"

哪个是最合适的方法,考虑到我有大约1000个这样的领域?

EDIT2

为了解决我的问题,我正在尝试在监听器中注入service_container服务,这样我就可以访问调度程序来调度一个新事件,该事件可以执行我需要的新实体的持久化.但是我该怎么做呢?

我尝试了通常的方法,我将以下内容添加到service.yml

app_bundle.project_tolereances_listener:
    class: AppBundle\EventListener\ProjectTolerancesListener
    arguments: [@service_container] 
Run Code Online (Sandbox Code Playgroud)

当然我向听众添加了以下内容:

protected $container;

public function __construct(ContainerInterface $container)
{
    $this->container = $container;
}
Run Code Online (Sandbox Code Playgroud)

但我得到以下内容:

Catchable Fatal Error: Argument 1 passed to AppBundle\ProjectEntityListener\ProjectTolerancesListener::__construct() must be an instance of AppBundle\ProjectEntityListener\ContainerInterface, none given, called in D:\provarepos\user\vendor\doctrine\orm\lib\Doctrine\ORM\Mapping\DefaultEntityListenerResolver.php on line 73 and defined
Run Code Online (Sandbox Code Playgroud)

任何的想法?

小智 6

Loggable侦听器仅保存实体的监视属性的更改值.

它不会触发事件,它会监听事件onFlushpostPersist理论事件.

我认为你在preUpdate和prePersist事件上寻找Doctrine监听器,你可以在a之前操作变换集flush.

请参阅:http://doctrine-orm.readthedocs.org/en/latest/reference/events.html

如果您使用的是Doctrine 2.4+,可以轻松地将它们添加到您的实体中:

简单的实体类:

namespace Your\Namespace\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 *  @ORM\Entity
 *  @ORM\EntityListeners({"Your\Namespace\Listener\DogListener"})
 */
class Dog
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=100)
     */
    private $name;

    /**
     * @ORM\Column(type="integer")
     */
    private $age;

    /**
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @param int $id
     */
    public function setId($id)
    {
        $this->id = $id;
    }

    /**
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @param string $name
     */
    public function setName($name)
    {
        $this->name = $name;
    }

    /**
     * @return int
     */
    public function getAge()
    {
        return $this->age;
    }

    /**
     * @param int $age
     */
    public function setAge($age)
    {
        $this->age = $age;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在Your\Namespace\Listener您创建ListenerClass DogListener:

namespace Your\Namespace\Listener;

use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use Your\Namespace\Entity\Dog;

class DogListener
{
    public function preUpdate(Dog $dog, PreUpdateEventArgs $event)
    {         
        if ($event->hasChangedField('name')) {                
            $updatedName = $event->getNewValue('name'). ' the dog';
            $dog->setName($updatedName);         
        }

        if ($event->hasChangedField('age')) {
            $updatedAge = $event->getNewValue('age') % 2;
            $dog->setAge($updatedAge);
        }

    }

    public function prePersist(Dog $dog, LifecycleEventArgs $event)
    {
        //
    }
}
Run Code Online (Sandbox Code Playgroud)

清除缓存并在刷新时调用侦听器.

更新

你是对的recomputeSingleEntityChangeSet在这种情况下是不需要的.我更新了监听器的代码.

第一种选择(实体内方法)的问题是您不能在方法中注入其他服务.如果您只需要EntityManager,那么是,这是代码最简单的方法.

使用外部Listener类,您可以执行此操作.

如果这1000个字段位于多个单独的实体中,则第二种类型的监听器将是最适合的.您可以创建一个NotifyOnXUpdateListener包含所有监视/通知逻辑的内容.


更新2

要在EntityListener中注入服务,请将Listener声明为标记为的服务doctrine.orm.entity_listener并注入您需要的内容.

<service id="app.entity_listener.your_service" class="Your\Namespace\Listener\SomeEntityListener">
        <argument type="service" id="logger" />
        <argument type="service" id="event_dispatcher" />
        <tag name="doctrine.orm.entity_listener" />
</service>
Run Code Online (Sandbox Code Playgroud)

并且听众将看起来像:

class SomeEntityListener
{
    private $logger;
    private $dispatcher;

    public function __construct(LoggerInterface $logger, EventDispatcherInterface $dispatcher)
    {
        $this->logger = $logger;
        $this->dispatcher = $dispatcher;
    }

    public function preUpdate(Block $block, PreUpdateEventArgs $event)
    {
        //
    }
}
Run Code Online (Sandbox Code Playgroud)

根据:如何在Symfony 2.4中使用Doctrine Entity Listener? 它需要DoctrineBundle 1.3+