简体   繁体   中英

Conditional validation of fields based on other field value in Symfony2

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?

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.

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!

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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM