我正在使用Doctrine来保存用户数据,我希望有一个last modification
字段。
以下是用户在按下Save
后保存表单的伪代码:
last updated
字段有问题的部分是if anything will be changed by this transaction
。 Doctrtrine可以给我这样的信息吗?
如何判断当前交易中的实体是否已更改?
修改
只是要清理一下,如果任何实体(包括但不限于lastUpdated
)将被更改,我正在尝试修改名为User
的实体中名为User
的字段一旦当前交易被提交。换句话说,如果我启动一个事务并修改名为nbCars
的实体名为Garage
的字段,我希望更新lastUpdated
实体的User
字段,即使该实体尚未修改。
答案 0 :(得分:5)
这是一个必要的回复,旨在纠正@ColinMorelli发布的内容(因为不允许在生命周期事件监听器中进行刷新 - 是的,在文档中有一个位置,否则,但我们将摆脱它,所以请不要这样做!)。
您可以通过以下听众简单地收听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
包含要提交给DB的更改时,才会将更改应用于已配置的UnitOfWork
对象(工作单元实际上是您可能定义为应用程序级别的状态交易)。
您可以随时致电
向ORM注册此订户$user = $entityManager->find('User', 123);
$eventManager = $entityManager->getEventManager();
$subscriber = new UpdateUserEventSubscriber($user);
$eventManager->addEventSubscriber($subscriber);
答案 1 :(得分:2)
很抱歉一开始就给你错误的答案,这应该引导你朝正确的方向发展(注意它并不完美)。
您需要实施两项活动。一个听取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);
}
一旦交易开始,遗憾的是,为了获得保存另一个实体的学说,为时已晚。因此,我们可以将更新发送到OnFlush处理程序中User
对象的字段,但我们实际上无法将其保存在那里。 (您可能会找到一种方法来执行此操作,但Doctrine不支持它,并且必须使用UnitOfWork的一些受保护的API)。
但是,一旦事务完成,您可以立即执行另一个快速事务来更新用户的日期时间。是的,这确实存在不在单个交易中执行的不幸副作用。
答案 2 :(得分:1)
@PreUpdate
事件。
答案 3 :(得分:1)
与其他2个答案类似,我的猜测是,当有或没有变化时,无论你想做什么,都要使用事件监听器。
但如果您只想在事务开始前知道,则可以使用Doctrine_Record::getModified()
(link)。