Symfony,原则:在嵌入式表单集合上持久化多对一实体


Symfony & Doctrine: persisting a many to one entity on an embedded form collection

目前有点麻烦。我有2个实体:主和子,这是一个onetmany关系(一个主可以有许多子)我做了一个集合的形式嵌入在一起。我首先有一个搜索表单,其中用户可以通过其属性之一搜索Main,然后它将它们发送到一个页面,其中有一个包含搜索Main的表单,其属性在表单上列出,但被禁用,因此用户无法编辑它们,并且启用的字段来自用户需要输入提交的嵌入式Sub表单。

1)用户通过其属性搜索Main,即" PO " (PO号)
2)用户被重定向到一个页面,该页面显示了他/她搜索的行,并列出了(pono), (cano), (bano) -它被禁用,因此无法编辑3) Enabled字段为空,用户必须输入将提交到Sub实体的信息。

在我的主实体

 /**
 * @var Sub
 * @ORM'OneToMany(targetEntity="Sub", mappedBy="mainId")
 */
protected $sub;
public function __construct() {
    $this->sub = new ArrayCollection();
}

和我的子实体:

 /**
 * @var integer
 *
 * @ORM'Column(name="main_id", type="integer")
*/
protected $mainId;
 /**
 * @ORM'ManyToOne(targetEntity="Main", inversedBy="sub", cascade={"persist"})
 * @ORM'JoinColumn(name="main_id", referencedColumnName="id")
 */
protected $main;

In my Main form:

 public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('pono', 'text', array(
                'label' => 'PO: ',
                'disabled' => true
            ))
        ->add('cano','text', array(
                'label' => 'CA: ',
                'disabled' => true
            ))
        ->add('bano', 'text', array(
                'label' => 'BA: ',
                'disabled' => true
            ))
        ->add('sub', 'collection', array('type' => new SubType()));
}

在我的子窗体中:

 public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('qty','integer', array(
                'label' => 'Qty: '
            ))
        ->add('location','text', array(
                'label' => 'Location: '
            ))
        ->add('priority','text', array(
                'label' => 'Priority: '
            ));
}
在我的控制器
 public function submitItemAction(Request $request, $pono) {
    $em = $this->getDoctrine()->getManager();
    $entity = $em->getRepository('ItemBundle:Main')
        ->findOneByPono($pono);
    $cano = $entity->getCano();
    $bano = $entity->getBano();
    $main = new Main();
    $main->setPono($pono);
    $main->setCano($cano);
    $main->setBano($bano);
    $sub = new Sub();
    $sub->setMain($main);
    $main->getSub()->add($sub);
    $form = $this->createForm(new MainType(), $main, array(
            'method' => 'POST'
        ))
        ->add('submit','submit');
    $form->handleRequest($request);
    if($form->isValid()) {
        $em = $this->getDoctrine()->getManager();
        $em->persist($sub);
        $em->flush();
        return $this->redirect($this->generateUrl('success'));
    }

现在提交时,它同时提交了Main和Sub。它给了我一个重复的Main和新添加的Sub。我知道这是它应该做的,但我需要它只提交Sub。我试着用$mainid = $entity->getId();从Main检索id并将其放入$sub->setMainId($mainid),我不断得到main_id不能为空的错误信息。

人吗?编辑:小树枝模板:

{{ form_start(form) }}
            {{ form_label(form.pono) }}
            {{ form_widget(form.pono) }} <br>
            {{ form_label(form.cano) }}
            {{ form_widget(form.cano) }}<br>
            {{ form_label(form.bano) }}
            {{ form_widget(form.bano) }} <br>
            {% for sub in form.sub %}
                {{ form_label(sub.qty) }}
                {{ form_widget(sub.qty) }} <br>
                {{ form_label(sub.location) }}
                {{ form_widget(sub.location) }} <br>
                {{ form_label(sub.priority) }}
                {{ form_widget(sub.priority) }}<br>
            {% endfor %}
        {{ form_widget(form.submit) }}
        {{ form_end(form) }}

看了你的代码后,我认为有可能使它工作,有一些事情你需要修复。我将在几个步骤中编辑这个答案。在你开始修改之前,也要备份/提交你的代码。

1)在你的MAIN实体中(添加cascade持久化)

 /**
 * @var Sub
 * @ORM'OneToMany(targetEntity="Sub", mappedBy="main", cascade={"persist"}) 
 */
protected $sub;
2)子实体:

删除受保护的$mainId;它是annotation

从ManyToOne中删除cascade={"persist"}

3)看你的控制器动作

$sub = new Sub();
$sub->setMain($main);
$main->getSub()->add($sub);

注意setMain()方法。你不希望在控制器中这样做,而希望在实体中自动这样做。你也应该手动添加到集合中,但是要为它创建一个方法。所以你只有这个:

$sub = new Sub();
$main->addSub($sub);
4)在MAIN实体添加(您可能需要导入Sub):
public function addSub(Sub $sub) {
    $sub->setMain($this);
    $this->sub->add($sub);
    return $this;
}

您还应该添加其他方法,如removeSub(), removeSub(), getSub()。getSub()返回集合,而前两个返回$this。

5)控制器

不要保存Sub,而是保存Main。(原则级联持久性到子级)

$em->persist($main);

6)你需要添加'by_reference'选项的子集合在你的主表单类型。

->add('sub', 'collection', array('type' => new SubType(), 'by_reference' => false));

这将调用实际的addSub()方法,而不是直接调用add方法。

7)我不知道你为什么在下面新建一个Main实体。

$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('ItemBundle:Main')
    ->findOneByPono($pono);
$cano = $entity->getCano();
$bano = $entity->getBano();
$main = new Main();
$main->setPono($pono);
$main->setCano($cano);
$main->setBano($bano); 

尝试更改为:

$em = $this->getDoctrine()->getManager();
$main = $em->getRepository('ItemBundle:Main')
    ->findOneByPono($pono);

您可能应该将Pono定义为唯一的