Как я могу узнать, изменит ли текущая транзакция какие-либо объекты с Doctrine 2?

Я использую Doctrine для сохранения пользовательских данных, и я хочу иметь last modification поле last modification . Вот псевдокод для того, как я хотел бы сохранить форму, как только пользователь нажмет Save :

  • начать транзакцию
  • делать много вещей, возможно, запрашивая базу данных, возможно, не
  • если что-либо будет изменено этой транзакцией
    • изменить last updated поле
  • совершать транзакции

Проблемная часть заключается в if anything will be changed by this transaction . Может ли доктрина дать мне такую ​​информацию?

Как я могу определить, изменились ли сущности в текущей транзакции?

редактировать

Просто для того, чтобы прояснить ситуацию, я пытаюсь изменить поле, называемое lastUpdated в объекте под названием « User если какой-либо объект (включая, но не ограничиваясь этим, User ) будет изменен после совершения currect транзакции. Другими словами, если я начинаю транзакцию и nbCars поле, называемое nbCars объекта под названием Garage , я хочу обновить lastUpdated обновленное поле объекта User даже если этот объект не был изменен.

Это необходимый ответ, который направлен на исправление того, что опубликовал @ColinMorelli (поскольку сброс в прослушиватель событий события жизненного цикла запрещен – да, в документах есть одно место, которое говорит иначе, но мы избавимся от этого, поэтому, пожалуйста, не делайте этого сделай это!).

Вы можете просто прослушать onFlush со слушателем, как onFlush ниже:

 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); } } 

Это применит изменение к настроенному объекту User только в том случае, если UnitOfWork содержит изменения, которые должны быть UnitOfWork к БД (единица работы на самом деле может быть определена как транзакция состояния уровня приложения).

Вы можете зарегистрировать этого абонента в ORM в любое время, позвонив

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

Извините за то, что вы сначала дали неверный ответ, это должно вести вас в правильном направлении (обратите внимание, что это не идеально).

Вам нужно будет реализовать два события. Тот, кто слушает событие OnFlush и действует следующим образом:

 // 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()); } } 

Нам нужно дождаться события OnFlush, потому что это единственная возможность для нас получить доступ ко всей работе, которая будет выполнена. Заметьте, я не включил его выше, но также есть $unitOfWork->getScheduledEntityDeletions() , если вы хотите отслеживать это.

Затем вам понадобится другой последний прослушиватель событий, который прослушивает событие PostFlush и выглядит следующим образом:

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

Как только транзакция была запущена, слишком поздно, к сожалению, получить доктрину для сохранения другого объекта. Из-за этого мы можем сделать обновление в поле объекта User в обработчике OnFlush, но мы не можем его фактически сохранить. (Вероятно, вы можете найти способ сделать это, но он не поддерживается Doctrine и должен будет использовать некоторые защищенные API-интерфейсы UnitOfWork).

Однако, как только транзакция завершается, вы можете немедленно выполнить другую быструю транзакцию, чтобы обновить дату и время для пользователя. Да, у этого есть неудачный побочный эффект, который не выполняется в одной транзакции.

Событие @PreUpdate не будет вызываться, если нет изменений в сущности.

Мое предположение было бы, подобно другим двум ответам, состоять в том, чтобы сказать, что вы хотите делать, когда будут или не будут изменения, используйте прослушиватели событий.

Но если вы хотите знать только до начала транзакции, вы можете использовать Doctrine_Record::getModified() ( ссылка ).