Doctrine多个侦听器级联

时间:2016-02-26 15:13:35

标签: php symfony orm doctrine

我有一个Symfony项目,它使用Doctrine2作为主要的ORM。该项目有多个相互关联的实体。我有以下实体:

Order - order in the shop
Product - products in orders
Addon - addons for products

对象按以下方式链接:

Order
|- Product
|- Product
   |- Addon
   |- Addon

订单和产品实体都有一个"状态" -field。产品的状态与订单的状态有关。产品和订单的状态可以通过几种方式改变;他们需要互相反应。

我正在考虑使用Doctrine EntityListeners来监听实体中的更改。因此,当订单实体的状态发生时,监听器可以更新产品的状态。

检测Order实体中的更改效果很好。但是当我想改变其产品的状态时,我需要清除Doctrine中的更改。当我从OrderListener中刷新Products的更改时,Symfony崩溃。

TL; DR:检测实体字段中更改的最佳方法是什么,并根据这些更改更新其他实体。

提前致谢,

的Wouter

services.yml

order_listener:
    class: AppBundle\EntityListener\OrderListener
    arguments: [ '@service_container' ]
    tags:
    - {name: doctrine.event_listener, event: preUpdate}
    - {name: doctrine.event_listener, event: postFlush}
product_listener:
    class: AppBundle\EntityListener\ProductListener
    arguments: [ '@service_container' ]
    tags:
    - {name: doctrine.event_listener, event: preUpdate}

OrderListener

namespace AppBundle\EntityListener;

use AppBundle\Entity\Product;
use AppBundle\Entity\Order;
use Doctrine\ORM\Event\PostFlushEventArgs;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use Symfony\Component\DependencyInjection\Container;

class OrderListener {

    /**
     * @var Container
     */
    protected $container;

    /**
     * @var PreUpdateEventArgs[]
     */
    protected $changed = [];

    /**
     * OrderListener constructor.
     *
     * @param Container $container
     */
    public function __construct(Container $container) {

        $this->container = $container;
    }

    public function preUpdate(PreUpdateEventArgs $preUpdateEventArgs){

        if(!$preUpdateEventArgs->getEntity() instanceof Order)
            return;

        $this->changed[] = $preUpdateEventArgs;
    }

    public function postFlush(PostFlushEventArgs $postFlushEventArgs){

        foreach($this->changed as $preUpdateEventArgs){

            /** @var Product $product */
            $em = $this->container->get('doctrine')->getEntityManager();
            foreach($preUpdateEventArgs->getEntity()->getProducts() as $product) {

                $product->setStatus(Product::STATUS_COMPLETED);
                $em->persist($product);
            }

            $em->flush();
        }

        $this->changed = [];
    }
}

ProductListener

namespace AppBundle\EntityListener;

use AppBundle\Entity\Product;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use Symfony\Component\DependencyInjection\Container;

class ProductListener {

    /**
     * @var Container
     */
    protected $container;

    /**
     * OrderListener constructor.
     *
     * @param Container $container
     */
    public function __construct(Container $container) {

        $this->container = $container;
    }

    public function preUpdate(PreUpdateEventArgs $eventArgs){

        if(!$eventArgs->getEntity() instanceof Product)
            return;

        dump($eventArgs);
    }
}

当刷新Order Symfony时,会出现此错误:

[Symfony\Component\Process\Exception\RuntimeException]  
The process has been signaled with signal "11".   

1 个答案:

答案 0 :(得分:0)

对其他实体的任何修改都必须进入onFlush事件。在preUpdate中调用持久化将产生不可预测的结果。这里有一个很好的解释示例。

Track field changes on Doctrine entity 可以在Doctrine文档中的Doctrine documentation处找到更多参考资料。