我希望每次保存新的 Distance
实体(从 Place_A 到 Place_B)时,都会得到相反的距离(从 Place_B 到 Place_A) gets inserted too into the DB .
我的问题是以下监听器无限循环(因此是计数器):
class Listener
{
public $count;
public function prePersist(LifecycleEventArgs $eventArgs)
{
if ($this->count > 5) {
die();
}
$entity = $eventArgs->getEntity();
if ($entity instanceof Distance) {
// $this->created = microtime(true) in Distance's constructor
echo 'Entity created at ' . $entity->created;
if ($entity->isReverse) {
echo " is reverse\n";
} else {
echo " is not reverse\n";
$this->count++;
$reverse = new Distance();
$reverse->setOrigin($entity->getDestination());
$reverse->setDestination($entity->getOrigin());
$reverse->set($entity->getMiles());
$reverse->isReverse = true;
$em = $eventArgs->getEntityManager();
$em->persist($reverse);
$em->flush();
}
}
}
}
输出:
Entity created at 1433168310.8787 is not reverse
Entity created at 1433168310.9073 is reverse
Entity created at 1433168310.8787 is not reverse
Entity created at 1433168310.9078 is reverse
Entity created at 1433168310.8787 is not reverse
Entity created at 1433168310.908 is reverse
Entity created at 1433168310.8787 is not reverse
Entity created at 1433168310.9084 is reverse
Entity created at 1433168310.8787 is not reverse
Entity created at 1433168310.9087 is reverse
Entity created at 1433168310.8787 is not reverse
这就像原始实体(创建时间以 8787 结尾)被保留了无数次。
以防万一,如果我删除对 $em->flush
的调用,我会正确地得到以下输出:
Entity created at 1433167824.2552 is not reverse
Entity created at 1433167824.2947 is reverse
但随后出现异常,表示没有参数绑定(bind)到插入查询。 Symfony 的分析器证实了这一点:
INSERT INTO Distance (
miles, origin_id, destination_id
)
VALUES
(?, ?, ?)
Parameters: { }
我想了解为什么我的监听器不能按我的预期工作,以及如何修复它。
根据要求,这里有更多代码。一切都来自地点
表单,除了输入地点名称之外,我还可以添加/删除/编辑到其他地点
的距离集合。
// PlaceController::updateAction
public function updateAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('MyBundle:Place')->find($id);
if (! $entity) {
throw $this->createNotFoundException('Unable to find Place entity.');
}
$deleteForm = $this->createDeleteForm($id);
$editForm = $this->createForm(new PlaceType(), $entity, array(
'action' => $this->generateUrl('update_place', array('id' => $entity->getId())),
'method' => 'PUT'
));
$editForm->add('submit', 'submit', array('label' => 'panel.button.save'));
$editForm->handleRequest($request);
if ($editForm->isValid()) {
$em->flush();
return array(
'entity' => $entity,
'form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
);
}
// PlaceType::buildForm
public function buildForm(FormBuilderInterface $builder, array $options)
{
$Place = $builder->getData();
$builder
->add(
'name',
'text',
[
'label' => 'object.place.name'
]
)
->add(
'distancesTo',
'collection',
[
'label' => 'object.place.distance.plural',
'type' => new DistanceType(),
'by_reference' => false,
'allow_add' => true,
'allow_delete' => true,
'options' => [
'required' => false,
'origin' => $Place->getId() ? $Place : null
]
]
);
}
最佳答案
你不应该在 prePersist 中使用 $em->flush() ,它受到 Doctrine 的限制:http://doctrine-orm.readthedocs.org/en/latest/reference/events.html#reference-events-implementing-listeners
有关于 preUpdate 的信息,但同样的情况(循环)适用于 prePesist 调用
9.6.6。预更新
PreUpdate is the most restrictive to use event, since it is called right before an update statement is called for an entity inside the EntityManager#flush() method. Changes to associations of the updated entity are never allowed in this >event, since Doctrine cannot guarantee to correctly handle referential ?integrity at this point of the flush operation.
这里描述了类似的情况preUpdate() siblings manage into tree: how to break ->persist() recursion?
因此,您也可以采用类似的方式:创建自定义事件,创建自定义事件订阅者,您将在其中创建反向实体并在 Controller 操作处分派(dispatch)该事件订阅者。
关于php - 尝试保存其他实体时 Doctrine 事件监听器中的无限循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30576245/