DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Cover image for Getting Doctrine's ChangeSet in a postUpdate event
Paul Rijke
Paul Rijke

Posted on

Getting Doctrine's ChangeSet in a postUpdate event

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.

Top comments (0)

Let's Get Wacky


Use any Linode offering to create something unique or silly in the DEV x Linode Hackathon 2022 and win the Wacky Wildcard category

β†’ Join the Hackathon <-