2013-04-14 39 views
5

我正在使用Symfony2 Forms和FOSRestBundle。如何正確使用Forms,FOS Rest Bundle和Symfony2中的多對多關係

我試圖在數據庫中保存一個具有多對多關係的實體。

我創建了一個表格集合場(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); 
} 

代碼JSON我從客戶端發送Backbone.js的是:

{"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」類型的對象時,該集合並沒有存在於多對多關係表中。保留「主」對象時,我必須手動保存集合。

我正在尋找一種方法來儘可能簡單地保存對象集合。

+0

您需要使用'cascade = {「persist」}'。 – cheesemacfly

+1

我得到這個錯誤:「這個表單不應該包含額外的字段」 – escrichov

+0

你可以發佈你的表單的代碼? – cheesemacfly

回答

4

我有一個類似的問題,我想你只需要配置表單以期望收集額外的項目。

'allow_add' => true 

這樣「這個表單不應該包含額外的字段」錯誤不會上升,因爲表單會期待這些額外的字段。所以,代碼應該是

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