Conditional validation of fields based on other field value in Symfony2
Asked Answered
H

3

15

So here is the scenario: I have a radio button group. Based on their value, I should or shouldn't validate other three fields (are they blank, do they contain numbers, etc).

Can I pass all these values to a constraint somehow, and compare them there?

Or a callback directly in the controller is a better way to solve this?

Generally, what is the best practice in this case?

Hakon answered 13/5, 2015 at 6:4 Comment(0)
V
11

I suggest you to use a callback validator.

For example, in your entity class:

<?php

use Symfony\Component\Validator\Constraints as Assert;

/**
 * @Assert\Callback(methods={"myValidation"})
 */
class Setting {
    public function myValidation(ExecutionContextInterface $context)
    {
        if (
                $this->getRadioSelection() == '1' // RADIO SELECT EXAMPLE
                &&
                ( // CHECK OTHER PARAMS
                 $this->getFiled1() == null
                )
            )
        {
            $context->addViolation('mandatory params');
        }
       // put some other validation rule here
    }
}

Otherwise you can build your own custom validator as described here.

Let me know you need more info.

Hope this helps.

Versicle answered 14/5, 2015 at 4:48 Comment(2)
Not exactly what I needed, but it lead me to the right solution. Thank you!!Hakon
Hi @spiridon, could you detail how you achieve the right solution based on this approach please? Thank youFerne
P
9

You need to use validation groups. This allows you to validate an object against only some constraints on that class. More information can be found in the Symfony2 documentation http://symfony.com/doc/current/book/validation.html#validation-groups and also http://symfony.com/doc/current/book/forms.html#validation-groups

In the form, you can define a method called setDefaultOptions, that should look something like this:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    // some other code here ...
    $builder->add('SOME_FIELD', 'password', array(
        'constraints' => array(
            new NotBlank(array(
                'message' => 'Password is required',
                'groups' => array('SOME_OTHER_VALIDATION_GROUP'),
            )),
        )
   ))
}

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(
        'validation_groups' => function (FormInterface $form) {
            $groups = array('Default');
            $data = $form->getData();

            if ($data['SOME_OTHER_FIELD']) { // then we want password to be required
                $groups[] = 'SOME_OTHER_VALIDATION_GROUP';
            }

            return $groups;
        }
    ));
}

The following link provides a detailed example of how you can make use them http://web.archive.org/web/20161119202935/http://marcjuch.li:80/blog/2013/04/21/how-to-use-validation-groups-in-symfony/.

Hope this helps!

Pisci answered 13/5, 2015 at 6:49 Comment(2)
I'm doing that in a sub form and $form->getData() returns an empty array. My Form Type has fields and it works nontheless.Ferne
EDIT: Ok, using $form->getData() was my mistake, i had to search for the right field : $form->get('aField')->getData()Ferne
C
1

For anyone that may still care, whilst a callback validator is perfectly acceptable for simpler dependencies an expression validator is shorter to implement.

For example if you've got a field called "Want a drink?" then if yes (true) "How many?" (integer), you could simplify this with:

    /**
     * @var bool|null $wantDrink
     * @ORM\Column(name="want_drink", type="boolean", nullable=true)
     * @Assert\NotNull()
     * @Assert\Type(type="boolean")
     */
    private $wantDrink;

    /**
     * @var int|null $howManyDrinks
     * @ORM\Column(name="how_many_drinks", type="integer", nullable=true)
     * @Assert\Type(type="int")
     * @Assert\Expression(
     *     "true !== this.getWantDrink() or (null !== this.getHowManyDrinks() and this.getHowManyDrinks() >= 1)",
     *     message="This value should not be null."
     * )
     */
    private $howManyDrinks;

You write the expression in PASS context, so the above is saying that $howManyDrinks must be a non-null integer at least 1 if $wantDrink is true, otherwise we don't care about $howManyDrinks. Make use of the expression syntax, which is sufficient for a broad range of scenarios.

Another scenario I find myself frequently using a expression validator are when I've got two fields to the effect of "date start" and "date end", so that they can each ensure that they are the right way around (so that the start date is before or equal to the end date and the end date is greater or equal to the start date).

Cowen answered 13/12, 2022 at 17:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.