Symfony 2 - 在postUpdate fire preUpdate事件中刷新

时间:2012-07-06 18:23:01

标签: symfony doctrine-orm event-listener

我发现这个问题“谢谢”我得到的一个例外:

Catchable Fatal Error: Argument 3 passed to
Doctrine\ORM\Event\PreUpdateEventArgs::__construct() 
must be an array, null given, called in 
/.../vendor/doctrine/lib/Doctrine/ORM/UnitOfWork.php on line 804 
and defined in
/.../vendor/doctrine/lib/Doctrine/ORM/Event/PreUpdateEventArgs.php line 28

我正在开展一个需要特定逻辑的项目:
当实体order中的book字段被修改后,我需要更新父实体books_order_modified_at中的字段bookstore(此字段可让我知道图书的顺序是否为书店改了。)

我决定在事件监听器中执行此操作,因为代码中有许多位置可能会改变书籍的顺序。

我没有找到任何方法来更新preUpdate事件中的相关实体,所以我在监听器类中有一个私有字段,用于告诉postUpdate事件更新相关{ {1}}实体。

我的问题是,当我这样做时,bookstore实体的preUpdate事件被触发。
当我检查更改集时,它仅包含book字段,但它在前后具有相同的值。

如果有人不知道如何解决问题 - 很棒。

如果没有 - 任何想法如何在teh modified_at事件中调用flush时阻止preUpdate事件被触发?

4 个答案:

答案 0 :(得分:6)

实际上,这是来自学说Doctrine Issue DDC-2726的问题。通过在侦听器中刷新后在实体管理器上添加一个清除调用来解决它,因此将重写该构造函数的第3个参数,实际上是entityChangeSets。

答案 1 :(得分:1)

如何更新实体中的modified_at并让doctrine处理它?您可以在书中更改setOrder方法,以更新BookOrder实体,如下所示:

class Book {
    public function setOrder($order) {
        // modify book
        $this->bookOrder->updateModifiedAt();
    }
}

当然,您的BookOrder必须实现modifiedAt:

class BookOrder {
    public function updateModifiedAt() {
        $this->modifiedAt = new \DateTime();
    }
}

如果您在日期时使用其他课程,则当然必须更改此代码!

Doctrine应该认识到BookOrder已经改变,应该更新它而不需要使用事件监听器。

答案 2 :(得分:0)

我建议您使用来自DoctrineExtensionsBundle的Doctrine的Timestampable扩展名。

通过使用它,您无需设置created_atmodified_at值。此扩展程序自动执行。即使只有在修改特定字段时才能设置modified_at。请参阅example

我认为你正在写这样的扩展名。所以,你不需要这样做,因为这已经完成了:)

答案 3 :(得分:0)

我遇到了类似的问题。尝试使用preupdate修改子元素会导致相同的错误。最后,我的解决方案是简单地更新属于父级的子级。无需明确调用flush

/**
 * Update expiry dates for all runners belonging to a campaign
 *
 * @param $runners
 * @param $expiryDate
 */
private function updateCampaignRunners($runners, $expiryDate){
    foreach($runners as $runner){
        $runner->setExpiresAt($expiryDate);
        $this->getModelManager()->update($runner);
    }
}

/**
 * Post update and persist lifecycle callback
 *
 * @param Campaign $campaign
 */
private function postAction(Campaign $campaign)
{
    $runnerExpire = $this->getForm()->get("runnerExpire")->getData();
    if($runnerExpiryDate && $campaign->getRunners()){
        $this->updateCampaignRunners($campaign->getRunners(), $runnersExpiryDate);
    }
}