2015-11-14 55 views
0

如何嵌套Symfony表單類?

我有問題搞清楚如何創建三個實體我有嵌套形式邏輯:電影演員位置。我按照symfony文檔here中的說明從我的數據庫中生成了我的Symfony實體(+ orm.xml)。

我的最終目標將是有一個頁面,用戶可以執行下列操作:

  • 創建從下拉菜單中選擇一個新的電影對象
  • 選擇電影,和然後創建一個新的演員對象關聯到它
  • 選擇從下拉菜單中選擇,然後創建一個ne w^位置對象關聯到它

演員位置都有一個1對多的加盟與Films表)

然而,我一直在掙扎在Symfony中嵌套表單的概念已經很長時間了,爲了「在我可以運行之前走路」,我只是試圖將以上每個單獨的路徑放在不同的路徑中:

  • /newfilm
  • /newactor
  • /newlocation

/New-film我可以得到的工作沒有問題。但是,對於另外兩個,我嘗試的任何東西似乎都不起作用。下面是我的代碼,如果有人能夠在Symfony中解釋嵌套表單的「理論」,以避免繼續擊中這個牆將非常讚賞......!

由於我的問題是兩個演員和位置相同,我只是將代碼爲演員(和電影),因爲我意識到這是相當多的已:

~~~ ~~控制器~~~~~

正是這個第二路線(/newactor),其具有嵌入/嵌套formType:

class DefaultController extends FOSRestController 
{ 
    /** 
    * @Route("/newfilm", name="new_film") 
    */ 
    public function newFilmAction(Request $request) 
    { 
     $film = new Films(); 
     $form = $this->CreateFormBuilder($film) 
      ->add('film_title','text',array('label'=>'Film title')) 
      ->add('Save','submit',array('label'=>'Add new film')) 
      ->getForm(); 
     $form->handleRequest($request); 

     if ($form->isValid()) { 
      $em = $this->getDoctrine()->getManager(); 
      $em->persist($film); 
      $em->flush(); 
      return $this->redirectToRoute('success_addFilm'); 
     } 

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


    /** 
    * @Route("/newactor", name="new_actor") 
    */ 
    public function newActorAction(Request $request) 
    { 
     $actor = new Actors(); 
     $form = $this->createForm(new ActorType(), $actor); 
     $form->handleRequest($request); 

     if ($form->isValid()) { 
      $em = $this->getDoctrine()->getManager(); 
      $em->persist($actor); 
      $em->flush(); 
      return $this->redirectToRoute('success_addActor'); 
     } 

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

~~~~~薄膜~~~~~

電影。PHP

/** 
* Films 
*/ 
class Films 
{ 
    /** 
    * @var integer 
    */ 
    private $filmid; 

    /** 
    * @var string 
    */ 
    private $film_title; 

    /** 
    * @var \AppBundle\Entity\Actors 
    */ 
    private $actor; 



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

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

    /** 
    * Set film_title 
    * @param string $film_title 
    * @return Films 
    */ 
    public function setFilm_title($film_title) 
    { 
     $this->film_title = $film_title; 
     return $this; 
    } 

    /** 
    * Set actor 
    * 
    * @param \AppBundle\Entity\Actors $actor 
    * 
    * @return Actors 
    */ 
    public function setActor(\AppBundle\Entity\Actors $actor = null) 
    { 
     $this->actor = $actor; 

     return $this; 
    } 

    /** 
    * Get actor 
    * 
    * @return \AppBundle\Entity\Actors 
    */ 
    public function getActor() 
    { 
     return $this->actor; 
    } 
} 

Films.orm.xml

<?xml version="1.0" encoding="utf-8"?> 
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> 
    <entity name="AppBundle\Entity\Films" table="Films"> 
    <indexes> 
     <index name="fk_Films_actors1_idx" columns="actor_id"/> 
    </indexes> 
    <id name="filmid" type="integer" column="filmid"> 
     <generator strategy="IDENTITY"/> 
    </id> 
    <field name="film_title" type="text" column="film_title" length="65535" nullable="false"> 
     <options> 
     <option name="fixed"/> 
     </options> 
    </field> 
    <many-to-one field="actor" target-entity="Actors" fetch="LAZY"> 
     <join-columns> 
     <join-column name="actor_id" referenced-column-name="actorid"/> 
     </join-columns> 
    </many-to-one> 
    </entity> 
</doctrine-mapping> 

FilmType.php

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

    public function configureOptions(OptionsResolver $resolver) 
    { 
     $resolver->setDefaults(array(
      'data_class'=>'AppBundle\Entity\Films' 
     )); 
    } 

    public function getName() 
    { 
     return 'film'; 
    } 
} 

~~~~~演員~~~~~

Actors.php

/** 
* Entries 
*/ 
class Entries 
{ 
    /** 
    * @var integer 
    */ 
    private $actorid; 


    /** 
    * @var string 
    */ 
    private $actorName; 




    /** 
    * Set actorid 
    * 
    * @param integer $actorid 
    * 
    * @return Actors 
    */ 
    public function setActorid($actorid) 
    { 
     $this->actorid = $actorid; 

     return $this; 
    } 

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

    /** 
    * Set actorName 
    * 
    * @param string $actorName 
    * 
    * @return Actors 
    */ 
    public function setActorName($actorName) 
    { 
     $this->actorName = $actorName; 

     return $this; 
    } 

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

Actors.orm.xml

<?xml version="1.0" encoding="utf-8"?> 
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> 
    <entity name="AppBundle\Entity\Actors" table="Actors"> 
    <id name="actorid" type="integer" column="actorid"> 
     <generator strategy="IDENTITY"/> 
    </id> 
    <field name="actorName" type="text" column="actorName" length="65535" nullable="true"> 
     <options> 
     <option name="fixed"/> 
     </options> 
    </field> 
    </entity> 
</doctrine-mapping> 

ActorType

class ActorType extends AbstractType 
{ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $builder 
      ->add('actorName') 
      ->add('film','entity',array(
       'class'=>'AppBundle:Films', 
       'query_builder'=>function(EntityRepository $er) { 
        return $er->createQueryBuilder('f') 
         ->orderBy('f.film_title','ASC'); 
       } 
      )); 
    } 

    public function configureOptions(OptionsResolver $resolver) 
    { 
     $resolver->setDefaults(array(
      'data_class'=>'\AppBundle\Entity\Actors' 
     )); 
    } 

    public function getName() 
    { 
     return 'actor'; 
    } 
} 

我現在的錯誤消息是:

Catchable Fatal Error: Object of class AppBundle\Entity\Films could not be converted to string

500 Internal Server Error - ContextErrorException

我看過的答案是說在功能添加到我的Films.php

public function __toString() { 
    return $this->name; 
} 

然而,當我這樣做,然後我得到的錯誤:

Error: Method AppBundle\Entity\Films::__toString() must not throw an exception

其他可能的想法,我」已經遇到在線(可惜沒有成功)是:

  • 設置形式服務
  • 數據轉換器
+0

爲什麼選擇xml? yaml更可讀 –

+0

謝謝:)我一直在試圖使用'最佳實踐',並閱讀這篇文章,其中建議使用XML,以便捆綁解耦以跨項目使用....否則我同意我會用註釋減少頭痛......! http://blog.danielribeiro.org/yes-you-can-have-low-coupling-in-a-symfony-standard-edition-application/ – Bendy

+0

@Bendy那篇文章已經過時了。如果你想'最佳實踐',你應該使用註釋。 http://symfony.com/doc/current/best_practices/business-logic.html#doctrine-mapping-information –

回答

0

'choice_label' => 'film_title',添加到您的表單構建器中。或者你可以在你的Film實體中實現一個__toString()函數來返回電影標題。

解決方案:

$builder 
    ->add('actorName') 
    ->add('film','entity',array(
     'class'=>'AppBundle:Films', 
     'choice_label' => 'film_title', 
     'query_builder'=>function(EntityRepository $er) { 
      return $er->createQueryBuilder('f') 
       ->orderBy('f.film_title','ASC'); 
     } 
    )); 

此外,您可能想保持你的實體名稱奇異(如:電影,而不是電影,演員不是演員)作爲X-到時,這可能會導致不必要的問題很多實體關係。

+0

'choice_label'修復了它謝謝!您關於保持實體名稱單數的評論 - 我也想知道這一點。但是,數據庫表的「最佳實踐」是讓表中包含的內容以複數形式命名? – Bendy

+1

你可以給你的實體一個單獨的名字,但你的表另一個名字,例如@ORM \ Table(name =「products」)和你的類名應該是Product。 –