Oleg
Oleg

Reputation: 2821

Add dynamically option to all fields of some type of symfony form

I have many fields of type subclass of EntityType, something like this:

    $builder->add('managers', SubclassEntityType::class, [
        'class' => 'User',
        'choice_label' => 'Managers',
        'required' => false,
        'query_builder' => function (UserRepository $er) {
            return $er->getManagersQueryBuilder();
        },
        'multiple' => true,
    ]);
    $builder->add('types', SubclassEntityType::class, [
        'class' => 'Type',
        'choice_label' => 'Types',
        'required' => false,
        'query_builder' => function (TypesRepository $er) {
            return $er->getManagersQueryBuilder();
        },
        'multiple' => true,
    ]);

Could I dynamically add option (option of fields in select, not option of form) to all fields of the same type like this (Empty) => 'empty? I don't want to customize it for each field. I need this option to filter allow to add to field null values, for examples, find entities to which not manager is assigned. Would it be easier to solve this if it were subclass of ChoiceType?

I tried to subclass ChoiceType и add empty option in buildView, but in this case validation fails as well. Does anybody know how to add option and make validation work? It looks like adding option in buildView doesn't solve the problem.

Upvotes: 0

Views: 285

Answers (1)

iraouf
iraouf

Reputation: 173

if isn't multiple ,You can achieve that by defining tow options placeholder and empty_data

class YourType extends AbstractType {
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        
        $builder->add('managers', SubclassEntityType::class, [
         'placeholder' => 'Please choose a manager..',
         'empty_data' => null,
        'class' => 'User',
        'choice_label' => 'Managers',
        'required' => false,
        'query_builder' => function (UserRepository $er) {
            return $er->getManagersQueryBuilder();
        },
        ]);
        $builder->add('types', SubclassEntityType::class, [
         'placeholder' => 'Please choose a type..',
         'empty_data' => null,
        'class' => 'User',
            'class' => 'Type',
            'choice_label' => 'Types',
            'required' => false,
            'query_builder' => function (UserRepository $er) {
                return $er->getManagersQueryBuilder();
            },
        ]);

    }
     

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
         // ... 
        
        ]);
     }



}

For multiple choices we can use finishView method for creating new choices and add them on children of your type.

<?php


namespace App\Form;



use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;

class YourType extends AbstractType
{

    // If you have in the future other type Entity Type and you want to add option empty
    // You can just add it on this list  
    private const OPTION_EMPTY_ENTITIES_TYPE = [
        // child name => 'Message on option empty',
        'managers' => 'Select a manager..',
        'types' => 'Select a type..',
    ];

    private const OPTION_EMPTY_KEY ='option-empty';
    
    public function buildForm(FormBuilderInterface $builder, array $options)
    {


        $builder->add('managers', SubclassEntityType::class, [
            'class' => 'User',
            'choice_label' => 'Managers',
            'required' => false,
            'query_builder' => function (UserRepository $er) {
                return $er->getManagersQueryBuilder();
            },
            'multiple' => true,
        ]);
        $builder->add('types', SubclassEntityType::class, [
            'class' => 'Type',
            'choice_label' => 'Types',
            'required' => false,
            'query_builder' => function (UserRepository $er) {
                return $er->getManagersQueryBuilder();
            },
            'multiple' => true,
        ]);

    $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
        $data = $event->getData();
        // remove all options we has add on finishView
        foreach (self::OPTION_EMPTY_ENTITIES_TYPE as $childName => $optionMessage) {
            if (false !== ($key = array_search(self::OPTION_EMPTY_KEY ,$data[$childName]))) {
               unset($data[$childName][$key]); // example $data['managers'][0] => option-empty
            }
        }
        $event->setData($data);
    });

    }


    public function finishView(FormView $view, FormInterface $form, array $options)
    {

        foreach (self::OPTION_EMPTY_ENTITIES_TYPE as $childName => $optionMessage) {

            // value option-empty is not a valid option of EntityType X ,otherwise if user select this option
            // this form is invalid...
            $newChoice = new ChoiceView(null, self::OPTION_EMPTY_KEY, $optionMessage);
            array_unshift($view->children[$childName]->vars['choices'], $newChoice);
        }
    }


    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            // ..
        ]);
    }


}

Upvotes: 1

Related Questions