在doctrine-mongodb中的preUpdate事件中创建/保留新文档

laz*_*mit 2 php mongodb odm doctrine-odm doctrine-mongodb

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

假设\InitialDocument获得了某种状态,该状态必须表现为 new 的初始状态\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
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

prePersist事件\StateDocument发生,但它不会将新文档保留在数据库中。因此postPersist事件永远不会被触发。

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

我怎么解决这个问题?preFlush在changeSet重新计算之前运行的事件不确定InitialDocument实例。所以这是一种“搜索”更新的技巧preFlush,让我认为这不是正确的方法。请给我一个合适的建议。谢谢。

jmi*_*ola 5

我在这里为您的用例创建了一个测试用例。从您问题中的代码中脱颖而出的一件事是,您没有recomputeSingleDocumentChangeSet()在生命周期回调期间调用正在修改的文档,如preUpdate文档中所述。但即使进行该调用,新文档也不会被插入。这是因为 UnitOfWork在插入和更新插入执行更新。完整的顺序可以在UnitOfWork 的commit()方法中看到:

  • 文档更新插入
  • 文档插页
  • 文档更新
  • 额外更新(由持久化类内部安排)
  • 集合删除
  • 收藏更新
  • 文档删除

preUpdate事件被调度时,新文档的更新插入/插入已经发生。即使调用了recomputeSingleDocumentChangeSet(),您最终也会安排文档插入,但 UnitOfWork 会忽略这一点,并最终在清除此处的所有计划队列时取消设置它。

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

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