3

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

看到有一个 LoggableListener。

当可记录实体中的(可记录)字段更改时,是否确实存在触发事件?如果是这样,有没有办法获取触发它的字段列表?

我在想象一个实体的情况,比如说 10 个字段,其中 3 个可记录。对于这 3 个中的每一个,如果它们更改值,我想执行一些操作,因此如果它们中的 3 个更改,则将执行 3 个操作。

任何想法?

谢谢!

编辑

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

1)直接在实体级别使用生命周期回调,即使我使用的学说> 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 个这样的字段,哪种方法最合适?

编辑2

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

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

app_bundle.project_tolereances_listener:
    class: AppBundle\EventListener\ProjectTolerancesListener
    arguments: [@service_container] 

当然,我在监听器中添加了以下内容:

protected $container;

public function __construct(ContainerInterface $container)
{
    $this->container = $container;
}

但我得到以下信息:

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

任何想法?

4

1 回答 1

6

Loggable 侦听器只会随着时间的推移保存实体的监视属性的更改值。

它不会触发事件,它会监听onFlushpostPersist学说事件。

我认为您正在寻找有关 preUpdate 和 prePersist 事件的 Doctrine 侦听器,您可以在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;
    }
}

然后在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)
    {
        //
    }
}

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

更新

您对 recomputeSingleEntityChangeSet 是正确的,在这种情况下不需要它。我更新了监听器的代码。

第一种选择(in-entity 方法)的问题是你不能在方法中注入其他服务。如果您只需要 EntityManager 那么是的,这是最简单的代码方式。

使用外部 Listener 类,您可以这样做。

如果这 1000 个字段位于多个单独的实体中,则第二种类型的 Listener 将是最合适的。您可以创建一个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>

监听器看起来像:

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)
    {
        //
    }
}

根据:How to use Doctrine Entity Listener with Symfony 2.4? 它需要 DoctrineBundle 1.3+

于 2015-06-08T20:03:39.907 回答