Symfony 表单不保存具有多对多关系的实体 [英] Symfony form not saving entity with ManyToMany relation

查看:32
本文介绍了Symfony 表单不保存具有多对多关系的实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在通过多对多关系保存实体槽形式时遇到问题.

I have problem saving entity trough form with ManyToMany relations.

我无法保存关系mappedBy"端的字段.

I can not save fields that are on "mappedBy" side of relation.

下面的代码不会将任何内容保存到数据库中,也不会引发任何错误:

Code below is not saving anything to database and not trowing any errors:

// Entity/Pet
/**
 * @var \Doctrine\Common\Collections\Collection
 *
 * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Customer", mappedBy="pet", cascade={"persist"})
 */
private $customer;

/**
 * Set customer
 *
 * @param \AppBundle\Entity\Customer $customer
 * @return Pet
 */
public function setCustomer($customer)
{
    $this->customer = $customer;

    return $this;
}

// Entity/Customer
/**
 * @var Pet
 *
 * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Pet", inversedBy="customer", cascade={"persist"})
 * @ORM\JoinTable(name="customer_pet",
 *   joinColumns={
 *     @ORM\JoinColumn(name="customer_id", referencedColumnName="id")
 *   },
 *   inverseJoinColumns={
 *     @ORM\JoinColumn(name="pet_id", referencedColumnName="id")
 *   }
 * )
 */
private $pet;

// PetType.php
$builder->add('customer', 'entity', 
          array(
            'class' => 'AppBundle:Customer',
            'property' => 'firstname',
            'empty_value' => 'Choose owner',
            'multiple' => true
          ));

它正在以相反的方式工作.因此,如果我从 CustomerType 中保存某些内容,一切正常.

It is working the other way around. So if I am saving something from CustomerType everything works.

以下解决方案对我有用,但几天后我发现该解决方案存在问题.如果表单将使用已保存在数据库中的值提交,则 Symfony 将引发错误.为了防止出现这种情况,我必须检查给定的客户是否已分配给宠物.

Solution below worked for me but after couple days I found a problem with that solution. If form will be submitted with value that has been already saved in the database then Symfony will trow an error. To prevent that I had to check if given customer has been already assigned to the pet.

必须在函数开始时检查当前分配的客户,而不是在提交表单之后,因为出于某种原因,提交后 Pet() 对象包含提交的值,而不仅仅是数据库中存在的值.

Checking of currently assigned customers had to be done on the beginning of function and not after form submission because for some reason after submission Pet() object contains submitted values not only those present in the db.

所以一开始我将所有已经分配的客户放入数组

So on the beginning I've putted all already assigned customers in to the array

  $em = $this->getDoctrine()->getManager();
  $pet = $em->getRepository('AppBundle:Pet')->find($id);
  $petOriginalOwners = array();
  foreach ($pet->getCustomer() as $petCustomer) 
  {
      $petOriginalOwners[] = $petCustomer->getId();
  } 

提交表单后,我检查了提交的 ID 是否在数组中

And after form submission I've checked if submitted ID's are in the array

if ($form->isValid()) 
{
  foreach ($form['customer']->getData()->getValues() as $v) 
  {
    $customer = $em->getRepository('AppBundle:Customer')->find($v->getId());
    if ($customer && !in_array($v->getId(), $petOriginalOwners) )      
    {
      $customer->addPet($pet);
    }
  }
  $em->persist($pet);
  $em->flush();
  return $this->redirect($this->generateUrl('path'));
} 

推荐答案

在 Symfony2 中,具有 inversedBy 原则注释属性的实体是应该编辑由多对多关系创建的额外表的实体.这就是为什么当您创建客户时,它会在该额外表中插入相应的行,从而保存相应的宠物.

In Symfony2 the entity with the property with the inversedBy doctrine comment is the one that is supposed to EDIT THE EXTRA TABLE CREATED BY THE MANYTOMANY RELATION. That is why when you create a customer it inserts the corresponding rows in that extra table, saving the corresponding pets.

如果您希望以相反的方式发生相同的行为,我建议:

If you want the same behavior to happen the other way around, I recommend:

//PetController.php
public function createAction(Request $request) {
    $entity = new Pet();
    $form = $this->createCreateForm($entity);
    $form->submit($request);



    if ($form->isValid()) {
        $em = $this->getDoctrine()->getManager();
        foreach ($form['customer']->getData()->getValues() as $v) {
            $customer = $em->getRepository('AppBundle:Customer')->find($v->getId());
            if ($customer) {
                $customer->addPet($entity);
            }
        }
        $em->persist($entity);
        $em->flush();

        return $this->redirect($this->generateUrl('pet_show', array('id' => $entity->getId())));
    }

    return $this->render('AppBundle:pet:new.html.twig', array(
                'entity' => $entity,
                'form' => $form->createView(),
    ));
}

private function createCreateForm(Pet $entity) {
        $form = $this->createForm(new PetType(), $entity, array(
            'action' => $this->generateUrl('pet_create'),
            'method' => 'POST',
        ));

        return $form;
    }

这两个只是标准的Symfony2 CRUD在Pet实体对应的控制器中生成的动作.

These two are but standard Symfony2 CRUD-generated actions in the controller corresponding to Pet entity.

唯一的调整是在第一个操作中插入的 foreach 结构,这样您就可以向表单中选择的每个客户强行添加相同的宠物,从而获得所需的行为.

The only tweak is the foreach structure inserted in the first action, that way you forcibly add the same pet to each customer you select in the form, thus getting the desired behavior.

看,这很可能不是正确的方法或正确的方法,而是一种方法并且它有效.希望有帮助.

Look, it is highly probable THIS is not the RIGHT WAY, or the PROPER WAY, but is A WAY and it works. Hope it helps.

这篇关于Symfony 表单不保存具有多对多关系的实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆