2012-06-19 25 views
8

Na stronie Symfony2 próbuję utworzyć formularz z 2 (lub 3) listami rozwijanymi z zależnością jak Kraj> Region> Miasto. A to miasto jest polem elementu, który edytuję za pomocą formularza. Chodzi o to, aby wypełnić listy w zależności od wyboru.Symfony2 Form Events - Listy rozwijane

Mam następnie samouczek z wydarzeń formularza tutaj: http://aulatic.16mb.com/wordpress/2011/08/symfony2-dynamic-forms-an-event-driven-approach/ (który jest oparty na Webb-on-the-web com/p = 5?)

Problem mam: to wszystko działa, ale kiedy używam formularza do edycji elementu, miasto jest wybrane poprawnie (z DB), ale listy rozwijane Kraj i Region są wstępnie wypełnione i pozostawione na "wybierz wartość". Nie wiem, czy to miało działać z tutorialem takim jaki jest.

Pytanie: w jaki sposób mogę wybrać te listy? Próbuję dodać wydarzenie POST_SET_DATA, ale nie mogę znaleźć sposobu, aby wybrać wartość w polu formularza.

Oto klasa formularza: http://pastebin.com/PpWkHxC3 (należy zwrócić uwagę, że zamiast miasta jest to: Pole> Temat i temat jest polem lekcji edytowanej przez formularz).

Odpowiedz

10

Prawie go miałem. Jeśli ktokolwiek kiedykolwiek potrzebuje ten oto co należy dodać do tej pracy rozwiązanie doskonale podczas edycji istniejący przedmiot:

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: skoro symfony 2.1, wydarzenie POST_SET_DATA nazywa zanim dzieci są dodawane do formularza , powodując, że cały get ('region') podniósł wyjątek. Rozwiązaniem jest stworzenie tego pola w POST_SET_DATA a nie w 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' 
     ))); 

Pamiętaj, że musisz dodać $ fabrykę do „użytkowania” do obsługi zdarzeń zamknięcia:

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

Oto cała klasa forma:

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

mam pytanie do was Thomas, mam podobną zależność rozwijane w moim systemie. Moim przypadkiem jest to, że tworzę formularz i wiążę go z innymi wartościami (faktycznie żądanie), jak ustawić dane "regionu" i pracować dalej, kiedy tworzę formularz, a ja go nie wiążę i kiedy się wiążę dane z prośbą? – eagleoneraptor

+0

Przepraszam, naprawdę nie zrozumiałem tego pytania. :) (pamiętajcie, że powiązanie Forms zostało ulepszone w 2.1, więc po prostu wywołujecie bind(), a nie bindRequest() już więcej – Thomas

+0

Witaj Thomasie, walczę jak diabli, aby zrobić to, co zrobiłeś. Niestety tutorial z formularzem Wydarzenia już nie są, link jest martwy, możesz być miły i edytować swoją odpowiedź, żeby inni jak ja mogli iść naprzód, to byłoby świetnie :) Dziękuję z góry. Twoje zdrowie. Marc – Marc