【问题标题】:Symfony2/Doctrine: Get the field(s) that changed after "Loggable" entity changedSymfony2/Doctrine:获取“可记录”实体更改后更改的字段
【发布时间】:2015-06-08 16:05:19
【问题描述】:

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

saw 说有一个 LoggableListener。

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

我正在想象一个实体的情况,假设有 10 个字段,其中 3 个可记录。对于这 3 个中的每一个,如果它们的值发生变化,我想执行一些操作,因此如果它们中的 3 个发生变化,则将执行 3 个操作。

有什么想法吗?

谢谢!

编辑

阅读下面的评论并阅读有关教义事件的文档后,我理解有 3 个选项:

1) 直接在实体级别使用 lifecycle callbacks 甚至 with arguments 如果我使用的是学说 >2.4

2) 我可以listen and subscribe to 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) 执行您的建议,即使用Entity listener,您可以在实体级别定义要“附加”到类的侦听器。

即使第一个解决方案看起来更简单,我读到“您也可以使用此侦听器来实现对所有已更改字段的验证。这比在需要调用昂贵的验证时使用生命周期回调更有效”。什么是“昂贵的验证”。

在我的情况下,我必须执行的操作类似于“如果实体 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] 

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

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

有什么想法吗?

【问题讨论】:

    标签: symfony doctrine-orm doctrine-extensions


    【解决方案1】:

    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 个字段位于多个单独的实体中,则第二种侦听器将是最合适的。您可以创建一个 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+

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-21
    • 2023-01-27
    • 2021-08-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多