How can I find out if the current transaction will change any objects with Doctrine 2?

I use Doctrine to save user data, and I want to have a last modification field. Here is the pseudocode for how I would like to save the form as soon as the user clicks Save :

  • start a transaction
  • do a lot of things, possibly querying the database, maybe not
  • if something is changed by this transaction
    • change last updated field
  • make a transaction

The problem part is if anything will be changed by this transaction . Can a doctrine give me such information?

How do I know if entities have changed in the current transaction?

change

Just to clarify the situation, I am trying to change a field called lastUpdated in essence with the name User , if any object (including, but not limited to, User ) changes after a currect transaction, In other words, if I start a transaction and change the field called nbCars object named Garage , I want to update the lastUpdated field of the lastUpdated object, even if this object has not been changed.

+2
source share
4 answers

This is a necessary answer that aims to correct what @ColinMorelli posted (since dumping a lifecycle event into the event listener is forbidden - yes, there is one place in the documents that says otherwise, but we will get rid of it, so please do not do this !).

You can just listen onFlush with the following listener:

 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 UnitOfWork contains changes that must be bound to the database (the unit of work is actually what you could define as an application-level state transaction).

You can register this subscriber in ORM at any time by calling

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

Sorry to give you the wrong answer at first, this should lead you in the right direction (note that this is not ideal).

You will need to implement two events. Anyone who listens to the OnFlush event and acts as follows:

 // This should listen to OnFlush events public function updateLastModifiedTime(OnFlushEventArgs $event) { $entity = $event->getEntity(); $entityManager = $event->getEntityManager(); $unitOfWork = $entityManager->getUnitOfWork(); if (count($unitOfWork->getScheduledEntityInsertions()) > 0 || count($unitOfWork->getScheduledEntityUpdates()) > 0) { // update the user here $this->user->setLastModifiedDate(new \DateTime()); } } 

We need to wait for the OnFlush event, because this is the only opportunity for us to access all the work that will be done. Notice I did not include it above, but there is also $unitOfWork->getScheduledEntityDeletions() if you want to track this.

Then you need another last event listener that listens for the PostFlush event and looks like this:

 // This should listen to PostFlush events public function writeLastUserUpdate(PostFlushEventArgs $event) { $entityManager = $event->getEntityManager(); $entityManager->persist($this->user); $entityManager->flush($this->user); } 

Once the transaction has been started, it is too late, unfortunately, to get a doctrine to save another object. Because of this, we can do an update in the field of the User object in the OnFlush handler, but we cannot actually save it. (You can probably find a way to do this, but it is not supported by Doctrine and will have to use some of UnitOfWork's secure APIs.)

Once the transaction completes, you can immediately execute another quick transaction to update the date and time for the user. Yes, this has an unfortunate side effect that is not executed in a single transaction.

+2
source

@PreUpdate event will not be @PreUpdate if there are no changes to the entity.

+1
source

My guess would, like the other two answers, be to say what you want to do when there will be or will not be changes, use event listeners.

But if you want to know just before the start of the transaction, you can use Doctrine_Record::getModified() ( link ).

+1
source

All Articles