phpsymfonysymfony-validator

Symfony Validator does not work with nested AtLeastOneOf Constraint


In following code (condensed from a project) the validation for $constraint2 returns no error, which is not the behaviour I expect (should also return errors):

    use Symfony\Component\Validator\Validation;
    use Symfony\Component\Validator\Constraints\Type;
    use Symfony\Component\Validator\Constraints\AtLeastOneOf;
    
    $config = 1; //Integer
    $constraint1 = new AtLeastOneOf([ new Type('string') ]);
    $constraint2 = new AtLeastOneOf([ new AtLeastOneOf([ new Type('string') ]) ]);
    
    $validator = Validation::createValidator();
    echo "Constraint 1: ".(count($validator->validate($config,$constraint1))).'<br>';
    echo "Constraint 2: ".(count($validator->validate($config,$constraint2))).'<br>';

Output:

Constraint 1: 1
Constraint 2: 0

The problem seems to be the nested AtLeastOneOf validator, but I do not understand why it does validate to no errors.


Solution

  • This behavior was indeed not expected, so I looked into it. As of today, it seems that there is an issue with nested AtLeastOneOf constraint as you can see from this issue from symfony/symfony.

    You probably do not want to wait for a fix so maybe the only way to fix it now is to

    Replace your deeply nested AtLeastOneOf constraint

    Let's say your constraint is:

        $constraints = [
            new AtLeastOneOf(
                [
                    new Type('string'),
                    new Type('datetime'),
                    new AtLeastOneOf([ new Type('boolean'), new Type('string') ]),
                ])
        ];
    

    You should be able to replace it with an equivalent constraint:

        $constraints = [
            new AtLeastOneOf(
                [
                    new Type('string'),
                    new Type('datetime'),
                    new Type('boolean'),
                    new Type('string'),
                ])
        ];
    

    If two AtLeastOneOf constraint are nested, you should be able to put whatever is in the second one into the first one without changing its behavior.