10000 [Validator] Allow Unique constraint validation on all elements · symfony/symfony@92baf9a · GitHub
[go: up one dir, main page]

Skip to content

Commit 92baf9a

Browse files
committed
[Validator] Allow Unique constraint validation on all elements
1 parent 0a9eb28 commit 92baf9a

File tree

3 files changed

+81
-4
lines changed

3 files changed

+81
-4
lines changed

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

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

2727
public array|string $fields = [];
2828
public ?string $errorPath = null;
29+
public bool $multipleErrors = false;
2930

3031
protected const ERROR_NAMES = [
3132
self::IS_NOT_UNIQUE => 'IS_NOT_UNIQUE',
@@ -48,13 +49,15 @@ public function __construct(
4849
mixed $payload = null,
4950
array|string|null $fields = null,
5051
?string $errorPath = null,
52+
?bool $multipleErrors = null,
5153
) {
5254
parent::__construct($options, $groups, $payload);
5355

5456
$this->message = $message ?? $this->message;
5557
$this->normalizer = $normalizer ?? $this->normalizer;
5658
$this->fields = $fields ?? $this->fields;
5759
$this->errorPath = $errorPath ?? $this->errorPath;
60+
$this->multipleErrors = $multipleErrors ?? $this->multipleErrors;
5861

5962
if (null !== $this->normalizer && !\is_callable($this->normalizer)) {
6063
throw new InvalidArgumentException(\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: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,18 @@ public function validate(mixed $value, Constraint $constraint): void
5151
->setParameter('{{ value }}', $this->formatValue($element))
5252
->setCode(Unique::IS_NOT_UNIQUE);
5353

54-
if (null !== $constraint->errorPath) {
55-
$violationBuilder->atPath("[$index].{$constraint->errorPath}");
54+
if ($constraint->multipleErrors || null !== $constraint->errorPath) {
55+
$violationBuilder->atPath("[$index]".(null !== $constraint->errorPath ? ".{$constraint->errorPath}" : ''));
5656
}
5757

5858
$violationBuilder->addViolation();
5959

60-
return;
60+
if (!$constraint->multipleErrors) {
61+
return;
62+
}
63+
} else {
64+
$collectionElements[] = $element;
6165
}
62-
$collectionElements[] = $element;
6366
}
6467
}
6568

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

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,77 @@ public function testErrorPathWithNonList()
394394
->assertRaised();
395395
}
396396

397+
public function testMultiple()
398+
{
399+
$this->validator->validate(
400+
['a1', 'a2', 'a1', 'a1', 'a2'],
401+
new Unique(multipleErrors: true),
402+
);
403+
404+
$this
405+
->buildViolation('This collection should contain only unique elements.')
406+
->setParameter('{{ value }}', '"a1"')
407+
->setCode(Unique::IS_NOT_UNIQUE)
408+
->atPath('property.path[2]')
409+
410+
->buildNextViolation('This collection should contain only unique elements.')
411+
->setParameter('{{ value }}', '"a1"')
412+
->setCode(Unique::IS_NOT_UNIQUE)
413+
->atPath('property.path[3]')
414+
415+
->buildNextViolation('This collection should contain only unique elements.')
416+
->setParameter('{{ value }}', '"a2"')
417+
->setCode(Unique::IS_NOT_UNIQUE)
418+
->atPath('property.path[4]')
419+
420+
->assertRaised();
421+
}
422+
423+
public function testMultipleWithErrorPath()
424+
{
425+
$array = [
426+
new DummyClassOne(),
427+
new DummyClassOne(),
428+
new DummyClassOne(),
429+
new DummyClassOne(),
430+
new DummyClassOne(),
431+
];
432+
433+
$array[0]->code = 'a1';
434+
$array[1]->code = 'a2';
435+
$array[2]->code = 'a1';
436+
$array[3]->code = 'a1';
437+
$array[4]->code = ' 9E7A a2';
438+
439+
$this->validator->validate(
440+
$array,
441+
new Unique(
442+
normalizer: [self::class, 'normalizeDummyClassOne'],
443+
fields: 'code',
444+
errorPath: 'code',
445+
multipleErrors: true,
446+
)
447+
);
448+
449+
$this
450+
->buildViolation('This collection should contain only unique elements.')
451+
->setParameter('{{ value }}', 'array')
452+
->setCode(Unique::IS_NOT_UNIQUE)
453+
->atPath('property.path[2].code')
454+
455+
->buildNextViolation('This collection should contain only unique elements.')
456+
->setParameter('{{ value }}', 'array')
457+
->setCode(Unique::IS_NOT_UNIQUE)
458+
->atPath('property.path[3].code')
459+
460+
->buildNextViolation('This collection should contain only unique elements.')
461+
->setParameter('{{ value }}', 'array')
462+
->setCode(Unique::IS_NOT_UNIQUE)
463+
->atPath('property.path[4].code')
464+
465+
->assertRaised();
466+
}
467+
397468
public static function normalizeDummyClassOne(DummyClassOne $obj): array
398469
{
399470
return [

0 commit comments

Comments
 (0)
0