Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitfd9c5b4

Browse files
feature#59274 [Validator] Allow Unique constraint validation on all elements (Jean-Beru)
This PR was squashed before being merged into the 7.3 branch.Discussion----------[Validator] Allow Unique constraint validation on all elements| Q | A| ------------- | ---| Branch? | 7.3| Bug fix? | no| New feature? | yes| Deprecations? | no| Issues || License | MITSometimes it could be useful to assert that every elements of a collection is not duplicated. This PR adds a `multipleErrors` option to the Unique constraint to avoid stopping at the first violation.Its value is `false` by default to avoid BC breaks:```php$violations = $this->validator->validate( ['a1', 'a2', 'a1', 'a1', 'a2'], new Unique(),);// 1 violation on [2]```Now```php$violations = $this->validator->validate( ['a1', 'a2', 'a1', 'a1', 'a2'], new Unique(multipleErrors: true),);// 3 violations on [2], [3] and [4]```Commits-------3fc871e [Validator] Allow Unique constraint validation on all elements
2 parents8d8183f +3fc871e commitfd9c5b4

File tree

4 files changed

+88
-57
lines changed

4 files changed

+88
-57
lines changed

‎src/Symfony/Component/Validator/CHANGELOG.md

Lines changed: 1 addition & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,59 +5,12 @@ CHANGELOG
55
---
66

77
* Deprecate defining custom constraints not supporting named arguments
8-
9-
Before:
10-
11-
```php
12-
use Symfony\Component\Validator\Constraint;
13-
14-
class CustomConstraint extends Constraint
15-
{
16-
public function __construct(array $options)
17-
{
18-
// ...
19-
}
20-
}
21-
```
22-
23-
After:
24-
25-
```php
26-
use Symfony\Component\Validator\Attribute\HasNamedArguments;
27-
use Symfony\Component\Validator\Constraint;
28-
29-
class CustomConstraint extends Constraint
30-
{
31-
#[HasNamedArguments]
32-
public function __construct($option1, $option2, $groups, $payload)
33-
{
34-
// ...
35-
}
36-
}
37-
```
388
* Deprecate passing an array of options to the constructors of the constraint classes, pass each option as a dedicated argument instead
39-
40-
Before:
41-
42-
```php
43-
new NotNull([
44-
'groups' => ['foo', 'bar'],
45-
'message' => 'a custom constraint violation message',
46-
])
47-
```
48-
49-
After:
50-
51-
```php
52-
new NotNull(
53-
groups: ['foo', 'bar'],
54-
message: 'a custom constraint violation message',
55-
)
56-
```
579
* Add support for ratio checks for SVG files to the`Image` constraint
5810
* Add the`Slug` constraint
5911
* Add support for the`otherwise` option in the`When` constraint
6012
* Add support for multiple fields containing nested constraints in`Composite` constraints
13+
* Add the`stopOnFirstError` option to the`Unique` constraint to validate all elements
6114

6215
7.2
6316
---

‎src/Symfony/Component/Validator/Constraints/Unique.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class Unique extends Constraint
2727

2828
publicarray|string$fields = [];
2929
public ?string$errorPath =null;
30+
publicbool$stopOnFirstError =true;
3031

3132
protectedconstERROR_NAMES = [
3233
self::IS_NOT_UNIQUE =>'IS_NOT_UNIQUE',
@@ -50,6 +51,7 @@ public function __construct(
5051
mixed$payload =null,
5152
array|string|null$fields =null,
5253
?string$errorPath =null,
54+
?bool$stopOnFirstError =null,
5355
) {
5456
if (\is_array($options)) {
5557
trigger_deprecation('symfony/validator','7.3','Passing an array of options to configure the "%s" constraint is deprecated, use named arguments instead.',static::class);
@@ -61,6 +63,7 @@ public function __construct(
6163
$this->normalizer =$normalizer ??$this->normalizer;
6264
$this->fields =$fields ??$this->fields;
6365
$this->errorPath =$errorPath ??$this->errorPath;
66+
$this->stopOnFirstError =$stopOnFirstError ??$this->stopOnFirstError;
6467

6568
if (null !==$this->normalizer && !\is_callable($this->normalizer)) {
6669
thrownewInvalidArgumentException(\sprintf('The "normalizer" option must be a valid callable ("%s" given).',get_debug_type($this->normalizer)));

‎src/Symfony/Component/Validator/Constraints/UniqueValidator.php

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,20 +46,24 @@ public function validate(mixed $value, Constraint $constraint): void
4646
continue;
4747
}
4848

49-
if (\in_array($element,$collectionElements,true)) {
50-
$violationBuilder =$this->context->buildViolation($constraint->message)
51-
->setParameter('{{ value }}',$this->formatValue($element))
52-
->setCode(Unique::IS_NOT_UNIQUE);
49+
if (!\in_array($element,$collectionElements,true)) {
50+
$collectionElements[] =$element;
51+
continue;
52+
}
5353

54-
if (null !==$constraint->errorPath) {
55-
$violationBuilder->atPath("[$index].{$constraint->errorPath}");
56-
}
54+
$violationBuilder =$this->context->buildViolation($constraint->message)
55+
->setParameter('{{ value }}',$this->formatValue($element))
56+
->setCode(Unique::IS_NOT_UNIQUE);
57+
58+
if (!$constraint->stopOnFirstError ||null !==$constraint->errorPath) {
59+
$violationBuilder->atPath("[$index]".(null !==$constraint->errorPath ?".{$constraint->errorPath}" :''));
60+
}
5761

58-
$violationBuilder->addViolation();
62+
$violationBuilder->addViolation();
5963

64+
if ($constraint->stopOnFirstError) {
6065
return;
6166
}
62-
$collectionElements[] =$element;
6367
}
6468
}
6569

‎src/Symfony/Component/Validator/Tests/Constraints/UniqueValidatorTest.php

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,77 @@ public function testErrorPathWithNonList()
387387
->assertRaised();
388388
}
389389

390+
publicfunctiontestWithoutStopOnFirstError()
391+
{
392+
$this->validator->validate(
393+
['a1','a2','a1','a1','a2'],
394+
newUnique(stopOnFirstError:false),
395+
);
396+
397+
$this
398+
->buildViolation('This collection should contain only unique elements.')
399+
->setParameter('{{ value }}','"a1"')
400+
->setCode(Unique::IS_NOT_UNIQUE)
401+
->atPath('property.path[2]')
402+
403+
->buildNextViolation('This collection should contain only unique elements.')
404+
->setParameter('{{ value }}','"a1"')
405+
->setCode(Unique::IS_NOT_UNIQUE)
406+
->atPath('property.path[3]')
407+
408+
->buildNextViolation('This collection should contain only unique elements.')
409+
->setParameter('{{ value }}','"a2"')
410+
->setCode(Unique::IS_NOT_UNIQUE)
411+
->atPath('property.path[4]')
412+
413+
->assertRaised();
414+
}
415+
416+
publicfunctiontestWithoutStopOnFirstErrorWithErrorPath()
417+
{
418+
$array = [
419+
newDummyClassOne(),
420+
newDummyClassOne(),
421+
newDummyClassOne(),
422+
newDummyClassOne(),
423+
newDummyClassOne(),
424+
];
425+
426+
$array[0]->code ='a1';
427+
$array[1]->code ='a2';
428+
$array[2]->code ='a1';
429+
$array[3]->code ='a1';
430+
$array[4]->code ='a2';
431+
432+
$this->validator->validate(
433+
$array,
434+
newUnique(
435+
normalizer: [self::class,'normalizeDummyClassOne'],
436+
fields:'code',
437+
errorPath:'code',
438+
stopOnFirstError:false,
439+
)
440+
);
441+
442+
$this
443+
->buildViolation('This collection should contain only unique elements.')
444+
->setParameter('{{ value }}','array')
445+
->setCode(Unique::IS_NOT_UNIQUE)
446+
->atPath('property.path[2].code')
447+
448+
->buildNextViolation('This collection should contain only unique elements.')
449+
->setParameter('{{ value }}','array')
450+
->setCode(Unique::IS_NOT_UNIQUE)
451+
->atPath('property.path[3].code')
452+
453+
->buildNextViolation('This collection should contain only unique elements.')
454+
->setParameter('{{ value }}','array')
455+
->setCode(Unique::IS_NOT_UNIQUE)
456+
->atPath('property.path[4].code')
457+
458+
->assertRaised();
459+
}
460+
390461
publicstaticfunctionnormalizeDummyClassOne(DummyClassOne$obj):array
391462
{
392463
return [

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp