Artisan Développeur

Qualité, amélioration continue, agilité.

Add choices to a Symfony formType with an event listener

If you want to add (or remove) choices from a ChoiceType in your formType, this is how to do it with an event listener.
The event you will subscribe depends on the data you have and your workflow.
I had to modify a formType to allow the edition of an entity with a particular value on one field.
The field is "mode".
"myParticularMode" is a mode not available by default, I use it only under certain conditions, the entity is programmatically created, and the user is redirected to the edit form to finish to fill the data.
I don't want to allow my users to use that mode om new I don't want to allow my users to use that mode on new entity, I need it only when I edit the entities defined with this "mode".

The code take the event "POST_SET_DATA", this way I have my data, and I know the mode.
If the "mode" is myParticularMode" I add it to the choices.

Add a choice to the choices:

$builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) {
    // get the form from the event
    $form = $event->getForm();
    
    if ('myParticularMode' == $form->get('mode')->getData()) {
        // get the field options
        $options = $form->get('mode')->getConfig()->getOptions();
        // add the mode to the choices array
        $options['choices']['MY_PARTICULAR_MODE'] = 'myParticularMode_display_name';
        $form->add('mode', ChoiceType::class, $options);
    }
});

To replace all the choices and display only the one, don’t take the options, just override the choices array, and you can even disable it:

$builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) {
    // get the form from the event
    $form = $event->getForm();
    
    if ('myParticularMode' == $form->get('mode')->getData()) {
        // add the mode to the choices array
        $options['choices']['MY_PARTICULAR_MODE'] = 'myParticularMode_display_name';
        // disable the field
        $options['disabled'] = true;
        $form->add('mode', ChoiceType::class, $options);
    }
});

Enjoy 🙂

Comments ( 2 )

  1. / ReplyAnonymous
    There is one major problem with this implementation (I've seen it in quite a few different resources). If you leverage the twig form rendering, without having to explictly render each form element in the template, then using an event like this you will end up with having your field rendered last. Simply speaking, imagine the following scenarion: $form->add('title', 'choice'); $form->add('name', 'text'); $form->add('age', 'text'); Then after your event has been dispatched, you will end up with following elements order when rendered: - name - age - title So... not that great.
    • / ReplyNicolas
      it's true, in general I always render my fields manually. But if you want to have a specific order, can't you just order the fields in the eventListener ? I my opinion though thinking of the rendering in the eventlistener is not that good, because of separation of repsonsability, let twig handle the display precisely if you need more.

Leave a reply

Your email address will not be published.

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.