2012-06-19 12 views
8

In un sito Web di Symfony2 sto provando a creare un modulo con 2 (o 3) elenchi a discesa con una dipendenza come Paese> Regione> Città. E quella città è un campo dell'elemento che sto modificando con il modulo. L'idea è di riempire gli elenchi a seconda delle selezioni.Symfony2 Eventi modulo - Elenco a discesa

ho seguito il tutorial con eventi form che trovi qui: http://aulatic.16mb.com/wordpress/2011/08/symfony2-dynamic-forms-an-event-driven-approach/ (che si basa su Webb-on-the-web .com/p = 5?)

Il problema che ho: funziona il tutto, ma quando uso il modulo per modificare l'elemento, la città viene selezionata correttamente (dal DB) ma gli elenchi a discesa Paese e Regione sono precompilati e lasciati su 'seleziona un valore'. Non so se avrebbe dovuto funzionare con il tutorial così com'è.

La domanda: come posso rendere queste liste selezionate? Sto tentando di aggiungere un evento POST_SET_DATA ma non riesco a trovare un modo per selezionare il valore nel campo modulo.

Ecco la classe modulo: http://pastebin.com/PpWkHxC3 (nota che invece di città è: Campo> Argomento e argomento è un campo di una lezione che il modulo modifica).

risposta

10

L'ho quasi avuto. Se chiunque altro mai ha bisogno di questo ecco cosa deve essere aggiunto per fare questo lavoro soluzione perfettamente quando si modifica un elemento esistente:

class ItemDetailForm extends AbstractType 
{ 
    ... 
     $builder->addEventListener(FormEvents::POST_SET_DATA, function (DataEvent $event) use ($refreshTopic) { 
      $data = $event->getData(); 
      $form = $event->getForm(); 
      if (null === $data) { 
       return; 
      } 

      $form->get('region')->setData($data->getCity()->getRegion()); 
     }); 
} 

Edit: dal symfony 2.1, l'evento POST_SET_DATA viene chiamato prima che i bambini vengono aggiunti al modulo , facendo sì che tutta la get ('region') generi un'eccezione. La soluzione è quella di creare questo campo nel POST_SET_DATA e non nel buildForm():

 /** @var FormFactory $factory */ 
     $form->add($factory->createNamed('region', 'entity', null, array(
      'class'=>'AcmeBundle:Region', 
      'property_path'=>false, 
      'empty_value'=>'Choose a value', 
      'required'=>true, 
      'label'=>'Region' 
     ))); 

Si noti che è necessario aggiungere il $ fabbrica per l' 'uso' della gestione dell'evento di chiusura:

$builder->addEventListener(FormEvents::POST_SET_DATA, function (DataEvent $event) use ($refreshTopic, $factory) { 

Ecco tutta la classe form:

<?php 
namespace AAA\CoreBundle\Form; 

use Symfony\Component\Form\AbstractType; 
use Symfony\Component\Form\FormBuilderInterface; 
use Symfony\Component\Form\FormFactory; 
use Symfony\Component\Form\FormEvents; 
use Symfony\Component\Form\FormEvent; 
use Symfony\Component\Form\Form; 
use Symfony\Component\OptionsResolver\OptionsResolverInterface; 
use Doctrine\ORM\EntityRepository; 
use AAA\CoreBundle\Entity\ClassYear; 
use AAA\CoreBundle\Entity\Field; 
use AAA\CoreBundle\Entity\Lesson; 
use AAA\CoreBundle\Form\LessonContentForm; 

class LessonDetailForm extends AbstractType 
{ 
    public $country; 
    function __construct($country=null) { 
     // Get country for classyear dropdown list 
     $this->country = $country; 
    } 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $factory = $builder->getFormFactory(); 

     $builder->add('name', null, array('label'=>'Titre de la leçon')); 
     $builder->add('description', 'textarea', array('label'=>'Description (définition conceptuelle) Qu\'est-ce que c\'est ? Et à quoi ça sert ? (importance, utilité)')); 
     $builder->add('text', 'textarea', array('label'=>'Leçon', 'required'=>false)); // Can't set 'required' on textareas used by TinyMCE 
     $builder->add('reperes', 'textarea', array('label'=>'Repères (détectionel) - Quels sont les éléments qui me permettent de repérer que je dois penser à ce concept ?', 'required'=>false)); 
     $builder->add('other_topic', null, array(
      'required' => false, 
      'mapped'  => false 
     )); 

     $refreshField = function ($form, $classyear) use ($factory) { 
      /** @var FormFactory $factory */ 
      /** @var Form $form */ 
      $form->add($factory->createNamed('field','entity',null, array(
       'class'   => 'AAA\CoreBundle\Entity\Field', 
       'mapped'  => false, 
       'label'   => 'Matière', 
       'empty_value' => 'Sélectionne une valeur', 
       'empty_data' => null, 
       'required'  => false, 
       'query_builder' => function (EntityRepository $repository) use ($classyear) { 
        $qb = $repository->createQueryBuilder('field') 
         ->innerJoin('field.classyear', 'classyear'); 

        if($classyear instanceof ClassYear) { 
         $qb = $qb->where('field.classyear = :classyear') 
          ->setParameter('classyear', $classyear); 
        } elseif(is_numeric($classyear)) { 
         $qb = $qb->where('classyear.id = :classyear_id') 
          ->setParameter('classyear_id', $classyear); 
        } else { 
         $qb = $qb->where('0 = 1'); 
        } 

        return $qb; 
       } 
      ))); 
     }; 
     $refreshTopic = function ($form, $field) use ($factory) { 
      /** @var FormFactory $factory */ 
      /** @var Form $form */ 
      $form->add($factory->createNamed('topic','entity',null, array(
       'class'   => 'AAA\CoreBundle\Entity\Topic', 
       'property'  => 'name', 
       'label'   => 'Sujet', 
       'empty_value' => 'Sélectionne une valeur', 
       'empty_data' => null, 
       'required'  => false, 
       'query_builder' => function (EntityRepository $repository) use ($field) { 
        $qb = $repository->createQueryBuilder('topic') 
         ->innerJoin('topic.field', 'field'); 

        if($field instanceof Field) { 
         $qb = $qb->where('topic.field = :field') 
          ->setParameter('field', $field); 
        } elseif(is_numeric($field)) { 
         $qb = $qb->where('field.id = :field_id') 
          ->setParameter('field_id', $field); 
        } else { 
         $qb = $qb->where('0 = 1'); 
        } 

        return $qb; 
       } 
      ))); 
     }; 

     // Populate ddl to show form 
     $country = $this->country; 
     $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($refreshTopic, $refreshField, $factory, $country) { 
      /** @var Lesson $data */ 
      $data = $event->getData(); 
      $form = $event->getForm(); 

      // Test if null because this event is called 2 times, only the second time with the actual Lesson object (which has null values in the creation case) 
      if($data != null) 
       // In case of creation 
       if($data->getId()==null) { 
        // Creates empty fields 
        $refreshTopic($form, null); 
        $refreshField($form, null); 
       } 
       // In case of edition 
       else { 
        if ($data->getTopic() != null) { 
         $refreshTopic($form, $data->getTopic()->getField()); 
         if ($data->getTopic()->getField() != null) { 
          $refreshField($form, $data->getTopic()->getField()->getClassYear()); 
         } 
        } 
        else { 
         $refreshField($form, null); 
         $refreshTopic($form, null); 
        } 
       } 

      /** @var FormFactory $factory */ 
      $form->add($factory->createNamed('classyear', 'entity', null, array(
       'class'   => 'AAACoreBundle:ClassYear', 
       'property'  => 'name'.$country, 
       'mapped'  => false, 
       'label'   => 'Année', 
       'empty_value' => 'Sélectionne une valeur', 
       'empty_data' => null, 
       'required'  => false, 
       'query_builder' => function (EntityRepository $repository) { 
        return $repository->createQueryBuilder('classyear') 
         ->orderBy('classyear.sort'); 
       } 
      ))); 
     }); 
     // Populate ddl when form was posted 
     $builder->addEventListener(FormEvents::PRE_BIND, function (FormEvent $event) use ($refreshTopic, $refreshField) { 
      $form = $event->getForm(); 
      $data = $event->getData(); 

      if(array_key_exists('classyear', $data)) { 
       $refreshField($form, $data['classyear']); 
      } 
      if(array_key_exists('field', $data)) { 
       $refreshTopic($form, $data['field']); 
      } 
     }); 

     // Select value in ddl when editing 
     $builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) use ($refreshTopic) { 
      /** @var Lesson $data */ 
      $data = $event->getData(); 
      $form = $event->getForm(); 
      if (null === $data || null === $data->getId()) { 
       return; 
      } 

      if ($data->getTopic() != null) { 
       $form->get('field')->setData($data->getTopic()->getField()); 
       if ($data->getTopic()->getField() != null) { 
        $form->get('classyear')->setData($data->getTopic()->getField()->getClassYear()); 
       } 
      } 
     }); 
    } 
    public function getName() 
    { 
     return 'LessonDetailForm'; 
    } 
    /** @param OptionsResolverInterface $resolver */ 
    public function setDefaultOptions(OptionsResolverInterface $resolver) 
    { 
     $resolver->setDefaults(array(
      'data_class' => 'AAA\CoreBundle\Entity\Lesson' 
     )); 
    } 
} 

?> 
+0

ho una domanda per te Thomas, ho una simile discesa dipendenza nel mio sistema. Il mio caso è che creo il modulo e lo lego ad altri valori (la richiesta in effetti), come posso impostare i dati 'region' e continuare a lavorare sia quando creo il modulo che non lo lego e quando lego i dati con la richiesta? – eagleoneraptor

+0

Scusa, non ho davvero capito questa domanda. :) (ricorda che il binding di Forms è stato migliorato in 2.1, quindi chiami più bind() e non bindRequest() – Thomas

+0

Ciao thomas. Sto lottando come l'inferno per fare quello che hai fatto. gli eventi non sono più lì. Il link è morto. Potresti essere gentile e modificare la tua risposta in modo che altri come me possano andare avanti. Sarebbe davvero fantastico :) Grazie in anticipo. Saluti. Marc – Marc

Problemi correlati