Php 尝试保存其他实体时事件侦听器中的无限循环

Php 尝试保存其他实体时事件侦听器中的无限循环,php,symfony,orm,doctrine-orm,doctrine,Php,Symfony,Orm,Doctrine Orm,Doctrine,我希望每次保存一个新的距离实体(从地点a到地点B)时,反向距离(从地点B到地点a) 我的问题是以下侦听器无限循环(因此计数器): 输出: 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 r

我希望每次保存一个新的
距离
实体(从地点a到地点B)时,反向距离(从地点B到地点a)

我的问题是以下侦听器无限循环(因此计数器):

输出:

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
但是出现了一个异常,表示没有参数绑定到insert查询。经Symfony的档案员确认:

INSERT INTO Distance (
    miles, origin_id, destination_id
) 
VALUES 
(?, ?, ?)
Parameters: { }
我想了解为什么我的听众不能像我期望的那样工作,以及如何解决它


根据要求,这里还有一些代码。所有内容都来自一个
Place
表单,在该表单中,除了输入地名外,我还可以添加/删除/编辑到其他
Place
s的距离集合

// 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(),它受条令限制:

有关于preUpdate的信息,但相同的情况(循环)也适用于prePesist调用

9.6.6。预更新

PreUpdate是使用事件的最严格限制,因为它被调用 就在为内部实体调用update语句之前 EntityManager#flush()方法。 在这个>事件中,永远不允许对更新实体的关联进行更改,因为条令不能保证在刷新操作的这一点上正确处理引用完整性

这里描述了类似的情况


所以,您也可以采用类似的方法:创建自定义事件,创建自定义事件订阅服务器,您将在其中创建反向实体,并在控制器操作中调度该事件订阅服务器

首先,你不应该调用
$em->flush()
鉴于实体管理器可能会在原始实体被持久化的地方被刷新,因此在prePersist块中进行刷新是一种不好的形式。您能在原始实体被持久化的地方添加代码吗?@decape保存原始距离实体的代码不是我的。当持久化父位置实体(
cascade:{“persist”}
在关联上)时,它会自动发生,如我的编辑中所述。
// 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
                ]
            ]
        );
}