如何正确使用Forms,FOS Rest Bundle以及Symfony2中的多对多关系

时间:2013-04-14 21:11:46

标签: forms symfony backbone.js fosrestbundle

我正在使用Symfony2 Forms和FOSRestBundle。

我正在尝试保存在数据库中,这是一个有多对多关系的实体。

我创建一个带有集合字段(http://symfony.com/doc/master/cookbook/form/form_collections.html)的表单,如下所示:

class MainType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('name');
        $builder->add('description');

        $builder->add('others', 'collection', array(
            'type' => new OtherType()
        ));
    }

    public function getName()
    {
        return '';
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Acme\SearchBundle\Entity\Main',
            'csrf_protection' => false
        ));
    }
}

class OtherType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('id');
    }

    public function getName()
    {
        return '';
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Acme\SearchBundle\Entity\Other',
            'csrf_protection' => false
        ));
    }
}

“其他”类型的对象集合存储在数据库中。而且我不想存储更多该类型的对象,只读取它们并将它们与主对象相关联。

当我处理表单时,我使用此函数:

private function processForm(Main $main, $new = false)
{

    $new = true;

    $statusCode = $new ? 201 : 204;

    $form = $this->createForm(new MainType(), $main);
    $form->bind($this->getRequest());


    if ($form->isValid()) {

        $mainValidated = $form->getData();

        // I should store the collection of objects of type other
        // in the database

        $em = $this->getDoctrine()->getEntityManager();
        $em->persist($mainValidated);
        $em->flush();

        return $this->view($new ? $mainValidated : null, $statusCode);
    }

    return $this->view($form, 400);
}

我从客户端Backbone.js发送的代码json是:

{"others":[{"id":1}, {"id":2}]}

实体:

  • 主要

XML:

  <entity name="Acme\SearchBundle\Entity\Main" table="main">
    <id name="id type="integer" column="id">
      <generator strategy="IDENTITY"/>
    </id>
    <field name="name" type="integer" column="name" nullable="true"/>
    <field name="description" type="integer" column="description" nullable="true"/>

    <many-to-many field="others" target-entity="Other" inversed-by="mains">
      <cascade>
         <cascade-persist/>
      </cascade>
      <join-table name="main_has_other">
        <join-columns>
          <join-column name="main" referenced-column-name="id"/>
        </join-columns>
        <inverse-join-columns>
          <join-column name="other" referenced-column-name="id"/>
        </inverse-join-columns>
      </join-table>
    </many-to-many>

  </entity>

实体:

<?php

namespace Acme\SearchBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

use JMS\Serializer\Annotation\Type;

use JMS\Serializer\Annotation\Groups;
use JMS\Serializer\Annotation\Expose;

class Main
{   
    /**
     * @Type("integer")
     * @Groups({"admin"})
     * 
     * @var integer
     * 
     */
    private $id;

    /**
     * 
     * @Type("string")
     * @Groups({"manage"})
     * 
     * @var string
     */
    private $name;


    /**
     * @Type("string")
     * @Groups({"manage"})
     * 
     * @var string
     */
    private $description;


    /**
     * @Type("ArrayCollection<Acme\SearchBundle\Entity\Other>")
     * @Groups({"manage"})
     * 
     * @var \Doctrine\Common\Collections\Collection
     */
    private $others;


    /**
     * Constructor
     */
    public function __construct()
    {
        $this->others = new \Doctrine\Common\Collections\ArrayCollection();
    }



    /**
     * Set name
     *
     * @param string $name
     * @return Main
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string 
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set description
     *
     * @param string $description
     * @return Main
     */
    public function setDescription($description)
    {
        $this->description = $description;

        return $this;
    }

    /**
     * Get description
     *
     * @return string
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Add others
     *
     * @param \Acme\SearchBundle\Entity\Other $other
     * @return Main
     */
    public function addOthers(\Acme\SearchBundle\Entity\Other $other)
    {
        $this->others[] = $other;

        return $this;
    }

    /**
     * Remove others
     *
     * @param \Acme\SearchBundle\Entity\Other $other
     */
    public function removeOthers(\Acme\SearchBundle\Entity\Other $other)
    {
        $this->others->removeElement($other);
    }

    /**
     * Get others
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getOthers()
    {
        return $this->others;
    }
}
  • 其他

XML:

<entity name="Acme\SearchBundle\Entity\Other" table="other">
  <id name="id" type="integer" column="id">
    <generator strategy="IDENTITY"/>
  </id>
  <field name="name" type="string" column="name" length="255" nullable="true"/>
  <field name="description" type="string" column="name" length="255" nullable="true"/>
  <many-to-many field="mains" target-entity="Main" mapped-by="others">
    <cascade>
        <cascade-persist/>
    </cascade>
  </many-to-many>
</entity>

实体:

<?php

namespace Acme\SearchBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

use JMS\Serializer\Annotation\Type;
use JMS\Serializer\Annotation\Groups;

class Other
{

   /**
     * @Type("integer")
     * @Groups({"manage"})
     * 
     * @var integer
     */
    private $id;

    /**
     * @Type("string")
     * @Groups({"manage"})
     * 
     * @var string
     */
    private $name;

    /**
     * @Type("string")
     * @Groups({"manage"})
     * 
     * @var string
     */
    private $description;

    /**
     * @Type("Acme\SearchBundle\Entity\Main")
     * @Groups({"admin"})
     * 
     * @var \Doctrine\Common\Collections\Collection
     */
    private $mains;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->mains = new \Doctrine\Common\Collections\ArrayCollection();
    }        

    /**
     * Set name
     *
     * @param string $name
     * @return Other
     */
    public function setName($name)
    {
        $this->name = $name
    }

    /**
     * Get name
     *
     * @return string 
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set description
     *
     * @param string $description
     * @return Other
     */
    public function setDescription($description)
    {
        $this->description = $description;

        return $this;
    }

    /**
     * Get description
     *
     * @return string 
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set id
     *
     * @param integer $id
     * @return Other
     */
    public function setId($id)
    {
        $this->id = $id;

        return $this;
    }

    /**
     * Add main
     *
     * @param \Acme\SearchBundle\Entity\Main $main
     * @return Other
     */
    public function addMains(\Acme\SearchBundle\Entity\Main $main)
    {
        $this->mains[] = $main;

        return $this;
    }

    /**
     * Remove main
     *
     * @param \Acme\SearchBundle\Entity\Main $main
     */
    public function removeMains(\AcmeSearchBundle\Entity\Main $main)
    {
        $this->mains->removeElement($main);
    }

    /**
     * Get mains
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getMains()
    {
        return $this->mains;
    }
}

当我在数据库中持久存在“main”类型的对象时,该集合不会持久存在于多对多关系的表中。我必须在持久保存“主”对象时手动保存集合。

我正在寻找一种尽可能简单地自动保存对象集合的方法。

1 个答案:

答案 0 :(得分:4)

我有一个类似的问题,我认为您只需要配置表单以期待您的收藏中的额外项目。

'allow_add' => true

这种方式“此表单不应包含额外的字段”错误不会上升,因为表单将期望这些额外的字段。所以,代码应该是

    $builder->add('others', 'collection', array(
        'type' => new OtherType(),
        'allow_add' => true
    ));