2012-06-19 41 views
8

Trong trang web Symfony2 Tôi đang cố gắng tạo biểu mẫu có 2 (hoặc 3) danh sách thả xuống với sự phụ thuộc như Quốc gia> Vùng> Thành phố. Và thành phố đó là một lĩnh vực của phần tử tôi đang chỉnh sửa với biểu mẫu. Ý tưởng là để điền vào các danh sách tùy thuộc vào lựa chọn.Sự kiện biểu mẫu Symfony2 - Danh sách thả xuống

Tôi đã theo các hướng dẫn với hình thức sự kiện ở đây: http://aulatic.16mb.com/wordpress/2011/08/symfony2-dynamic-forms-an-event-driven-approach/ (mà là dựa trên webb-on-the-web .com/p = 5?)

Vấn đề tôi có: tất cả các công trình nhưng khi tôi sử dụng biểu mẫu để chỉnh sửa phần tử, thành phố được chọn chính xác (từ DB) nhưng danh sách thả xuống Quốc gia và Vùng được điền sẵn và để lại trên 'chọn giá trị'. Tôi không biết nếu nó được cho là làm việc với hướng dẫn như nó được.

Câu hỏi: làm cách nào để tôi có thể chọn các danh sách này? Tôi đang cố gắng thêm một sự kiện POST_SET_DATA nhưng tôi không thể tìm thấy một cách để chọn giá trị trong trường biểu mẫu.

Đây là loại biểu mẫu: http://pastebin.com/PpWkHxC3 (lưu ý rằng thay vì thành phố đó là: Trường> Chủ đề và chủ đề là trường của Bài học mà biểu mẫu chỉnh sửa).

Trả lời

10

Tôi gần như đã có nó. Nếu bất cứ ai bao giờ cần ở đây là những gì cần phải được thêm vào làm cho công việc giải pháp này một cách hoàn hảo khi chỉnh sửa một mục hiện có:

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

Chỉnh sửa: kể từ symfony 2.1, sự kiện POST_SET_DATA được gọi trước khi trẻ em được thêm vào biểu mẫu , gây ra tất cả các get ('khu vực') để nâng cao một ngoại lệ. Giải pháp là tạo ra lĩnh vực này trong POST_SET_DATA và không nằm trong 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' 
     ))); 

Lưu ý rằng bạn cần phải thêm nhà máy $ đến 'sử dụng' về việc xử lý sự kiện đóng cửa:

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

Dưới đây là toàn bộ lớp mẫu:

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

tôi có một câu hỏi cho bạn Thomas, tôi có một sự phụ thuộc thả xuống tương tự như trong hệ thống của tôi. Trường hợp của tôi là tôi tạo biểu mẫu và tôi ràng buộc nó với các giá trị khác (yêu cầu thực sự), làm cách nào tôi có thể đặt dữ liệu 'vùng' và tiếp tục làm việc cả khi tôi tạo biểu mẫu và tôi không ràng buộc nó và khi tôi ràng buộc dữ liệu với yêu cầu? – eagleoneraptor

+0

Xin lỗi, tôi thực sự không hiểu câu hỏi đó. :) (nhớ rằng ràng buộc của các hình thức đã được cải thiện trong 2.1, vì vậy bạn chỉ cần gọi bind() và không bindRequest() nữa – Thomas

+0

Xin chào thomas.Tôi đang đấu tranh như địa ngục để làm những gì bạn đã làm. các sự kiện không còn nữa. Liên kết đã chết Bạn có thể là con trai và chỉnh sửa câu trả lời của bạn để những người khác như tôi có thể tiến lên phía trước. Điều đó thực sự tuyệt vời :) Cảm ơn bạn trước. Chúc mừng. Marc – Marc

Các vấn đề liên quan