Doctrine ORM - подписчик на событие, который вычисляет значения «дочерних объектов» и сохраняет эти значения в другом объекте - PullRequest
0 голосов
/ 05 ноября 2019

Я немного сбит с толку, где мне реализовать подписчика на события (на самом деле, я даже не уверен, должен ли я вместо этого использовать Entity Listener).

Итак, у меня есть эта сущность с именем 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. Am Правильно ли я слушать onFlush событие
  3. Какой объект должен быть указан в списке:

    (a) ServiceDoctrine объект и проходить через каждое устройство хранения?

    (b) или ServiceStorageDevicesDoctrineEntity, но разве это не означает, что логика вычислений будет выполняться для каждого изменения запоминающего устройства?

1 Ответ

1 голос
/ 06 ноября 2019

Прав ли я при использовании подписчика на событие?

Да. Если вы хотите выполнить некоторую логику после того, как произошло определенное событие, вы находитесь в правильном месте для этого.

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

Надеюсь, это поможет.

...