Php 在doctrine mongodb中预更新事件时创建/持久化新文档

Php 在doctrine mongodb中预更新事件时创建/持久化新文档,php,mongodb,doctrine-odm,odm,doctrine-mongodb,Php,Mongodb,Doctrine Odm,Odm,Doctrine Mongodb,我正在使用doctrine-mongodb-odm-1.0.0-BETA10并试图在预更新事件运行时提供一些基于\InitialDocument的自定义逻辑 假设\InitialDocument获得了一些状态,这些状态必须作为新\StateDocument的初始状态。我在做这样的事情: class InitDocListener implements \Doctrine\Common\EventSubscriber { public function getSubscribedEvent

我正在使用
doctrine-mongodb-odm-1.0.0-BETA10
并试图在
预更新
事件运行时提供一些基于
\InitialDocument
的自定义逻辑

假设
\InitialDocument
获得了一些状态,这些状态必须作为新
\StateDocument
的初始状态。我在做这样的事情:

class InitDocListener implements \Doctrine\Common\EventSubscriber {
    public function getSubscribedEvents()
    {
        return [
            Events::preUpdate
        ];
    }

    public function preUpdate($args){
        $document = $args->getDocument();
        if($document instanceOf InitialDocument && $document->getState() == 'mine'){
            $stateDocument = new \StateDocument();
            $stateDocument->setInitDocument($document);
            $args->getDocumentManager()->persist($stateDocument);
            //no flush cause recursion happens
        }
    }

}
prePersist
事件由
\StateDocument
发生,但它不会将新文档持久保存在数据库中。和
postPersist
事件将永远不会触发

还有一些自定义逻辑,但都在事件范围内。在某一点上,逻辑可能引发异常,该异常必须停止
InitialDocument
的更新事件,因此
InitialDocument
状态取决于业务范围内的
\StateDocument
创建过程


我怎样才能解决这个问题<在更改集重新计算之前要运行的代码>预刷新事件不确定
初始文档
实例。因此,在
preFlush
上“搜索”更新是一种伎俩,让我觉得这不是正确的方法。请给我一个合适的建议。谢谢。

我为您的用例创建了一个测试用例。问题中代码中突出的一点是,您没有在生命周期回调期间对要修改的文档调用
重新计算SingleDocumentChangeSet()
,如中所述。但即使有了这个调用,新文档也不会被插入。这是因为UnitOfWork在插入和升级之后执行更新。完整顺序见:

  • 文件升级
  • 文件插入
  • 文件更新
  • 额外更新(由持久化类在内部安排)
  • 集合删除
  • 收藏更新
  • 文件删除
调度
preUpdate
事件时,新文档的追加/插入已经发生。即使调用了
重新计算SingleDocumentChangeSet()
,最终也会安排文档插入,但UnitOfWork会忽略这一点,并在清除所有计划队列时最终将其取消设置

虽然一个简单的解决方案是ODM在处理更新后检查额外的插入,但在某些情况下,这可能会导致无限循环。UnitOfWork排序早于我在项目中的工作,但我认为在最初的实现构思时,循环的风险可能是一个问题


作为一种解决方法,您可能希望侦听器转储要插入到其他容器(或侦听器本身)中的新文档,然后在事后检查是否有其他文档需要持久化/刷新。

我为您的用例创建了一个测试用例。问题中代码中突出的一点是,您没有在生命周期回调期间对要修改的文档调用
重新计算SingleDocumentChangeSet()
,如中所述。但即使有了这个调用,新文档也不会被插入。这是因为UnitOfWork在插入和升级之后执行更新。完整顺序见:

  • 文件升级
  • 文件插入
  • 文件更新
  • 额外更新(由持久化类在内部安排)
  • 集合删除
  • 收藏更新
  • 文件删除
调度
preUpdate
事件时,新文档的追加/插入已经发生。即使调用了
重新计算SingleDocumentChangeSet()
,最终也会安排文档插入,但UnitOfWork会忽略这一点,并在清除所有计划队列时最终将其取消设置

虽然一个简单的解决方案是ODM在处理更新后检查额外的插入,但在某些情况下,这可能会导致无限循环。UnitOfWork排序早于我在项目中的工作,但我认为在最初的实现构思时,循环的风险可能是一个问题


作为一种解决方法,您可能需要让侦听器转储要插入到其他容器(或侦听器本身)中的新文档,然后在事后检查是否需要保留/刷新其他文档。

谢谢。昨天我和UnitOfWork玩了一段时间,得出了类似的结论。您刚刚确认了这样一个假设:在这种情况下,我们需要在其他容器中处理插入文档。问题是,
preUpdate
事件会导致新文档的托管状态在提交时和提交后保持不变
//清除其上游(和其他内容)。文档保持已知状态并声明为托管状态,但在对该文档进行新的持久化/刷新时会导致错误。因此,我尝试将
flush()
包装起来,以在提交后处理自己的自定义事件
(在
清除后
),并再次添加scheduleForUpsert以防止执行
持久化()
。但它没有起作用。现在我正试图放弃
preUdpate
,完全支持我的
afterCommit
。如果问题在GitHub中得到批准,将带来一些(故障转移?)测试。决定放弃
preUpdate
事件,以支持wrapped flush,并在新文档持久化应用程序逻辑出现故障时实现具有回滚行为的
afterCommit
事件。队列:1<代码>预更新
验证初始文档并进行更改设置以进行回滚。2.
afterUpdate
将文档附加到
updated\u docs集合
。3
afterCommit
事件触发基于
updated_docs_collection
创建新文档,并在失败时刷新它们或回滚更新的文档。这不是一个很好的实现,但目前仍然有效。谢谢。昨天我和UnitOfWork玩了一段时间,得出了类似的结论。你刚刚加入了