【问题标题】:Track field changes on Doctrine entity跟踪 Doctrine 实体上的字段更改
【发布时间】:2015-07-22 12:52:48
【问题描述】:

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

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

问题是,我找不到保留这个新实体的方法。如果我在preUpdatepersist()flush()postUpdate 中,如果我只更改一个实体,它就可以工作。如果更改了多个实体,我会收到变更集为空的错误。

我尝试摆弄具有不同结果的不同事件。空白页、跟踪实体不会被持久化等。

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

【问题讨论】:

    标签: php entity-framework symfony doctrine-orm


    【解决方案1】:

    不要使用 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 (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);
                    }
                }
            }
        }
    }
    

    【讨论】:

    • 坦克你,我建立它类似于你的例子。它现在就像一个魅力。
    • if (!is_array($changeset)) { return null; } 应该继续吗?
    • @jgmjgm 不,因为在上面的示例中 a) 您找到了要检查更改的特定实体类,并且 b) 没有更改,所以您完成了。继续不会破坏任何东西,但会增加不必要的额外迭代。如果您要检查多个不同的实体类,那么 continue 会很有意义。
    • 一个更好的问题:为什么变更集不是一个数组,为什么在遇到这种情况后不会有另一个相同类型的实体?
    • 根据文档并查看代码,更改集应该始终是一个数组,因此可能不需要 if 条件。如果是,那么它可能是版本相关的、文档中的漏洞甚至是小错误。
    【解决方案2】:

    您可能对EntityAudit bundle 感兴趣。

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

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

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

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

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

    因此您可以轻松比较实体的当前状态和旧状态。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-10
      • 2011-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多