8

Given this input:

[
    'key' => 'value',
]

How to validate to ensure that:

  1. key attribute exists
  2. Its value is an array (with any number of elements)

I expected this constraint to work

    $constraint = new Collection([
        'key' => new Required([
            new Type('array'),
            new Collection([
                'value' => new Required([
                    new NotBlank(),
                ]),
            ]),
        ]),
    ]);

but it throws an exception:

Symfony\Component\Validator\Exception\UnexpectedTypeException: Expected argument  of type "array or Traversable and ArrayAccess", "string" given

What am I missing?

PS: it's symfony v2.7.1

PPS: just to clarify: I know one can use a callback. If I wanted to re-implement the validation manually from scratch - I wouldn't have used symfony at the very first place. So the question is particularly about combining the existing constraints and not about using a callback constraint..

2
  • something like if ((is_array($a)) or ($a instanceof Traversable)) Commented Jun 24, 2015 at 5:25
  • @Umair the question is particularly about using symfony2 validator Commented Jun 24, 2015 at 5:28

3 Answers 3

5
+50

I had the exact same problem two nights ago.

The conclusion at the very end was that Symfony2 validation has no "fast-fail" validation. That is, even if your Type() constraint would fail it would proceed with other constraints and thus fail with UnexpectedTypeException exception.

However, I was able to find a way to tackle that:

$constraint = new Collection([
    'key' => new Required([
        new Type(['type' => 'array']),
        new Collection([
            // Need to wrap fields into this
            // in order to provide "groups"
            'fields' => [ 
                'value' => new Required([
                    new NotBlank(),
                ]),
            ],
            'groups' => 'phase2' // <-- THIS IS CRITICAL
        ]),
    ]),
]);

// In your controller, service, etc...
$V = $this->get('validator');

// Checks everything by `Collection` marked with special group
$violations = $V->validate($data, $constraint);

if ( $violations->count()){
    // Do something
}

// Checks *only* "phase2" group constraints
$violations = $V->validate($data, $constraint, 'phase2');

if ( $violations->count()){
    // Do something
}

Hope that this helps a bit. Personally, I find it annoying that we need to do this. Some sort of "fast-fail" flag within validator service would be much helpful.

Sign up to request clarification or add additional context in comments.

1 Comment

That is finally something that looks like an answer, thanks :-) 3 days left for bounty to expire, this one is the only candidate yet.
2

You're saying the Collection constraint should just fail instead of throwing an exception because 'value' is a string and not an array.

There is a recently logged Symfony bug for this: https://github.com/symfony/symfony/issues/14943

3 Comments

Constraints have a concept of so called "default options", which is type in case of a Type constraint. Which means that new Type(['type' => 'array']) is identical to new Type('array'). See github.com/symfony/symfony/blob/2.8/src/Symfony/Component/… and github.com/symfony/symfony/blob/2.8/src/Symfony/Component/…
Doing type validation is always "fun" because at what level the actual type error occurred is rarely clear. Sorry about that, try this new answer.
"Your input has the string 'value' as the value of index 'key', which is not an array, so the exception is thrown here" --- I know why it was thrown. The question was: how to write a constraint that would accept ANY INPUT. If I could guarantee that input is always valid - I wouldn't use validators. "If you change your input to" --- would you literally put it on your site: please dear hackers, don't pass us what we not except since it crashes our application?
1

Use Callback constraint(docs) where you can implement your custom validation logic.

The other way is to create custom constraint and validator classes. (docs)

1 Comment

What exactly are you suggesting? To reimplement all the symfony2 constraints? What is the point of using a symfony validator at all then?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.