【问题标题】:Doctrine ORM - Event Subscriber that computes the values of "Child entities" and persist this values on another EntityDoctrine ORM - 计算“子实体”的值并将此值保存在另一个实体上的事件订阅者
【发布时间】:2019-11-05 13:04:59
【问题描述】:

我有点困惑应该在哪里实现事件订阅器(实际上,我什至不确定是否应该使用实体监听器)。

所以,我有这个实体叫ServiceDoctrineEntity,这个实体有很多存储设备:

class ServiceDoctrineEntity {

    /**
     * One Service has many storage devices.
     *
     * @OneToMany(targetEntity="ServiceStorageDevicesDoctrineEntity", mappedBy="service", cascade={"all"})
     * @OrderBy({"order" = "ASC"})
     * @var ServiceStorageDevicesDoctrineEntity $storage_devices Description.
     */
    private $storage_devices;
}

每个存储设备都有自己的“存储空间/价值”

class ServiceStorageDevicesDoctrineEntity {
    /**
     * @Column(type="bigint", nullable=true, options={"comment":"The normalised value, calculated from $amount * $unit."})
     * @var int $value The normalised value, calculated from $amount * $unit.
     */
    private $value;
}

我的问题是,我应该运行一个计算逻辑,该逻辑将在每次存储设备发生变化时触发(添加/删除新存储设备,或更改存储空间等)。

  1. 我需要计算此服务拥有的“存储设备”总数。
  2. 汇总或求和每个存储设备的总“值”

这些“摘要”将保存在一个名为:ServiceStorageSummaryDoctrineEntity的实体上

class ServiceStorageSummaryDoctrineEntity {

    /**
     * One Service Support type has One Service.
     *
     * @OneToOne(targetEntity="ServiceDoctrineEntity", inversedBy="storage_summary")
     * @JoinColumn(name="service_id", referencedColumnName="id")
     */
    private $service;

    /**
     * @Column(type="bigint", nullable=true, options={"default":0, "comment":"The total value (normalised) of storage space."})
     * @var integer $total_value The total value (normalised) of storage space.
     */
    private $total_value;

    /**
     * @Column(type="integer", nullable=true, options={"default":0, "comment":"The total amount of storage devices."})
     * @var integer $device_count The total amount of storage devices.
     */
    private $device_count;

}

我尝试为此编写一个EventSubscriber 类来监听onFlush 事件:

class ServiceStorageDevicesEventListener implements EventSubscriber {

    /**
     * Returns an array of events this subscriber wants to listen to.
     *
     * @return string[]
     */
    public function getSubscribedEvents() {
        return array(
            Events::onFlush,
        );
    }

    public function onFlush( OnFlushEventArgs $eventArgs ) {
        $em  = $eventArgs->getEntityManager();
        $uow = $em->getUnitOfWork();

        foreach ( $uow->getScheduledEntityInsertions() as $entity ) {
            // Should I run the computation here?
            // Which entity should I be listening to? `ServiceDoctrineEntity` or `ServiceStorageSummaryDoctrineEntity`?
        }

        foreach ( $uow->getScheduledEntityUpdates() as $entity ) {
            // Should I run the computation here?
            // Which entity should I be listening to? `ServiceDoctrineEntity` or `ServiceStorageSummaryDoctrineEntity`?
        }

        foreach ( $uow->getScheduledEntityDeletions() as $entity ) {
            // Should I run the computation here?
            // Which entity should I be listening to? `ServiceDoctrineEntity` or `ServiceStorageSummaryDoctrineEntity`?
        }
    }
}

但我不确定如何继续:

  1. 我是否正确使用事件订阅者?
  2. 我是否有权收听onFlush 事件
  3. 我应该列出哪个实体:

    (a) ServiceDoctrine 实体并循环遍历每个存储设备?

    (b) 或ServiceStorageDevicesDoctrineEntity 但这不意味着计算逻辑将针对每个存储设备更改运行?

【问题讨论】:

    标签: php symfony doctrine-orm doctrine


    【解决方案1】:

    我是否正确使用事件订阅者?

    是的。如果您想在某个事件发生后执行一些逻辑,那么您来对地方了。

    EventSubscriber 为您提供更大的灵活性,因为您可以收听多个 Doctrine 事件(其中 EventListener 通常与特定事件相关联)

    我听 onFlush 事件是对的吗

    onFlush 事件在计算完所有实体更改集后发生。

    由于您要更新相关实体的数据,我建议您监听以下事件:

    • prePersist
    • preUpdate
    • preRemove

    我应该列出哪个实体

    收听ServiceStorageSummaryDoctrineEntity 意味着您可以在此实体 被更改时执行一些操作。但由于您从不手动更新此实体,因此您的事件将永远不会被触发。

    您想要做的是在 ServiceStorageDevicesDoctrineEntity 更改时观察更改。

    您的 EventListener 可能如下所示:

    class ServiceStorageDevicesEventListener implements EventSubscriber {
        public function getSubscribedEvents() {
            return array(
                Events::prePersist,
                Events::preUpdate,
                Events::preRemove,
            );
        }
    
        public function prePersist(LifecycleEventArgs $args)
        {
            $entity = $args->getObject();
    
            // don't perform operations for other entities
            if (!$entity instanceof ServiceStorageDevicesDoctrineEntity) {
               return;
            }
    
            // update your related entity here, ex:
            $entity->getServiceStorageDevices()->getServiceStorageSummary()->setTotalValue(10);
        }
    
        public function preUpdate(PreUpdateEventArgs $args)
        {
            // ...
        }
    
        public function preRemove(LifecycleEventArgs $args)
        {
            // ...
        }
    }
    

    希望对你有帮助。

    【讨论】:

    • 我能够通过保持onFlush 事件来解决我的问题,到目前为止我没有遇到任何问题,但如果我有一个问题,我会尝试使用你的解决方案。
    猜你喜欢
    • 1970-01-01
    • 2017-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多