2015-11-14 1 views
0

Comment imbriquer des classes de formulaire Symfony?

J'ai des problèmes déterminer la logique de la façon de créer des formes imbriquées pour les trois entités que j'ai: Films, Acteurs et Emplacements. J'ai généré mes entités Symfony (+ orm.xml) à partir de ma base de données en suivant les instructions des documents symfony here.

Mon but ultime serait d'être avoir une page où l'utilisateur peut effectuer l'une des actions suivantes:

  • Créer une nouvelle Films objet
  • Select Films dans un menu déroulant, et puis créez une nouvelle Acteurs objet à associer
  • Sélectionnez Films dans un menu déroulant, puis créez un w Emplacements objet à lui associer

(Acteurs et Emplacements ont tous deux un 1-à-plusieurs se joignent à la table Films)

Cependant, j'ai du mal avec le concept de formes imbriquées dans Symfony depuis longtemps et afin de "marcher avant que je puisse courir" j'essaye juste de mettre chacun des ci-dessus dans des itinéraires séparés avec des formes séparées:

  • /newfilm
  • /newactor
  • /newlocation

/New-film je peux obtenir de travailler sans problème. Cependant, avec l'un ou l'autre des deux autres, tout ce que j'essaie ne semble pas fonctionner. Ci-dessous est mon code, si quelqu'un peut expliquer la "théorie" des formes imbriquées dans Symfony pour éviter de continuer à frapper ce mur serait très apprécié ...!

Comme mon problème est le même pour les deux Acteur et l'emplacement, je ne mettre le code pour Acteurs (et Films) que je sais qu'il est tout à fait déjà beaucoup:

~~~ ~~ contrôleur ~~~~~

Il est cette seconde voie (/newactor) qui a la intégré/imbriquée 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(), 
     )); 
    } 
} 

~~~~~ ~~~~~ Films

Films.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'; 
    } 
} 

~~~~~ ~~~~~ acteurs

Acteurs.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'; 
    } 
} 

Mon message d'erreur actuel est:

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

500 Internal Server Error - ContextErrorException

J'ai lu des réponses qui disent à ajouter dans la fonction à mon Films.php:

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

Cependant, quand je fais ça, je puis obtenir l'erreur:

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

Autres idées possibles I » ve rencontré en ligne (mais malheureusement sans succès) sont:

  • Définition des formulaires que les services
  • Transformateurs de données
+0

pourquoi xml? yaml est beaucoup plus lisible –

+0

Merci d'avoir regardé :) J'ai essayé d'utiliser les 'meilleures pratiques' et j'ai lu cet article qui recommande d'utiliser XML afin que les paquets soient découplés pour être utilisés dans tous les projets .... sinon je suis d'accord avoir moins de mal de tête avec des annotations ...! http://blog.danielribeiro.org/yes-you-can-low-coupling-in-a-symfony-standard-edition-application/ – Bendy

+0

@Bendy cet article est obsolète. Vous devriez utiliser des annotations si vous voulez des «meilleures pratiques». http://symfony.com/doc/current/best_practices/business-logic.html#doctrine-mapping-information –

Répondre

0

Ajoutez 'choice_label' => 'film_title', à votre générateur de formulaire. Cela ou vous pouvez mettre en œuvre une fonction __toString() au sein de votre entité Film qui renvoie le titre du film.

Solution:

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

En outre, vous pouvez garder vos noms d'entités singulier (ex: film, pas de films, l'acteur non acteurs) car cela pourrait causer des problèmes inutiles lorsqu'ils traitent avec x à -De nombreuses relations d'entité.

+0

'choice_label' corrigé merci! Votre commentaire sur le fait de garder les noms d'entités singuliers - je m'étais aussi demandé à ce sujet. Cependant, la meilleure pratique des tables de base de données est d'avoir la table au pluriel pour ce qui est contenu? – Bendy

+1

vous pouvez donner un nom singulier à votre entité, mais vos tables portent un autre nom, par ex. @ORM \ Table (name = "products") et votre nom de classe doit être Product. –