在Doctrine实体监听器的preUpdate内部持续其他实体 [英] Persisting other entities inside preUpdate of Doctrine Entity Listener

查看:157
本文介绍了在Doctrine实体监听器的preUpdate内部持续其他实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了清楚起见,我继续讨论开始这里

For clarity I continue here the discussion started here.

里面 Doctrine实体监听器,在preUpdate方法中(我可以访问实体的任何字段的旧值和新值)我试图坚持一个与焦点不相关的实体。

Inside a Doctrine Entity Listener, in the preUpdate method (where I have access to both the old and new value of any field of the entity) I'm trying to persist an entity unrelated to the focal one.

基本上我有实体A,当我更改我要写入的一个字段中的值时,在project_notification表中,oldValue,newValue加上其他字段。

Basically I have entity A, and when I change a value in one of the fields I want to write, in the project_notification table, the fields oldValue, newValue plus others.

如果我没有在PreUpdate方法中刷新,新的通知实体不会存储在数据库中。如果我刷新它,我进入无限循环。

If I don't flush inside the preUpdate method, the new notification entity does not get stored in DB. If I flush it I enter into a infinite loop.

这是preUpdate方法:

This is the preUpdate method:

public function preUpdate(ProjectTolerances $tolerances, PreUpdateEventArgs $event)
{
    if ($event->hasChangedField('riskToleranceFlag')) {
    $project = $tolerances->getProject();                
    $em = $event->getEntityManager();
    $notification = new ProjectNotification();
    $notification->setValueFrom($event->getOldValue('riskToleranceFlag'));
    $notification->setValueTo($event->getNewValue('riskToleranceFlag'));
    $notification->setEntity('Entity'); //TODO substitute with the real one
    $notification->setField('riskToleranceFlag');
    $notification->setProject($project);
    $em->persist($notification);


    // $em->flush(); // gives infinite loop
    }
}

Googling有点我发现您不能在侦听器内调用flush,而在这里,建议将要持久存储的数据存储在数组中,以便稍后在onFlush中刷新。尽管如此,它不起作用,因为在调用preUpdate之后,监听器类的实例被破坏,所以当您以后调用onFlush时,在类的级别保存的受保护属性将被丢失,或者我是否缺少某些东西?)

Googling a bit I discovered that you cannot call the flush inside the listeners, and here it's suggested to store the stuff to be persisted in an array, to flush it later in the onFlush. Nonetheless it does not work (and probably it should not work, as the instance of the listener class gets destroyed after you call the preUpdate, so whatever you store in as protected attribute at the level of the class gets lost when you later call the onFlush, or am I missing something?).

以下是监听器的更新版本:

Here is the updated version of the listener:

class ProjectTolerancesListener
{
    protected $toBePersisted = [];

    public function preUpdate(ProjectTolerances $tolerances, PreUpdateEventArgs $event)
    {
        $uow = $event->getEntityManager()->getUnitOfWork();
//        $hasChanged = false;

        if ($event->hasChangedField('riskToleranceFlag')) {
        $project = $tolerances->getProject();                
        $notification = new ProjectNotification();
        $notification->setValueFrom($event->getOldValue('riskToleranceFlag'));
        $notification->setValueTo($event->getNewValue('riskToleranceFlag'));
        $notification->setEntity('Entity'); //TODO substitute with the real one
        $notification->setField('riskToleranceFlag');
        $notification->setProject($project);

        if(!empty($this->toBePersisted))
            {
            array_push($toBePersisted, $notification);
            }
        else
            {
            $toBePersisted[0] = $notification;
            }
        }
    }

    public function postFlush(LifecycleEventArgs $event)
    {
        if(!empty($this->toBePersisted)) {

            $em = $event->getEntityManager();

            foreach ($this->toBePersisted as $element) {

                $em->persist($element);
            }

            $this->toBePersisted = [];
            $em->flush();
        }
    }
}

也许我可以解决这个从监听器内部发出一个事件,并提供所有需要的信息,以便在刷新之后执行我的日志记录操作...但是:

Maybe I can solve this by firing an event from inside the listener with all the needed info to perform my logging operations after the flush...but:

1)我不知道我是否可以这样做

1) I don't know if I can do it

2)似乎有点过分了

谢谢!

推荐答案

不要使用preUpdate,请使用 onFlush - 这允许您访问UnitOfWork API&你可以坚持实体。

Don't use preUpdate, use onFlush - this allows you to access the UnitOfWork API & you can then persist entities.

例如。 (这是我如何在2.3中,可能会在较新版本中更改)

E.g. (this is how I do it in 2.3, might be changed in newer versions)

    $this->getEntityManager()->persist($entity);
    $metaData = $this->getEntityManager()->getClassMetadata($className);
    $this->getUnitOfWork()->computeChangeSet($metaData, $entity);

这篇关于在Doctrine实体监听器的preUpdate内部持续其他实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆