我想跟踪对Doctrine Entity字段的更改。我使用Symfony 2.5.0和Doctrine 2.2.3。
到目前为止,我有EventSubscriber
订阅preUpdate
。在这里,我想创建一个新的实体,它存储新旧值并保存对更新的实体的引用。
问题是,我无法找到坚持这个新实体的方法。如果persist()
中的preUpdate
和flush()
中的postUpdate
,如果我只更改了一个实体,则会有效。如果更改了多个实体,则会收到更改集为空的错误。
我试着摆弄不同的事件,结果不同。空白页面,跟踪entites不会持久化等。
我认为这应该是一个常见的用例 - 但我找不到例子。
答案 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
);
这样您就可以轻松比较实体的当前状态和旧状态。
该软件包还附带了示例视图,演示了如何显示修订列表,比较不同版本的对象等。