在Doctrine实体上跟踪字段更改

时间:2015-07-22 12:52:49

标签: php entity-framework symfony doctrine-orm

我想跟踪对Doctrine Entity字段的更改。我使用Symfony 2.5.0和Doctrine 2.2.3。

到目前为止,我有EventSubscriber订阅preUpdate。在这里,我想创建一个新的实体,它存储新旧值并保存对更新的实体的引用。

问题是,我无法找到坚持这个新实体的方法。如果persist()中的preUpdateflush()中的postUpdate,如果我只更改了一个实体,则会有效。如果更改了多个实体,则会收到更改集为空的错误。

我试着摆弄不同的事件,结果不同。空白页面,跟踪entites不会持久化等。

我认为这应该是一个常见的用例 - 但我找不到例子。

2 个答案:

答案 0 :(得分:8)

不要使用preUpdate或postUpdate,您将遇到问题。请改为onFlush

此时您可以访问完整的变更集,因此您可以找出哪些字段已更改,已添加的内容等。您还可以安全地保留新实体。请注意,docs表示,在持久化或更改实体时,您必须重新计算更改集。

简单的例子我一起敲了一下,没有经过测试,但类似的东西会得到你想要的东西。

public function onFlush(OnFlushEventArgs $args) {

    $entityManager = $args->getEntityManager();
    $unitOfWork = $entityManager->getUnitOfWork();
    $updatedEntities = $unitOfWork->getScheduledEntityUpdates();

    foreach ($updatedEntities as $updatedEntity) {

        if ($updatedEntity instanceof YourEntity) {

            $changeset = $unitOfWork->getEntityChangeSet($updatedEntity);

            if (!is_array($changeset)) {

                return null;
            }

            if (array_key_exists('someFieldInYourEntity', $changeset)) {

                $changes = $changeset['someFieldInYourEntity'];

                $previousValueForField = array_key_exists(0, $changes) ? $changes[0] : null;
                $newValueForField = array_key_exists(1, $changes) ? $changes[1] : null;

                if ($previousValueForField != $newValueForField) {

                    $yourChangeTrackingEntity = new YourChangeTrackingEntity();
                    $yourChangeTrackingEntity->setSomeFieldChanged($previousValueForField);
                    $yourChangeTrackingEntity->setSomeFieldChangedTo($newValueForField);

                    $entityManager->persist($yourChangeTrackingEntity);
                    $metaData = $entityManager->getClassMetadata('YourNameSpace\YourBundle\Entity\YourChangeTrackingEntity');
                    $unitOfWork->computeChangeSet($metaData, $yourChangeTrackingEntity);
                }
            }
        }
    }
}

答案 1 :(得分:3)

您可能对EntityAudit bundle感兴趣。

它允许配置应跟踪哪些实体。然后介绍了数据库 revisions 的概念。每个修订版都有时间戳,用户名和受影响的实体列表。

然后,您可以找到影响特定实体的所有修订:

$revisions = $auditReader->findRevisions('AppBundle\Entity\Article', 1);

或在特定版本中实例化它:

$oldArticle = $auditReader->find(
  'AppBundle\Entity\Article',
  $id = 1,
  $rev = 2
);

这样您就可以轻松比较实体的当前状态和旧状态。

该软件包还附带了示例视图,演示了如何显示修订列表,比较不同版本的对象等。

selecting comparison

comparison view