Я использую 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()
( ссылка ).