Symfony2 Form Events - Drop down lists

后端 未结 1 327
青春惊慌失措
青春惊慌失措 2021-02-03 13:01

In a Symfony2 website I\'m trying to make a form with 2 (or 3) dropdown lists with a dependency like Country > Region > City. And that city is a field of the element I\'m editin

相关标签:
1条回答
  • 2021-02-03 13:36

    I almost had it. If anybody else ever needs this here's what needs to be added to make this solution work perfectly when editing an existing item :

    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: since symfony 2.1, the POST_SET_DATA event is called before the children are added to the form, causing all the get('region') to raise an exception. The solution is to create this field in the POST_SET_DATA and not in the 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'
            )));
    

    Note that you need to add the $factory to the 'use' of the closure handling the event :

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

    Here is the whole form class:

    <?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 讨论(0)
提交回复
热议问题