Reputation: 1579
I am using doctrine's event listener class to implement logging of the DB events. I am using postUpdate event. I have an embedded document within my mongoDB document. Within the postUpdate event, when I call the $uow->getDocumentChangeSet($entity)
method, I am only getting the changed values in the change set object. 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"
}
}
}
}
}
}
Here the first element of the change set array should reflect the older state of the embedded document, but it always shows the same (new) document in both the array indexes. For documents with no embedded documents, it works fine. Any idea?
Upvotes: 4
Views: 2232
Reputation: 21817
I'm not very familiar with the Doctrine ODM (mongo), but I am familiar with the Doctrine ORM, and they have a lot of similarities. I've built loggers like the one you describe for the ORM, so let me share my experience.
I favor the OnFlush event to hook into, because it's a single point in time where all write operations can be found, just before they actually happen. So you can get a consistent set of changes that are about to happen.
With the ORM, using PostPersist, PostUpdate and PostDelete you'll be to late, as the changes have already happened, and can't get reliable change-sets.
Using PrePersist, PreUpdate and PreDelete you won't get a single point in time: PreUpdate and PreDelete will happen inside a flush operation, but PrePersist happens as soon as you call persist()
on an entity/document.
So in a OnFlush listener, I will gather all entity/document changes, as well as association changes. I'll keep those in memory, until the PostFlush event gets dispatched. The PostFlush event happens right after everything is persisted into the database, so that's a safe point to write the log. In other words: When the flush operation fails for any reason, the log won't be written, because we haven't actually persisted anything.
With the ORM, changes to scalar properties are always detected. But changes to objects are detected by reference. This means that if the property contains a new object the change is detected. But when the property contains the same object (although that object itself has changed) the change won't be detected.
This is why, with the ORM at least, entities with changed collections won't show up in the return-value of $uow->getScheduledEntityInsertions()
, etc. I'm not sure, but I suspect the ODM behaves in the same way.
So when tracking changes in the listener, you'll have to use all these methods:
$uow->getScheduledDocumentInsertions();
$uow->getScheduledDocumentUpserts();
$uow->getScheduledDocumentUpdates();
$uow->getScheduledDocumentDeletions();
$uow->getScheduledCollectionDeletions();
$uow->getScheduledCollectionUpdates();
The last 2 of these will return an array of collections that have changed. From the collection you can get the owning entity/document ($col->getOwner()
), and use the diff methods ($col->getInsertDiff()
and $col->getDeleteDiff()
) to find out what changed exactly.
I hope this helps you reach a solution!
Upvotes: 4