symfony: Collection validation does not stop after first violation
PHP 7 Using Symfony\Component\Validator\Constraints\Collection;
I’m using Symfony 3.1 and I hope I’m not doing something wrong. When I validate a field, it doesn’t stop after the first violation. Example :
$errors = $val->validate(
$info,
new \Symfony\Component\Validator\Constraints\Collection([
'fields' => array(
'specialKey' => array(
new NotBlank(),
new Length(['min' => 8,'max' => 20]),
new Regex(['value' => "/^[A-Za-z]*$/"]),
)
),
'allowExtraFields' => true,
])
);
I’m getting :
'This value is too short. It should have 8 characters or more.'
'This value is not valid.'
I found a walk-around for those who are interested :
$errors = $val->validate(
$info,
new \Symfony\Component\Validator\Constraints\Collection([
'fields' => array(
'specialKey' => array(
new NotBlank(['groups' => 'groupe1']),
new Length(['min' => 8,'max' => 20,'groups' => 'groupe2']),
new Regex(['value' => "/^[A-Za-z]*$/",'groups' => 'groupe3']),
)
),
'allowExtraFields' => true,
]),
new GroupSequence(array('Default','groupe1','groupe2','groupe3'))
);
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Comments: 24 (16 by maintainers)
Commits related to this issue
- feature #34456 [Validator] Add a constraint to sequentially validate a set of constraints (ogizanagi) This PR was merged into the 5.1-dev branch. Discussion ---------- [Validator] Add a constraint ... — committed to symfony/symfony by fabpot 4 years ago
- feature #34456 [Validator] Add a constraint to sequentially validate a set of constraints (ogizanagi) This PR was merged into the 5.1-dev branch. Discussion ---------- [Validator] Add a constraint ... — committed to symfony/validator by fabpot 4 years ago
I agree with @jaikdean. If I want to check a property for non-empty string and then second validator checks it in the database, the query will be executed anyway, even if the first validator will fail, and that’s not cool.
I agree with @xabbuh here, and group sequences already are a solution to this. But, throwing a raw idea: could a
@Sequence
constraint be helpful? It’ll be a composite constraint and accept a collection of constraints as argument (like the@All
constraint for instance), and proceed to the next constraint validation only if there is no violation yet. Looks like it could help solving some simple cases straightforwardly to me (but not as powerful as group sequences).+1 for a “stopOnFailure” type option.
Our use case is using validators to check the format of user input from a JSON request body. Say we’ve decoded the JSON and want a PIN field to be a string of 4 numeric digits (not an integer in case it starts with a 0):
This all appears to work correctly, until the user starts messing around and sends an array for the value of this field. In this case, the
Type
constraint causes a violation as expected, but theRegex
constraint throws an uncaughtUnexpectedTypeException
.We’re currently calling
validate()
for each constraint individually and stopping when we get a violation, to work around this.@pfcloutier I tagged this as a feature request.
I’m looking for pretty much what you describe @ogizanagi so yes, that sounds like a good idea to me.
For that use case there is the concept of group sequence providers where subsequent validation groups are only checked if the previous ones did not error.
I see many people around suggesting like @xabbuh and @ogizanagi using group sequences, but this may not always be a good workaround as a violation in one group would skip validation of constraints in subsequent groups on all other fields as well, even if those fields comply with first groups constraints but violate some constraints in subsequent groups.
Although I understand @Jean85’s POV and the need to show all independent constraint violations at once (like password length and charset), some constraints may still be dependent on previous ones being valid.
I think that’s especially true about data type constraints, as @jaikdean and @rijnhard pointed out, since trying to validate constraints on a value of the wrong type makes no sense to me (e.g. why raising an error about a date field not being in an expected period of time if the input is not a date in the first place?), and this may even lead to raising exceptions/errors if subsequent validation rely on code that assumes that values have the expected type. I’m facing a similar issue validating a field which is expected to be a float value (so having a
Type
constraint on it) and also havingExpression
constraints using some arithmetics with the value. If the input is not numeric, then the evaluation of these expressions raises anErrorException
up to thevalidate()
method invocation thus the constraint violation list of the whole entity is lost and subsequent fields aren’t validated either! If I want to avoid it, I can still duplicate type checking in every subsequent constraint (using ternary operator aroundvalue
occurrences in my case) but this is dirty IMO, this clutters the code and makes less clear what the actual constraint is.As an API user, I think we should have an easy way to set a
Type
constraint and use it as a safe guard before further validation, without having to write a custom validator or such. Moreover, I feel this is inconsistent with how validators deal withnull
values. As @webmozart said in #10221 comment:Then why not silently allowing incoherent data types as well? I feel like (a) whether a value’s type is coherent/safe and (b) which constraints this value has to satisfy, if it is coherent/safe type-wise, are also orthogonal concepts. And this may be why some (many?) of us don’t expect Symfony to raise further violations when type constraint is violated.
+1 for a
@Sequence
compound constraint (although it may make constraint inference more difficult for other annotation-scanning components?) +1 as well for a “stopOnFailure” (or “orSkipNext”) option, at least onType
constraint but maybe even a base inherited option, defaulted to no-skip to preserve BC. Something like:(Apologies for being beyond OP scope about Collection validation of independent constraints, I didn’t want to create a new issue…)
How to Sequentially Apply Validation Groups
https://symfony.com/doc/3.4/validation/sequence_provider.html
works for me.
@iltar I know, but since the issue that you raised is UX related, that is helpful, since it stops the user even before submitting the form, requiring the field to be filled.
Why it should stop? If there are multiple errors, the users should be made aware of all of them! Otherwise it could get frustrating for him, getting a different error for 2-3 submission in a row