更改集Doctrine事件监听器中的嵌入式文档

时间:2014-08-11 09:20:15

标签: php mongodb symfony doctrine-orm embedded-documents

我正在使用doctrine的事件监听器类来实现DB事件的记录。我正在使用postUpdate事件。我的mongoDB文档中有一个嵌入式文档。在postUpdate事件中,当我调用$uow->getDocumentChangeSet($entity)方法时,我只获取更改集对象中的更改值。 e.g。

[0]=>
  object(Tyre24\ProductBundle\Document\Translations)#1178 (1) {
    ["translations":protected]=>
    object(Doctrine\ODM\MongoDB\PersistentCollection)#1216 (10) {
      ["snapshot":"Doctrine\ODM\MongoDB\PersistentCollection":private]=>
      array(0) {
      }
      ["coll":"Doctrine\ODM\MongoDB\PersistentCollection":private]=>
      object(Doctrine\Common\Collections\ArrayCollection)#1217 (1) {
        ["_elements":"Doctrine\Common\Collections\ArrayCollection":private]=>
        array(1) {
          [0]=>
          object(Tyre24\ProductBundle\Document\Translation)#1227 (3) {
            ["key":protected]=>
            string(11) "testkey_new"
            ["language":protected]=>
            string(5) "xx_XX"
            ["value":protected]=>
            string(9) "testvalue"
          }
        }
      }
    }
  }
  [1]=>
  object(Tyre24\ProductBundle\Document\Translations)#1178 (1) {
    ["translations":protected]=>
    object(Doctrine\ODM\MongoDB\PersistentCollection)#1216 (10) {
      ["snapshot":"Doctrine\ODM\MongoDB\PersistentCollection":private]=>
      array(0) {
      }
      ["coll":"Doctrine\ODM\MongoDB\PersistentCollection":private]=>
      object(Doctrine\Common\Collections\ArrayCollection)#1217 (1) {
        ["_elements":"Doctrine\Common\Collections\ArrayCollection":private]=>
        array(1) {
          [0]=>
          object(Tyre24\ProductBundle\Document\Translation)#1227 (3) {
            ["key":protected]=>
            string(11) "testkey_new"
            ["language":protected]=>
            string(5) "xx_XX"
            ["value":protected]=>
            string(9) "testvalue"
          }
        }
      }
    }
  }
}

此处,更改集数组的第一个元素应该反映嵌入文档的旧状态,但它始终在两个数组索引中显示相同的(新)文档。对于没有嵌入文档的文档,它可以正常工作。有什么想法吗?

1 个答案:

答案 0 :(得分:3)

我对Doctrine ODM(mongo)不太熟悉,但我对Doctrine ORM很熟悉,它们有很多相似之处。我已经建立了你为ORM描述的记录器,所以让我分享一下我的经验。

哪些事件和原因

我赞成将OnFlush事件挂钩,因为它是可以找到所有写入操作的单一时间点,只是之前它们实际发生。因此,您可以获得即将发生的一系列一致的更改。

使用ORM,使用PostPersist,PostUpdate和PostDelete,您将会迟到,因为更改已经发生,并且无法获得可靠的更改集。

使用PrePersist,PreUpdate和PreDelete,您不会获得单个时间点:PreUpdate和PreDelete将在刷新操作中发生,但是一旦您在实体/文档上调用persist()就会发生PrePersist

因此,在OnFlush监听器中,我将收集所有实体/文档更改以及关联更改。我将这些保留在内存中,直到调度PostFlush事件。 PostFlush事件发生在所有内容持久存储到数据库之后,因此这是写日志的安全点。换句话说:当刷新操作因任何原因失败时,日志就不会被写入,因为我们实际上并没有保留任何内容。

追踪什么

使用ORM,始终会检测到标量属性的更改。但是通过引用检测对象的更改。这意味着如果属性包含新对象,则会检测到更改。但是当属性包含相同的对象时(尽管该对象本身已经更改),将无法检测到更改。

这就是为什么,至少在ORM中,具有更改集合的实体不会出现在$uow->getScheduledEntityInsertions()等的返回值中。我不确定,但我怀疑ODM的行为方式相同。

因此,当跟踪侦听器中的更改时,您必须使用所有这些方法:

  • $uow->getScheduledDocumentInsertions();
  • $uow->getScheduledDocumentUpserts();
  • $uow->getScheduledDocumentUpdates();
  • $uow->getScheduledDocumentDeletions();
  • $uow->getScheduledCollectionDeletions();
  • $uow->getScheduledCollectionUpdates();

其中最后两个将返回已更改的集合数组。从集合中,您可以获取拥有实体/文档($col->getOwner()),并使用diff方法($col->getInsertDiff()$col->getDeleteDiff())来找出确切更改的内容。

我希望这可以帮助您找到解决方案!