Doctrine2
offers very powerful API for getting entity properties that have changed. This can be achieved using Doctrine\ORM\UnitOfWork
. We can call:
Doctrine\ORM\UnitOfWork::computeChangeSets()
to compute all the changes that have been done to entities and collections and store these changes;Doctrine\ORM\UnitOfWork::getEntityChangeSet($entity)
to retrieve all changes to our entity object;Doctrine\ORM\UnitOfWork::getOriginalEntityData($entity)
to retrieve the original data of an entity before introduced changes.
This simple example will explain it:
1 2 3 4 5 6 7 8 9 |
// find entity $post = $em->find('Entity\Post', 1); // change property value $post->setStatus(\Entity\Post::STATUS_PUBLISHED); $uow = $em->getUnitOfWork(); // this step is required only if you are using UnitOfWork outside of listeners $uow->computeChangeSets(); $changeset = $uow->getEntityChangeSet($post); |
But what about relations? While working with Doctrine2
relations we are dealing with Doctrine\ORM\PersistentCollection
which also has some useful public methods:
Doctrine\ORM\PersistentCollection::getSnapshot
to return the last snapshot of the elements in the collection;Doctrine\ORM\PersistentCollection::getDeleteDiff
to return removed entities from the collection;Doctrine\ORM\PersistentCollection::getInsertDiff
to return new entities thast have been added to the collection;Doctrine\ORM\PersistentCollection::isDirty
to check whether this collection is dirty which means its state needs to be synchronized with the database.
Those methods are marked in doc as INTERNAL
but have public access.
Usage:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// find entity $post = $em->find('Entity\Post', 1); $tag1 = $em->find('Entity\Tag', 1); $tag2 = $em->find('Entity\Tag', 2); $uow = $em->getUnitOfWork(); $post->addTag($tag1); // this step is required only if you are using UnitOfWork outside of listeners $uow->computeChangeSets(); // entities that have been added $changeset = $post->getTags()->getInsertDiff(); $post->removeTag($tag2); // this step is required only if you are using UnitOfWork outside of listeners $uow->computeChangeSets(); // entities that have been removed $changeset = $post->getTags()->getDeleteDiff(); |
This is very useful when you are auditing your entities and you want to know how your entities relations are changing, for example while adding / removing Post->tags
or User->roles
. We don’t need to store whole entities state because this should be audited separately but we can store its ids. In my case solution that I needed was:
1 2 3 4 5 6 7 |
$uow->computeChangeSets(); // PersistentCollection $collection = $post->getTags(); if ($collection-isDirty()) { // audit tags -> remember current state } |
To store something like:
1 2 3 |
[ 'tags' => [1, 8] ] |
I hope this will be useful as lately I was looking for similar solution for Doctrine2
relations.
Pingback: Is there a built-in way to get all of the changed/updated fields in a Doctrine 2 entity()