Symfony2表单集合不允许在更新时设置额外的实体


Symfony2 form collection not allowing additional entities to be set on update

我们遵循acmepizzabundance提供的示例。我们有一个DeliveryType表单,它包含一个日期字段和一个deliveryItems集合,如下所示:

$builder
    ->add('date', 'date', array(
            'widget' => 'single_text',
            'datepicker' => true
    ))
    ->add('deliveryItems', 'collection', array(
        'type'         => new DeliveryItemType(),
        'allow_add'    => true,
        'allow_delete' => true,
        'prototype'    => true,
        'by_reference' => false,
    ))
;

Delivery实体与DeliveryItem实体有关系:

/**
 * @var 'Doctrine'Common'Collections'ArrayCollection
 *
 * @ORM'OneToMany(targetEntity="DeliveryItem", mappedBy="delivery", cascade={"persist", "remove"}, orphanRemoval=true)
 * @Assert'NotBlank()
 */
private $deliveryItems;

当我们创建一个包含4个相关的DeliveryItems的Delivery时,一切似乎都可以正常工作。这是由于createAction中的以下代码:

...
if ($form->isValid()) {
    $em->persist($entity);
    $em->flush();
...

如果我们去编辑这个交付,我们会遇到一个问题,如果我们添加一个额外的DeliveryItem(现在总共有5个),那么一个就会被剔除。这是updateAction的控制器:

/**
 * Edits an existing Delivery entity.
 *
 * @Route("/{id}", name="delivery_update")
 * @Method("PUT")
 * @Template("AcmeAppBundle:Delivery:edit.html.twig")
 */
public function updateAction(Request $request, $id)
{
    $em = $this->getDoctrine()->getManager();
    $entity = $em->getRepository('AcmeAppBundle:Delivery')->find($id);
    if (!$entity) {
        return new RedirectResponse($this->generateUrl('delivery'));
    }
    $deleteForm = $this->createDeleteForm($id);
    $editForm = $this->createForm(new DeliveryType(), $entity, array(
        'action' => $this->generateUrl('delivery_update', array('id' => $entity->getId())),
        'method' => 'PUT',
    ));
    $form->add('submit', 'submit', array('label' => 'Update'));
    $editForm->handleRequest($request);
    if ($editForm->isValid()) {
        $em->getConnection()->beginTransaction(); // transaction
        try {
            $em->persist($entity);
            $em->flush();
            $em->getConnection()->commit(); // transaction
            return $this->redirect($this->generateUrl('delivery_show', array('id' => $id)));
        } catch (Exception $e) {
            $em->getConnection()->rollback(); // transaction
            $entity = new Delivery();
            return $this->redirect($this->generateUrl('delivery'));
        }
    }
    return array(
        'entity'      => $entity,
        'edit_form'   => $editForm->createView(),
        'delete_form' => $deleteForm->createView(),
    );
}

有趣的是,如果我们执行print_r($request),似乎只保留了第一个项,然后所有其他字段最终都会随着我们添加的项的增加而更新(在这个例子中,我们有4个,我们添加了第5个,它覆盖了第二个字段):

[request] => Symfony'Component'HttpFoundation'ParameterBag Object
        (
            [parameters:protected] => Array
                (
                    [_method] => PUT
                    [northerncam_appbundle_delivery] => Array
                        (
                            [date] => 2014-08-07
                            [poNumber] => 345
                            [deliveryItems] => Array
                                (
                                    [0] => Array
                                        (
                                            [stock] => 1
                                            [quantity] => 1
                                        )
                                    [1] => Array
                                        (
                                            [stock] => 1
                                            [quantity] => 5
                                        )
                                    [2] => Array
                                        (
                                            [stock] => 1
                                            [quantity] => 3
                                        )
                                    [3] => Array
                                        (
                                            [stock] => 1
                                            [quantity] => 4
                                        )
                                )
                            [submit] => 
                            [_token] => QpaKjcOP35kDBC1EAW8dDGpugtoxF4-MhL5rC6pYTVU
                        )
                )
        )

更奇怪的是,如果我们在原来的Delivery中添加额外的5个元素(4个),我们最终会覆盖原来的3个字段,然后额外创建第5个项。所以我们最终得到这样的结果:

[0] => Array
    (
        [stock] => 1
        [quantity] => 1
    )
[1] => Array
    (
        [stock] => 1
        [quantity] => 5
    )
[2] => Array
    (
        [stock] => 1
        [quantity] => 6
    )
[3] => Array
    (
        [stock] => 1
        [quantity] => 7
    )
[4] => Array
    (
        [stock] => 1
        [quantity] => 8
    )
[5] => Array
    (
        [stock] => 1
        [quantity] => 9
    )

我们使用的是Symfony v2.5.2和doctrine/orm v2.4.4

找到解决方案。我们的代码工作得很完美。问题是由phiamo/MopaBootstrapBundle (v3.0.0-beta 3)处理的实时表单生成,如问题#738所指出的。

因此,我们用@wolfwolker注释的options.initial_size = $this.parents(collection_id).find('.collection-items').children().length;和nrun php app/console assetic:dump替换了第108行,现在一切正常。