Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony3 + Select2 AJAX - disable validation of choices

I have a Symfony3 form that has a ChoiceType field. It uses Select2 with an AJAX data source. This bit is working fine. However, when the form is submitted, the Symfony validation kicks in and complains:

This value is not valid  

I guess this is because the choice picked via AJAX doesn't exist in the 'choices' key in the Form Type.

I'm relatively new to Symfony. Can someone point me in the right direction to disable the validation on the field?

like image 956
fistameeny Avatar asked Mar 08 '16 20:03

fistameeny


2 Answers

You shouldn't disable validation. Add choices dynamically with Form Events - http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html

You can also take a look at this bundle: https://github.com/tetranz/select2entity-bundle

like image 107
Paweł Mikołajczuk Avatar answered Oct 11 '22 04:10

Paweł Mikołajczuk


You must always use a string value to submit data to a ChoiceType.

Considering the following ChoiceType configuration:

use Symfony\Component\Form\Extension\Core\Type\ChoiceType;

$builder->add('some_choice', ChoiceType::class, array(
    'choices' => array(
        'Choose 1' => 1,
        'Choose A' => 'A',
        'Choose True' => true,
    ),
));

By default, you might expect every key from the choice array to be used as label, and and every choice value to be converted to string and used as html value:

<option value="1">Choose 1</option>
<option value="A">Choose A</option>
<option value="1">Choose True</option>

This example above is wrong.

As you can see, casting true to string gives "1" and it's already used for integer 1 choice.

All choice values MUST always be unique, so instead by default, in that case, the ChoiceType uses a numeric incrementation:

<option value="0">Choose 1</option>
<option value="1">Choose A</option>
<option value="2">Choose True</option>

The same happens when some model choice value in the choice array are not scalar (e.g array, object, null ...).

Then the submitted data should be "0", "1" or "2". Each will be mapped backed to the corresponding choice by the ChoiceType.

To keep the full control of the string value to use for each choice, you can use the option choice_value as a closure which gets passed each choice as only argument and must return its string value.

If your choices are objects or arrays you can set it as a property path:

'choice_value' => 'property'

// will be equivalent to

'choice_value' => function ($choice) {
    if (is_array($choice)) {
        return $choice['property'];
    }

    if (is_object($choice)) {
        return $choice->getProperty();
        // or even $choice->isProperty()
    }

    throw new UnexpectedTypeException();
}

Conclusion:

Default behavior is same as:

$builder->add('some_choice', ChoiceType::class, array(
    'choices' => array(
        'Choose 1' => 1,
        'Choose A' => 'A',
        'Choose True' => true,
    ),
    'choice_value' => function ($choice) {
        if (!is_scalar($choice) {
            return null;
        }

        return false === $choice ? '0' : (string) $choice;
    },
));

If null or two identical values are returned, an incrementing integer will be used instead.

You always have to submit the string choice value in order to get it mapped back by the ChoiceType.

Any unknown values or "extra" values will end up with your error.

See the official doc

like image 21
Heah Avatar answered Oct 11 '22 03:10

Heah