Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit f550c97

Browse files
authored
Merge pull request #11 from programmatordev/YAPV-9-create-range-rule
Create Range rule
2 parents c7ec104 + 6e6e5e3 commit f550c97

File tree

4 files changed

+112
-6
lines changed

4 files changed

+112
-6
lines changed

src/Rule/Choice.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,17 @@ public function assert(mixed $value, string $name): void
4343
);
4444
}
4545

46+
if (
47+
$this->multiple
48+
&& $this->minConstraint !== null
49+
&& $this->maxConstraint !== null
50+
&& $this->minConstraint > $this->maxConstraint
51+
) {
52+
throw new UnexpectedValueException(
53+
'Max constraint value must be greater than or equal to min constraint value.'
54+
);
55+
}
56+
4657
if ($this->multiple) {
4758
foreach ($value as $input) {
4859
if (!\in_array($input, $this->constraints, true)) {

src/Rule/Range.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace ProgrammatorDev\YetAnotherPhpValidator\Rule;
44

55
use ProgrammatorDev\YetAnotherPhpValidator\Exception\RangeException;
6+
use ProgrammatorDev\YetAnotherPhpValidator\Exception\UnexpectedValueException;
67
use ProgrammatorDev\YetAnotherPhpValidator\Rule\Util\AssertIsComparableTrait;
78
use ProgrammatorDev\YetAnotherPhpValidator\Validator;
89
use Symfony\Component\OptionsResolver\OptionsResolver;
@@ -22,7 +23,7 @@ public function __construct(
2223
$resolver = new OptionsResolver();
2324

2425
$resolver->setDefaults([
25-
'message' => 'The {{ name }} value should be between "{{ minConstraint }}" and "{{ maxConstraint }}", "{{ value }}" given.'
26+
'message' => 'The "{{ name }}" value should be between "{{ minConstraint }}" and "{{ maxConstraint }}", "{{ value }}" given.'
2627
]);
2728

2829
$resolver->setAllowedTypes('message', 'string');
@@ -34,7 +35,13 @@ public function assert(mixed $value, string $name): void
3435
{
3536
$this->assertIsComparable($this->minConstraint, $this->maxConstraint);
3637

37-
if (!Validator::greaterThan($this->minConstraint)->lessThan($this->maxConstraint)->validate($value)) {
38+
if (!Validator::greaterThan($this->minConstraint)->validate($this->maxConstraint)) {
39+
throw new UnexpectedValueException(
40+
'Max constraint value must be greater than min constraint value.'
41+
);
42+
}
43+
44+
if (!Validator::greaterThanOrEqual($this->minConstraint)->lessThanOrEqual($this->maxConstraint)->validate($value)) {
3845
throw new RangeException(
3946
message: $this->options['message'],
4047
parameters: [

tests/ChoiceTest.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,12 @@ class ChoiceTest extends AbstractTest
1818

1919
public static function provideRuleUnexpectedValueData(): \Generator
2020
{
21-
yield 'multiple but not array' => [
22-
new Choice([1, 2], true), 1, '/Expected value of type "array" when multiple, "(.*)" given/'
23-
];
21+
$constraints = [1, 2, 3, 4, 5];
22+
$multipleMessage = '/Expected value of type "array" when multiple, "(.*)" given/';
23+
$constraintMessage = '/Max constraint value must be greater than or equal to min constraint value./';
24+
25+
yield 'multiple not array' => [new Choice($constraints, true), 1, $multipleMessage];
26+
yield 'min greater than max constraint' => [new Choice($constraints, true, 3, 2), [1, 2], $constraintMessage];
2427
}
2528

2629
public static function provideRuleFailureConditionData(): \Generator
@@ -50,7 +53,8 @@ public static function provideRuleSuccessConditionData(): \Generator
5053
yield 'multiple valid choices' => [new Choice($constraints, true), [1, 2, 3]];
5154
yield 'min constraint' => [new Choice($constraints, true, 2), [1, 2]];
5255
yield 'max constraint' => [new Choice($constraints, true, null, 2), [1, 2]];
53-
yield 'min and max constraint' => [new Choice($constraints, true, 2, 2), [1, 2]];
56+
yield 'min and max constraint' => [new Choice($constraints, true, 2, 4), [1, 2, 3]];
57+
yield 'same min and max constraint' => [new Choice($constraints, true, 2, 2), [1, 2]];
5458
}
5559

5660
public static function provideRuleMessageOptionData(): \Generator

tests/RangeTest.php

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
namespace ProgrammatorDev\YetAnotherPhpValidator\Test;
4+
5+
use ProgrammatorDev\YetAnotherPhpValidator\Exception\RangeException;
6+
use ProgrammatorDev\YetAnotherPhpValidator\Rule\Range;
7+
use ProgrammatorDev\YetAnotherPhpValidator\Test\Util\TestRuleFailureConditionTrait;
8+
use ProgrammatorDev\YetAnotherPhpValidator\Test\Util\TestRuleMessageOptionTrait;
9+
use ProgrammatorDev\YetAnotherPhpValidator\Test\Util\TestRuleSuccessConditionTrait;
10+
use ProgrammatorDev\YetAnotherPhpValidator\Test\Util\TestRuleUnexpectedValueTrait;
11+
12+
class RangeTest extends AbstractTest
13+
{
14+
use TestRuleUnexpectedValueTrait;
15+
use TestRuleFailureConditionTrait;
16+
use TestRuleSuccessConditionTrait;
17+
use TestRuleMessageOptionTrait;
18+
19+
public static function provideRuleUnexpectedValueData(): \Generator
20+
{
21+
$comparableMessage = '/Cannot compare a type "(.*)" with a type "(.*)"/';
22+
$constraintMessage = '/Max constraint value must be greater than min constraint value./';
23+
24+
yield 'datetime constraint with int constraint' => [new Range(new \DateTime(), 10), new \DateTime(), $comparableMessage];
25+
yield 'datetime constraint with float constraint' => [new Range(new \DateTime(), 10.0), new \DateTime(), $comparableMessage];
26+
yield 'datetime constraint with string constraint' => [new Range(new \DateTime(), 'a'), new \DateTime(), $comparableMessage];
27+
yield 'int constraint with string constraint' => [new Range(10, 'a'), 10, $comparableMessage];
28+
yield 'float constraint with string constraint' => [new Range(1.0, 'a'), 1.0, $comparableMessage];
29+
yield 'array constraint' => [new Range([10], 10), 10, $comparableMessage];
30+
yield 'null constraint' => [new Range(null, 10), 10, $comparableMessage];
31+
32+
yield 'min greater than max constraint' => [new Range(10, 9), 10, $constraintMessage];
33+
yield 'same min and max constraint' => [new Range(10, 10), 10, $constraintMessage];
34+
}
35+
36+
public static function provideRuleFailureConditionData(): \Generator
37+
{
38+
$exception = RangeException::class;
39+
$message = '/The "(.*)" value should be between "(.*)" and "(.*)", "(.*)" given./';
40+
41+
yield 'min datetime' => [new Range(new \DateTime('today'), new \DateTime('tomorrow')), new \DateTime('yesterday'), $exception, $message];
42+
yield 'min int' => [new Range(10, 20), 1, $exception, $message];
43+
yield 'min float' => [new Range(10.0, 20.0), 1.0, $exception, $message];
44+
yield 'min int with float' => [new Range(10, 20), 1.0, $exception, $message];
45+
yield 'min string' => [new Range('b', 'z'), 'a', $exception, $message];
46+
yield 'max datetime' => [new Range(new \DateTime('today'), new \DateTime('tomorrow')), new \DateTime('+2 days'), $exception, $message];
47+
yield 'max int' => [new Range(10, 20), 30, $exception, $message];
48+
yield 'max float' => [new Range(10.0, 20.0), 30.0, $exception, $message];
49+
yield 'max int with float' => [new Range(10, 20), 30.0, $exception, $message];
50+
yield 'max string' => [new Range('a', 'y'), 'z', $exception, $message];
51+
}
52+
53+
public static function provideRuleSuccessConditionData(): \Generator
54+
{
55+
yield 'datetime' => [new Range(new \DateTime('today'), new \DateTime('tomorrow')), new \DateTime('+1 hour')];
56+
yield 'int' => [new Range(10, 20), 15];
57+
yield 'float' => [new Range(10.0, 20.0), 15.0];
58+
yield 'int with float' => [new Range(10, 20), 15.0];
59+
yield 'string' => [new Range('a', 'z'), 'b'];
60+
yield 'min datetime' => [new Range(new \DateTime('today'), new \DateTime('tomorrow')), new \DateTime('today')];
61+
yield 'min int' => [new Range(10, 20), 10];
62+
yield 'min float' => [new Range(10.0, 20.0), 10.0];
63+
yield 'min int with float' => [new Range(10, 20), 10.0];
64+
yield 'min string' => [new Range('a', 'z'), 'a'];
65+
yield 'max datetime' => [new Range(new \DateTime('today'), new \DateTime('tomorrow')), new \DateTime('tomorrow')];
66+
yield 'max int' => [new Range(10, 20), 20];
67+
yield 'max float' => [new Range(10.0, 20.0), 20.0];
68+
yield 'max int with float' => [new Range(10, 20), 20.0];
69+
yield 'max string' => [new Range('a', 'z'), 'z'];
70+
}
71+
72+
public static function provideRuleMessageOptionData(): \Generator
73+
{
74+
yield 'message' => [
75+
new Range(
76+
minConstraint: 10,
77+
maxConstraint: 20,
78+
options: [
79+
'message' => 'The "{{ name }}" value "{{ value }}" should be between "{{ minConstraint }}" and "{{ maxConstraint }}".'
80+
]
81+
), 30, 'The "test" value "30" should be between "10" and "20".'
82+
];
83+
}
84+
}

0 commit comments

Comments
 (0)