2013-04-14 13 views
5

Pracuję z Symfony2 Forms i FOSRestBundle.Jak poprawnie pracować z Forms, pakietem Rest FOS i wieloma lub wieloma relacjami w Symfony2

Próbuję zapisać w bazie danych, podmiot o wielu do wielu relacji.

utworzyć formularz z polem zbiórki (http://symfony.com/doc/master/cookbook/form/form_collections.html) tak:

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 
     )); 
    } 
} 

Zbiór obiektów typu „inne” są przechowywane w bazie danych. I nie chcę przechowywać więcej obiektów tego typu, tylko czytać i odnosić je do głównego obiektu.

Kiedy przetwarzać formularza używam tej funkcji:

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); 
} 

Kod json poślę od klienta backbone.js brzmi:

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

podmioty:

  • Menem

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> 

jednostki:

<?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; 
    } 
} 
  • Inne

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> 

jednostki:

<?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; 
    } 
} 

Gdy utrzymuję obiekt typu "main" w bazie danych, kolekcja nie jest uwzględniana w tabeli wielu do wielu relacji. Muszę zapisać kolekcję ręcznie, gdy utrwalam obiekt "główny".

Szukam sposobu, aby zapisać kolekcję obiektów automatycznie tak proste, jak to możliwe.

+0

Musisz użyć 'cascade = {" persist "}'. – cheesemacfly

+1

Otrzymuję ten błąd: "ten formularz nie powinien zawierać dodatkowych pól" – escrichov

+0

Czy możesz umieścić swój kod do formularza? – cheesemacfly

Odpowiedz

4

Miałem podobny problem, myślę, że wystarczy skonfigurować formularz, aby spodziewać się dodatkowych elementów w swojej kolekcji.

W ten sposób błąd "ten formularz nie zawiera dodatkowych pól" nie wzrośnie, ponieważ formularz będzie oczekiwał tych dodatkowych pól. Tak więc kod powinien być

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