我使用原则来保存用户数据,我想有一个last modification
字段。这里是伪代码,我想如何保存表单一旦用户按下Save
:
- <
- 开始事务/gh>
- 做很多事情,可能是查询数据库,也可能不是
- 如果此事务将更改任何内容
- 修改
last updated
字段
< - 修改
- 提交事务/gh>
问题部分为if anything will be changed by this transaction
。教义能给我这样的信息吗?
我如何知道实体是否在当前事务中发生了变化?
编辑
只是为了澄清事情,我试图修改一个名为User
的实体中的一个名为lastUpdated
的字段,如果任何实体(包括但不限于User
)一旦提交当前事务将被更改。换句话说,如果我启动一个事务并修改一个名为Garage
的实体的nbCars
字段,我希望更新User
实体的lastUpdated
字段,即使该实体尚未被修改。
这是一个必要的回复,旨在纠正@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);
}
}
只有当UnitOfWork
包含要提交给DB的更改时,才会将更改应用到配置的User
对象(一个工作单元实际上可能是您可以定义为应用程序级状态事务的内容)。
您可以随时通过调用
向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);
}
一旦事务已经开始,不幸的是,要用原则来保存另一个实体已经太晚了。正因为如此,我们可以在OnFlush处理程序中使更新到User
对象的字段,但我们实际上不能将其保存在那里。(你可能会找到一种方法来做到这一点,但它不被Doctrine支持,并且必须使用UnitOfWork的一些受保护的api)
@PreUpdate
事件将不会被调用,如果在实体上没有变化。
我的猜测是,类似于其他两个答案,是说无论你想做什么,当会或不会有变化,使用事件侦听器。
但是如果您只想在事务开始之前知道,您可以使用Doctrine_Record::getModified()
(link)。