Встроенный документ в наборе изменений прослушивателя событий Doctrine

Я использую класс слушателя событий доктрины для реализации регистрации событий БД. Я использую событие postUpdate. У меня есть встроенный документ в моем документе mongoDB. В событии postUpdate, когда я вызываю $uow->getDocumentChangeSet($entity) метод, я получаю только измененные значения в объекте набора изменений. например

[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 ответ

Решение

Я не очень знаком с доктриной ODM (монго), но я знаком с доктриной ORM, и у них много общего. Я создал регистраторы, подобные тому, который вы описываете для ORM, поэтому позвольте мне поделиться своим опытом.

Какие события и почему

Я предпочитаю подключать событие OnFlush, потому что это единый момент времени, когда все операции записи могут быть найдены непосредственно перед тем, как они действительно произойдут. Таким образом, вы можете получить последовательный набор изменений, которые должны произойти.

С ORM, используя PostPersist, PostUpdate и PostDelete, вы опоздаете, так как изменения уже произошли, и не сможете получить надежные наборы изменений.

Используя PrePersist, PreUpdate и PreDelete, вы не получите ни единого момента времени: PreUpdate и PreDelete произойдут внутри операции сброса, но PrePersist произойдет, как только вы вызовете persist() на объекте / документе.

Таким образом, в слушателе OnFlush я соберу все изменения сущности / документа, а также изменения ассоциации. Я буду хранить их в памяти до тех пор, пока не будет отправлено событие PostFlush. Событие PostFlush происходит сразу после того, как все сохранено в базе данных, так что это безопасная точка для записи журнала. Другими словами: когда операция сброса по какой-либо причине завершится неудачно, журнал не будет записан, потому что мы на самом деле ничего не сохранили.

Что отслеживать

С ORM изменения скалярных свойств всегда обнаруживаются. Но изменения в объектах обнаруживаются по ссылке. Это означает, что если свойство содержит новый объект, изменение обнаруживается. Но когда свойство содержит тот же объект (хотя сам этот объект изменился), изменение не будет обнаружено.

Вот почему, по крайней мере с ORM, сущности с измененными коллекциями не будут отображаться в возвращаемом значении $uow->getScheduledEntityInsertions()и т. д. Я не уверен, но подозреваю, что ODM ведет себя так же.

Поэтому при отслеживании изменений в слушателе вам придется использовать все эти методы:

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

Последние 2 из них вернут массив коллекций, которые были изменены. Из коллекции вы можете получить владеющую сущность / документ ($col->getOwner()) и использовать методы diff ($col->getInsertDiff() а также $col->getDeleteDiff()) чтобы узнать, что именно изменилось.

Я надеюсь, что это поможет вам найти решение!

Другие вопросы по тегам