Doctrine onFlush - catch entity changed fields

时间:2018-02-26 18:00:38

标签: symfony doctrine event-listener

I need to store all changed field in logs when user change something in Product Entity.

I have event subscriber which works fine. I have two methods. Onflush and postFlush.

In onFlush method I have simply this:

public function onFlush(OnFlushEventArgs $args): void
{
    $em = $args->getEntityManager();
    $uow = $em->getUnitOfWork();
    foreach ($uow->getScheduledEntityUpdates() as $key => $entity) {
        if ($entity instanceof Product) {
            $this->entitiesToProcess[] = $entity;
        }
    }
    /**
     * @var PersistentCollection $entity
     */
    foreach ($uow->getScheduledCollectionUpdates() as $entity) {
        foreach ($entity as $relationEntity) {
            if ($relationEntity instanceof Product) {
                $this->collectionToProcess[] = $entity;
            }
        }
    }
}

in entitiesToProcess I store simple field changes, and on collectionToProcess I store my collection changes. But the weird thing is that my ManyToMany changes is in getScheduledEntityUpdates where ManyToOne are stored in collectionToProcess

In postFlush method where I search my collectionToProcess request I have changed entities but I also have a problem.

In ManyToOne I have old and new values, but in ManyToMany I don't. I only have updated state. So I have those notices also when I don't update this field.

In another ManyToMany collection - my collection form of entity I have those values in getScheduledEntityUpdates instead of getScheduledCollectionUpdates which I don't understand why.

How can I catch ManyToMany relation changes ?

I tried to do this in simple way also in controller

    $basedEntity = $product;
    $command = new ProductEditCommand($product);
    $form = $this->createForm(ProductEditType::class, $command)->handleRequest($request);
    if ($form->isSubmitted() && $form->isValid()) {
        $this->commandBus->handle($command);
        var_dump($basedEntity->getName());
        var_dump(count($basedEntity->getTags()));
        var_dump(count($basedEntity->getFilters()));
        die("!");
    }

and whats weird. Name of the product is the old one - so before any changes. But relations like Tags or Filters are updated. How can I fetch related association from before changes ? f

2 个答案:

答案 0 :(得分:1)

对于PersistentCollection实体,使用getSnapshot()获取原始数据:)

http://www.doctrine-project.org/api/orm/2.3/class-Doctrine.ORM.PersistentCollection.html#_getSnapshot

答案 1 :(得分:0)

你给我正确的方向。我在getScheduledCollectionUpdates事件上使用getDeletedDiff和getInsertedDiff。但是我有一个问题,当我有形式的值,然后我执行操作并删除它们(集合是空的)。我没有在getScheduledCollectionUpdates或getScheduledCollectionDeletions中使用它们。我只是无法获取已删除的集合

这是我的onFlush收集方法:

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

    foreach ($uow->getScheduledCollectionUpdates() as $key => $entity) {
        if ($entity->getOwner() instanceof Product) {
            if ($entity->getTypeClass()->getName() === 'App\Entity\Tag') {
                if ($entity->isDirty()) {
                    $this->collectionToProcess[] = [
                        'type' => 'tags',
                        'old' => $this->fetchManyToManyRelation($entity->getInsertDiff()),
                        'new' => $this->fetchManyToManyRelation($entity->getDeleteDiff()),
                    ];
                }
            }
        }
    }
}

还有一件事。一个ManyToMany关联方面的反转Snapshot始终为空,与getDeleteDiff相同 - 只显示getInstertedDiff实际上是表单中的数据。因此,如果我有一个集合并添加另一个集合,我将在getInstertedDiff中有两个集合。如果我有一个关系并且没有添加任何关系 - 我仍然在getInsertedDiff中有一个集合而不是0。