Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I tell if the current transaction will change any entities with Doctrine 2?

I'm using Doctrine to save user data and I want to have a last modification field. Here is the pseudo-code for how I would like to save the form once the user presses Save:

  • start transaction
  • do a lot of things, possibly querying the database, possibly not
  • if anything will be changed by this transaction
    • modify a last updated field
  • commit transaction

The problematic part is if anything will be changed by this transaction. Can Doctrine give me such information?

How can I tell if entities have changed in the current transaction?

edit

Just to clear things up, I'm trying to modify a field called lastUpdated in an entity called User if any entity (including but not limited to User) will be changed once the currect transaction is commited. In other words, if I start a transaction and modify the field called nbCars of an entity called Garage, I wish to update the lastUpdated field of the User entity even though that entity hasn't been modified.

like image 625
Shawn Avatar asked Mar 07 '13 20:03

Shawn


People also ask

What is a repository doctrine?

It means the place where our data can be accessed from, a repository of data. This is to distinguish it from a database as a repository does not care how its data is stored.

What is symfony Doctrine?

Symfony provides all the tools you need to use databases in your applications thanks to Doctrine, the best set of PHP libraries to work with databases. These tools support relational databases like MySQL and PostgreSQL and also NoSQL databases like MongoDB.

What is Symfony flush?

The flush tag tells Twig to flush the output buffer: 1 {% flush %} Internally, Twig uses the PHP flush function. « filter | for » The Twig logo is © 2010-2022 Symfony.


1 Answers

This is a necessary reply that aims at correcting what @ColinMorelli posted (since flushing within an lifecycle event listener is disallowed - yes, there's one location in the docs that says otherwise, but we'll get rid of that, so please don't do it!).

You can simply listen to onFlush with a listener like following:

use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\Events;

class UpdateUserEventSubscriber implements EventSubscriber
{
    protected $user;

    public function __construct(User $user)
    {
        // assuming the user is managed here
        $this->user = $user;
    }

    public function onFlush(OnFlushEventArgs $args)
    {
        $em  = $args->getEntityManager();
        $uow = $em->getUnitOfWork();

        // before you ask, `(bool) array()` with empty array is `false`
        if (
            $uow->getScheduledEntityInsertions()
            || $uow->getScheduledEntityUpdates()
            || $uow->getScheduledEntityDeletions()
            || $uow->getScheduledCollectionUpdates()
            || $uow->getScheduledCollectionDeletions()
        ) {
            // update the user here
            $this->user->setLastModifiedDate(new DateTime());
            $uow->recomputeSingleEntityChangeSet(
                $em->getClassMetadata(get_class($this->user)), 
                $this->user
            );
        }
    }

    public function getSubscribedEvents()
    {
        return array(Events::onFlush);
    }
}

This will apply the change to the configured User object only if the UnitOfWork contains changes to be committed to the DB (an unit of work is actually what you could probably define as an application level state transaction).

You can register this subscriber with the ORM at any time by calling

$user         = $entityManager->find('User', 123);
$eventManager = $entityManager->getEventManager();
$subscriber   = new UpdateUserEventSubscriber($user);

$eventManager->addEventSubscriber($subscriber);
like image 173
Ocramius Avatar answered Sep 20 '22 17:09

Ocramius