我有一个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".
答案 0 :(得分:0)
对其他实体的任何修改都必须进入onFlush事件。在preUpdate中调用持久化将产生不可预测的结果。这里有一个很好的解释示例。
Track field changes on Doctrine entity 可以在Doctrine文档中的Doctrine documentation处找到更多参考资料。