Getting Doctrine's ChangeSet in a postUpdate event
Paul Rijke

Paul Rijke @parijke

About: Paul is a senior backend developer at Dawn Technology

Location:
The Netherlands
Joined:
Jan 22, 2021

Getting Doctrine's ChangeSet in a postUpdate event

Publish Date: Sep 30 '22
1 0

Recently, I had the need of having the changes of an entity in a lifecycle event after the database was updated. Normally, the postUpdate event doesn't have access to this information. So, what to do?

I figured, that storing the changes during onFlush or preUpdate would do the trick, but how? I did not want to enforce extra database calls. Therefor, the in memory ArrayAdapter of symfony cache to the rescue.

According to the documentation:

Generally, this adapter is useful for testing purposes, as its contents are stored in memory and not persisted outside the running PHP process in any way.

So it is gone after the running process? Exactly what I needed. Here's how I set it during a preUpdate.

class DoctrineSubscriber implements EventSubscriberInterface
{
    private ArrayAdapter $arrayAdapter;

    public function __construct(
    ) {
        $this->arrayAdapter = new ArrayAdapter();
    }

    public function getSubscribedEvents(): array
    {
        return [
            Events::preUpdate, //OR
            Events::onFlush,
            // THEN
            Events::postUpdate,

        ];
    }

    public function preUpdate(PreUpdateEventArgs $args): void
    {
        $entity = $args->getObject();

        if ($entity instanceof Meeting) {
            $this->arrayAdapter->get($entity->getId(), fn () => $args->getEntityChangeSet());
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Then, you can easily retrieve it using the stored id as the key, like:

public function postUpdate(LifeCycleEventArgs $args)
    {
        $entity = $args->getObject();

        if ($entity instanceof Meeting) {
            $id = $entity->getId();
            $changeSet = $this->arrayAdapter->getItem($id)->get();
        }

    }
Enter fullscreen mode Exit fullscreen mode

If for some reason the database wasn't updated due to errors, the postUpdate isn't called and the changeset disappears. Just as I needed.

If you want to be sure on listeners or subscribers changes your entity before persistence, you should/could use the onFlush event instead, like this:

public function onFlush(OnFlushEventArgs $eventArgs): void
    {
        $uow = $eventArgs->getObjectManager()->getUnitOfWork();

        foreach ($uow->getScheduledEntityUpdates() as $entity) {
            if ($entity instanceof Meeting) {
                $this->arrayAdapter->get($entity->getId(), fn () => $uow->getEntityChangeSet($entity));
            }
        }
    }
Enter fullscreen mode Exit fullscreen mode

Because onFlush is the last event called before database persistence, we're pretty sure nothing altered the changeset afterwards.

As a disclaimer... I use uuid as the id, so I am pretty sure the cache key will be unique for that change.

Comments 0 total

    Add comment