在 Doctrine Entity Listener 的 preUpdate 中保留其他实体 [英] Persisting other entities inside preUpdate of Doctrine Entity Listener

查看:27
本文介绍了在 Doctrine Entity Listener 的 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
    }
}

搜索了一下我发现你不能在监听器内部调用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) 好像有点矫枉过正

2) It seems a bit an overkill

谢谢!

推荐答案

不要使用 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 Entity Listener 的 preUpdate 中保留其他实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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