Search code examples
phpformssymfonysymfony-formsmultiple-choice

Symfony FormType at least one radio selected


I'm working on Symfony 3.4 and I have a FormType with multiples fields and 2 booleans like :

           ->add("is_my_first_boolean", ChoiceType::class, array(
                "expanded" => true,
                "multiple" => false,
                "choices" => array(
                    'Yes' => "1",
                    'No' => "0"
                )
            ))
            ->add("is_my_second_boolean", ChoiceType::class, array(
                "expanded" => true,
                "multiple" => false,
                "choices" => array(
                    'Yes' => "1",
                    'No' => "0"
                )
            ))

So the user can select 2 booleans Yes/No on my form, and what I need is a validation (PHP validation in back-end, not in front) like at least one of these two booleans is selected.

So if both are set to NO, there is an error 'You must choose at least first_boolean or second_boolean"

What's the best way to do that ?

Thanks !


Solution

  • Well if you only have the form type and no underlying form type you could add a simple Expression constraint:

    use Symfony\Component\Validator\Constraints as Assert;
    
    ....
    
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add("is_my_first_boolean", ChoiceType::class, array(
                "expanded" => true,
                "multiple" => false,
                "choices" => array(
                    'Yes' => "1",
                    'No' => "0"
                ),
                'constraints' => [
                    new Assert\Expression(array(
                        'expression' => 'value == 1 or this.getParent()["is_my_second_boolean"].getData() == 1',
                        'message' => 'Either is_my_first_boolean or is_my_second_boolean must be selected',
                    ))
                ]
            ))
            ->add("is_my_second_boolean", ChoiceType::class, array(
                "expanded" => true,
                "multiple" => false,
                "choices" => array(
                    'Yes' => "1",
                    'No' => "0"
                ),
                'constraints' => [
                    new Assert\Expression(array(
                        'expression' => 'value == 1 or this.getParent()["is_my_first_boolean"].getData() == 1',
                        'message' => 'Either is_my_first_boolean or is_my_second_boolean must be selected',
                    ))
                ]
            ));
    }
    

    Notice how in the expression the second or contains a reference to the other field. This way both fields are getting the "error". If that is too much you could just remove one constraint and only one field is highlighted with the error.

    If your form is backed by a data class you can of course add the Expression constraint to this class:

    /**
     * @Assert\Expression(
     *     "this.getisMyFirstBoolean() or this.getisMySecondBoolean()",
     *     message="Either first or second boolean have to be set",
     * )
     */
     class MyFormData
    

    In this case the error message is displayed at the form level.