8000 [Validator] Add `Finite` constraint · symfony/symfony@679acd9 · GitHub
[go: up one dir, main page]

Skip to content

Commit 679acd9

Browse files
committed
[Validator] Add Finite constraint
1 parent 6c85287 commit 679acd9

File tree

5 files changed

+213
-0
lines changed

5 files changed

+213
-0
lines changed

src/Symfony/Component/Validator/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ CHANGELOG
66

77
* Allow single integer for the `versions` option of the `Uuid` constraint
88
* Allow single constraint to be passed to the `constraints` option of the `When` constraint
9+
* Add `Finite` constraint
910

1011
6.3
1112
---
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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+
*
19+
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
20+
*
21+
* @author Guillaume Aveline <guillaume@codr.fr>
22+
*/
23+
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
24+
class Finite extends Constraint
25+
{
26+
public const NOT_FINITE_ERROR = '5f809eb0-78b9-492d-ad37-5a5188390415';
27+
28+
protected const ERROR_NAMES = [
29+
self::NOT_FINITE_ERROR => 'NOT_FINITE_ERROR',
30+
];
31+
32+
public $message = 'This value should be finite.';
33+
34+
public function __construct(array $options = [], array $groups = null, mixed $payload = null, string $message = null)
35+
{
36+
parent::__construct($options, $groups, $payload);
37+
38+
$this->message = $message ?? $this->message;
39+
}
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\UnexpectedTypeException;
17+
18+
/**
19+
* @author Guillaume Aveline <guillaume@codr.fr>
20+
*/
21+
class FiniteValidator extends ConstraintValidator
22+
{
23+
public function validate(mixed $value, Constraint $constraint): void
24+
{
25+
if (!$constraint instanceof Finite) {
26+
throw new UnexpectedTypeException($constraint, Finite::class);
27+
}
28+
29+
if (null === $value) {
30+
return;
31+
}
32+
33+
if (is_numeric($value) && is_finite($value)) {
34+
return;
35+
}
36+
37+
$this->context->buildViolation($constraint->message)
38+
->setParameter('{{ value }}', $this->formatValue($value))
39+
->setCode(Finite::NOT_FINITE_ERROR)
40+
->addViolation();
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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 PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Validator\Constraints\Finite;
16+
use Symfony\Component\Validator\Mapping\ClassMetadata;
17+
use Symfony\Component\Validator\Mapping\Loader\AnnotationLoader;
18+
19+
class FiniteTest extends TestCase
20+
{
21+
public function testAttributes()
22+
{
23+
$metadata = new ClassMetadata(FiniteDummy::class);
24+
$loader = new AnnotationLoader();
25+
self::assertTrue($loader->loadClassMetadata($metadata));
26+
27+
[$bConstraint] = $metadata->properties['b']->getConstraints();
28+
self::assertSame('myMessage', $bConstraint->message);
29+
self::assertSame(['Default', 'FiniteDummy'], $bConstraint->groups);
30+
31+
[$cConstraint] = $metadata->properties['c']->getConstraints();
32+
self::assertSame(['my_group'], $cConstraint->groups);
33+
self::assertSame('some attached data', $cConstraint->payload);
34+
}
35+
}
36+
37+
class FiniteDummy
38+
{
39+
#[Finite]
40+
private $a;
41+
42+
#[Finite(message: 'myMessage')]
43+
private $b;
44+
45+
#[Finite(groups: ['my_group'], payload: 'some attached data')]
46+
private $c;
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Finite;
15+
use Symfony\Component\Validator\Constraints\FiniteValidator;
16+
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
17+
18+
class FiniteValidatorTest extends ConstraintValidatorTestCase
19+
{
20+
protected function createValidator(): FiniteValidator
21+
{
22+
return new FiniteValidator();
23+
}
24+
25+
public function testNullIsValid()
26+
{
27+
$constraint = new Finite();
28+
29+
$this->validator->validate(null, $constraint);
30+
31+
$this->assertNoViolation();
32+
}
33+
34+
/**
35+
* @dataProvider getValidValues
36+
*/
37+
public function testValidValues(mixed $value)
38+
{
39+
$constraint = new Finite();
40+
41+
$this->validator->validate($value, $constraint);
42+
43+
$this->assertNoViolation();
44+
}
45+
46+
public static function getValidValues(): array
47+
{
48+
return [
49+
[0],
50+
['0'],
51+
[1.5],
52+
['1.5'],
53+
['12345'],
54+
];
55+
}
56+
57+
/**
58+
* @dataProvider getInvalidValues
59+
*/
60+
public function testInvalidValues(mixed $value, string $valueAsString)
61+
{
62+
$constraint = new Finite([
63+
'message' => 'myMessage',
64+
]);
65+
66+
$this->validator->validate($value, $constraint);
67+
68+
$this->buildViolation('myMessage')
69+
->setParameter('{{ value }}', $valueAsString)
70+
->setCode(Finite::NOT_FINITE_ERROR)
71+
->assertRaised();
72+
}
73+
74+
public static function getInvalidValues(): array
75+
{
76+
return [
77+
[\NAN, 'NAN'],
78+
[\INF, 'INF'],
79+
['', '""'],
80+
['foo', '"foo"'],
81+
];
82+
}
83+
}

0 commit comments

Comments
 (0)
0