Skip to content

Commit c146744

Browse files
committed
feature symfony#26555 [Validator] Add constraint on unique elements collection(Assert\Unique) (zenmate, nicolas-grekas)
This PR was merged into the 4.3-dev branch. Discussion ---------- [Validator] Add constraint on unique elements collection(Assert\Unique) | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | no <!-- please add some, will be required by reviewers --> | Fixed tickets | symfony#26535 | License | MIT | Doc PR | symfony/symfony-docs#... <!-- required for new features --> <!-- Write a short README entry for your feature/bugfix here (replace this comment block.) This will help people understand your PR and can be used as a start of the Doc PR. Additionally: - Bug fixes must be submitted against the lowest branch where they apply (lowest branches are regularly merged to upper ones so they get the fixes too). - Features and deprecations must be submitted against the master branch. --> Commits ------- d0eb13e Rebase and update to latest CS fc66683 Add UniqueCollection constraint and validator
2 parents c34f8a9 + d0eb13e commit c146744

File tree

4 files changed

+174
-0
lines changed

4 files changed

+174
-0
lines changed

src/Symfony/Component/Validator/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ CHANGELOG
88
* added UATP cards support to `CardSchemeValidator`
99
* added option `allowNull` to NotBlank constraint
1010
* added `Json` constraint
11+
* added `Unique` constraint
1112

1213
4.2.0
1314
-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Validator\Constraints;
13+
14+
use Symfony\Component\Validator\Constraint;
15+
16+
/**
17+
* @Annotation
18+
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
19+
*
20+
* @author Yevgeniy Zholkevskiy <[email protected]>
21+
*/
22+
class Unique extends Constraint
23+
{
24+
public const IS_NOT_UNIQUE = '7911c98d-b845-4da0-94b7-a8dac36bc55a';
25+
26+
protected static $errorNames = [
27+
self::IS_NOT_UNIQUE => 'IS_NOT_UNIQUE',
28+
];
29+
30+
public $message = 'This collection should contain only unique elements';
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Validator\Constraints;
13+
14+
use Symfony\Component\Validator\Constraint;
15+
use Symfony\Component\Validator\ConstraintValidator;
16+
use Symfony\Component\Validator\Exception\UnexpectedValueException;
17+
18+
/**
19+
* @author Yevgeniy Zholkevskiy <[email protected]>
20+
*/
21+
class UniqueValidator extends ConstraintValidator
22+
{
23+
/**
24+
* {@inheritdoc}
25+
*/
26+
public function validate($value, Constraint $constraint)
27+
{
28+
if (!$constraint instanceof Unique) {
29+
throw new UnexpectedTypeException($constraint, Unique::class);
30+
}
31+
32+
if (null === $value) {
33+
return;
34+
}
35+
36+
if (!\is_array($value) && !$value instanceof \IteratorAggregate) {
37+
throw new UnexpectedValueException($value, 'array|IteratorAggregate');
38+
}
39+
40+
$collectionElements = [];
41+
foreach ($value as $element) {
42+
if (\in_array($element, $collectionElements, true)) {
43+
$this->context->buildViolation($constraint->message)
44+
->setParameter('{{ value }}', $this->formatValue($value))
45+
->setCode(Unique::IS_NOT_UNIQUE)
46+
->addViolation();
47+
48+
return;
49+
}
50+
$collectionElements[] = $element;
51+
}
52+
}
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Validator\Tests\Constraints;
13+
14+
use Symfony\Component\Validator\Constraints\Unique;
15+
use Symfony\Component\Validator\Constraints\UniqueValidator;
16+
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
17+
18+
class UniqueValidatorTest extends ConstraintValidatorTestCase
19+
{
20+
protected function createValidator()
21+
{
22+
return new UniqueValidator();
23+
}
24+
25+
/**
26+
* @expectedException \Symfony\Component\Validator\Exception\UnexpectedValueException
27+
*/
28+
public function testExpectsUniqueConstraintCompatibleType()
29+
{
30+
$this->validator->validate('', new Unique());
31+
}
32+
33+
/**
34+
* @dataProvider getValidValues
35+
*/
36+
public function testValidValues($value)
37+
{
38+
$this->validator->validate($value, new Unique());
39+
40+
$this->assertNoViolation();
41+
}
42+
43+
public function getValidValues()
44+
{
45+
return [
46+
yield 'null' => [[null]],
47+
yield 'empty array' => [[]],
48+
yield 'single integer' => [[5]],
49+
yield 'single string' => [['a']],
50+
yield 'single object' => [[new \stdClass()]],
51+
yield 'unique booleans' => [[true, false]],
52+
yield 'unique integers' => [[1, 2, 3, 4, 5, 6]],
53+
yield 'unique floats' => [[0.1, 0.2, 0.3]],
54+
yield 'unique strings' => [['a', 'b', 'c']],
55+
yield 'unique arrays' => [[[1, 2], [2, 4], [4, 6]]],
56+
yield 'unique objects' => [[new \stdClass(), new \stdClass()]],
57+
];
58+
}
59+
60+
/**
61+
* @dataProvider getInvalidValues
62+
*/
63+
public function testInvalidValues($value)
64+
{
65+
$constraint = new Unique([
66+
'message' => 'myMessage',
67+
]);
68+
$this->validator->validate($value, $constraint);
69+
70+
$this->buildViolation('myMessage')
71+
->setParameter('{{ value }}', 'array')
72+
->setCode(Unique::IS_NOT_UNIQUE)
73+
->assertRaised();
74+
}
75+
76+
public function getInvalidValues()
77+
{
78+
$object = new \stdClass();
79+
80+
return [
81+
yield 'not unique booleans' => [[true, true]],
82+
yield 'not unique integers' => [[1, 2, 3, 3]],
83+
yield 'not unique floats' => [[0.1, 0.2, 0.1]],
84+
yield 'not unique string' => [['a', 'b', 'a']],
85+
yield 'not unique arrays' => [[[1, 1], [2, 3], [1, 1]]],
86+
yield 'not unique objects' => [[$object, $object]],
87+
];
88+
}
89+
}

0 commit comments

Comments
 (0)