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

Commit d83639b

Browse files
committed
feat: added compatibility with string date-time formats in compatibility rules
1 parent 1868f88 commit d83639b

14 files changed

Lines changed: 121 additions & 61 deletions

src/Rule/All.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
use ProgrammatorDev\YetAnotherPhpValidator\Exception\AllException;
66
use ProgrammatorDev\YetAnotherPhpValidator\Exception\UnexpectedValueException;
77
use ProgrammatorDev\YetAnotherPhpValidator\Exception\ValidationException;
8-
use ProgrammatorDev\YetAnotherPhpValidator\Rule\Util\IsValidatableTrait;
8+
use ProgrammatorDev\YetAnotherPhpValidator\Rule\Util\ValidatableTrait;
99
use Symfony\Component\OptionsResolver\OptionsResolver;
1010

1111
class All extends AbstractRule implements RuleInterface
1212
{
13-
use IsValidatableTrait;
13+
use ValidatableTrait;
1414

1515
private array $options;
1616

src/Rule/GreaterThan.php

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44

55
use ProgrammatorDev\YetAnotherPhpValidator\Exception\GreaterThanException;
66
use ProgrammatorDev\YetAnotherPhpValidator\Exception\UnexpectedComparableException;
7-
use ProgrammatorDev\YetAnotherPhpValidator\Rule\Util\IsComparableTrait;
7+
use ProgrammatorDev\YetAnotherPhpValidator\Rule\Util\ComparableTrait;
88
use Symfony\Component\OptionsResolver\OptionsResolver;
99

1010
class GreaterThan extends AbstractRule implements RuleInterface
1111
{
12-
use IsComparableTrait;
12+
use ComparableTrait;
1313

1414
private array $options;
1515

@@ -29,20 +29,23 @@ public function __construct(private readonly mixed $constraint, array $options =
2929
*/
3030
public function assert(mixed $value, string $name): void
3131
{
32-
if (!$this->isComparable($this->constraint, $value)) {
32+
$constraint = $this->convertToComparable($this->constraint);
33+
$value = $this->convertToComparable($value);
34+
35+
if (!$this->isComparable($constraint, $value)) {
3336
throw new UnexpectedComparableException(
34-
get_debug_type($this->constraint),
37+
get_debug_type($constraint),
3538
get_debug_type($value)
3639
);
3740
}
3841

39-
if (!($value > $this->constraint)) {
42+
if (!($value > $constraint)) {
4043
throw new GreaterThanException(
4144
message: $this->options['message'],
4245
parameters: [
4346
'value' => $value,
4447
'name' => $name,
45-
'constraint' => $this->constraint
48+
'constraint' => $constraint
4649
]
4750
);
4851
}

src/Rule/GreaterThanOrEqual.php

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
use ProgrammatorDev\YetAnotherPhpValidator\Exception\GreaterThanException;
66
use ProgrammatorDev\YetAnotherPhpValidator\Exception\GreaterThanOrEqualException;
77
use ProgrammatorDev\YetAnotherPhpValidator\Exception\UnexpectedComparableException;
8-
use ProgrammatorDev\YetAnotherPhpValidator\Rule\Util\IsComparableTrait;
8+
use ProgrammatorDev\YetAnotherPhpValidator\Rule\Util\ComparableTrait;
99
use Symfony\Component\OptionsResolver\OptionsResolver;
1010

1111
class GreaterThanOrEqual extends AbstractRule implements RuleInterface
1212
{
13-
use IsComparableTrait;
13+
use ComparableTrait;
1414

1515
private array $options;
1616

@@ -30,20 +30,23 @@ public function __construct(private readonly mixed $constraint, array $options =
3030
*/
3131
public function assert(mixed $value, string $name): void
3232
{
33-
if (!$this->isComparable($this->constraint, $value)) {
33+
$constraint = $this->convertToComparable($this->constraint);
34+
$value = $this->convertToComparable($value);
35+
36+
if (!$this->isComparable($constraint, $value)) {
3437
throw new UnexpectedComparableException(
35-
get_debug_type($this->constraint),
38+
get_debug_type($constraint),
3639
get_debug_type($value)
3740
);
3841
}
3942

40-
if (!($value >= $this->constraint)) {
43+
if (!($value >= $constraint)) {
4144
throw new GreaterThanOrEqualException(
4245
message: $this->options['message'],
4346
parameters: [
4447
'value' => $value,
4548
'name' => $name,
46-
'constraint' => $this->constraint
49+
'constraint' => $constraint
4750
]
4851
);
4952
}

src/Rule/LessThan.php

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44

55
use ProgrammatorDev\YetAnotherPhpValidator\Exception\LessThanException;
66
use ProgrammatorDev\YetAnotherPhpValidator\Exception\UnexpectedComparableException;
7-
use ProgrammatorDev\YetAnotherPhpValidator\Rule\Util\IsComparableTrait;
7+
use ProgrammatorDev\YetAnotherPhpValidator\Rule\Util\ComparableTrait;
88
use Symfony\Component\OptionsResolver\OptionsResolver;
99

1010
class LessThan extends AbstractRule implements RuleInterface
1111
{
12-
use IsComparableTrait;
12+
use ComparableTrait;
1313

1414
private array $options;
1515

@@ -29,20 +29,23 @@ public function __construct(private readonly mixed $constraint, array $options =
2929
*/
3030
public function assert(mixed $value, string $name): void
3131
{
32-
if (!$this->isComparable($this->constraint, $value)) {
32+
$constraint = $this->convertToComparable($this->constraint);
33+
$value = $this->convertToComparable($value);
34+
35+
if (!$this->isComparable($constraint, $value)) {
3336
throw new UnexpectedComparableException(
34-
get_debug_type($this->constraint),
37+
get_debug_type($constraint),
3538
get_debug_type($value)
3639
);
3740
}
3841

39-
if (!($value < $this->constraint)) {
42+
if (!($value < $constraint)) {
4043
throw new LessThanException(
4144
message: $this->options['message'],
4245
parameters: [
4346
'value' => $value,
4447
'name' => $name,
45-
'constraint' => $this->constraint
48+
'constraint' => $constraint
4649
]
4750
);
4851
}

src/Rule/LessThanOrEqual.php

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44

55
use ProgrammatorDev\YetAnotherPhpValidator\Exception\LessThanOrEqualException;
66
use ProgrammatorDev\YetAnotherPhpValidator\Exception\UnexpectedComparableException;
7-
use ProgrammatorDev\YetAnotherPhpValidator\Rule\Util\IsComparableTrait;
7+
use ProgrammatorDev\YetAnotherPhpValidator\Rule\Util\ComparableTrait;
88
use Symfony\Component\OptionsResolver\OptionsResolver;
99

1010
class LessThanOrEqual extends AbstractRule implements RuleInterface
1111
{
12-
use IsComparableTrait;
12+
use ComparableTrait;
1313

1414
private array $options;
1515

@@ -29,20 +29,23 @@ public function __construct(private readonly mixed $constraint, array $options =
2929
*/
3030
public function assert(mixed $value, string $name): void
3131
{
32-
if (!$this->isComparable($this->constraint, $value)) {
32+
$constraint = $this->convertToComparable($this->constraint);
33+
$value = $this->convertToComparable($value);
34+
35+
if (!$this->isComparable($constraint, $value)) {
3336
throw new UnexpectedComparableException(
34-
get_debug_type($this->constraint),
37+
get_debug_type($constraint),
3538
get_debug_type($value)
3639
);
3740
}
3841

39-
if (!($value <= $this->constraint)) {
42+
if (!($value <= $constraint)) {
4043
throw new LessThanOrEqualException(
4144
message: $this->options['message'],
4245
parameters: [
4346
'value' => $value,
4447
'name' => $name,
45-
'constraint' => $this->constraint
48+
'constraint' => $constraint
4649
]
4750
);
4851
}

src/Rule/Range.php

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
use ProgrammatorDev\YetAnotherPhpValidator\Exception\RangeException;
66
use ProgrammatorDev\YetAnotherPhpValidator\Exception\UnexpectedComparableException;
77
use ProgrammatorDev\YetAnotherPhpValidator\Exception\UnexpectedValueException;
8-
use ProgrammatorDev\YetAnotherPhpValidator\Rule\Util\IsComparableTrait;
8+
use ProgrammatorDev\YetAnotherPhpValidator\Rule\Util\ComparableTrait;
99
use ProgrammatorDev\YetAnotherPhpValidator\Validator;
1010
use Symfony\Component\OptionsResolver\OptionsResolver;
1111

1212
class Range extends AbstractRule implements RuleInterface
1313
{
14-
use IsComparableTrait;
14+
use ComparableTrait;
1515

1616
private array $options;
1717

@@ -32,17 +32,21 @@ public function __construct(
3232

3333
public function assert(mixed $value, string $name): void
3434
{
35-
if (!$this->isComparable($this->minConstraint, $this->maxConstraint)) {
35+
$minConstraint = $this->convertToComparable($this->minConstraint);
36+
$maxConstraint = $this->convertToComparable($this->maxConstraint);
37+
$value = $this->convertToComparable($value);
38+
39+
if (!$this->isComparable($minConstraint, $maxConstraint)) {
3640
throw new UnexpectedComparableException(
37-
get_debug_type($this->minConstraint),
38-
get_debug_type($this->maxConstraint)
41+
get_debug_type($minConstraint),
42+
get_debug_type($maxConstraint)
3943
);
4044
}
4145

4246
if (
4347
!Validator
44-
::greaterThan($this->minConstraint)
45-
->validate($this->maxConstraint)
48+
::greaterThan($minConstraint)
49+
->validate($maxConstraint)
4650
) {
4751
throw new UnexpectedValueException(
4852
'Max constraint value must be greater than min constraint value.'
@@ -51,17 +55,17 @@ public function assert(mixed $value, string $name): void
5155

5256
if (
5357
!Validator
54-
::greaterThanOrEqual($this->minConstraint)
55-
->lessThanOrEqual($this->maxConstraint)
58+
::greaterThanOrEqual($minConstraint)
59+
->lessThanOrEqual($maxConstraint)
5660
->validate($value)
5761
) {
5862
throw new RangeException(
5963
message: $this->options['message'],
6064
parameters: [
6165
'value' => $value,
6266
'name' => $name,
63-
'minConstraint' => $this->minConstraint,
64-
'maxConstraint' => $this->maxConstraint
67+
'minConstraint' => $minConstraint,
68+
'maxConstraint' => $maxConstraint
6569
]
6670
);
6771
}

src/Rule/Util/ComparableTrait.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
namespace ProgrammatorDev\YetAnotherPhpValidator\Rule\Util;
4+
5+
trait ComparableTrait
6+
{
7+
private function isComparable(mixed $value1, mixed $value2): bool
8+
{
9+
if ($value1 instanceof \DateTimeInterface && $value2 instanceof \DateTimeInterface) {
10+
return true;
11+
}
12+
13+
if (\is_numeric($value1) && \is_numeric($value2)) {
14+
return true;
15+
}
16+
17+
if (\is_string($value1) && \is_string($value2)) {
18+
return true;
19+
}
20+
21+
return false;
22+
}
23+
24+
private function convertToComparable(mixed $value): mixed
25+
{
26+
if (\is_string($value)) {
27+
// If is string and has only one char,
28+
// return value to avoid conflicting with DateTime formats
29+
if (mb_strlen($value) === 1) {
30+
return $value;
31+
}
32+
33+
// Guess if is a DateTime string and convert
34+
// (like "yesterday" or "1985-07-19")
35+
try {
36+
return new \DateTimeImmutable($value);
37+
}
38+
catch (\Exception) {
39+
return $value;
40+
}
41+
}
42+
43+
return $value;
44+
}
45+
}

src/Rule/Util/IsComparableTrait.php

Lines changed: 0 additions & 23 deletions
This file was deleted.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use ProgrammatorDev\YetAnotherPhpValidator\Exception\UnexpectedValueException;
66
use ProgrammatorDev\YetAnotherPhpValidator\Rule\RuleInterface;
77

8-
trait IsValidatableTrait
8+
trait ValidatableTrait
99
{
1010
private function isValidatable(array $constraints): bool
1111
{

tests/GreaterThanOrEqualTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public static function provideRuleUnexpectedValueData(): \Generator
2323
yield 'datetime constraint with int value' => [new GreaterThanOrEqual(new \DateTime()), 10, $message];
2424
yield 'datetime constraint with float value' => [new GreaterThanOrEqual(new \DateTime()), 1.0, $message];
2525
yield 'datetime constraint with string value' => [new GreaterThanOrEqual(new \DateTime()), 'a', $message];
26+
yield 'datetime string constraint with string value' => [new GreaterThanOrEqual('now'), 'a', $message];
2627
yield 'int constraint with string value' => [new GreaterThanOrEqual(10), 'a', $message];
2728
yield 'float constraint with string value' => [new GreaterThanOrEqual(1.0), 'a', $message];
2829
yield 'array constraint' => [new GreaterThanOrEqual([10]), 10, $message];
@@ -35,6 +36,7 @@ public static function provideRuleFailureConditionData(): \Generator
3536
$message = '/The "(.*)" value should be greater than or equal to "(.*)", "(.*)" given./';
3637

3738
yield 'datetime' => [new GreaterThanOrEqual(new \DateTime('today')), new \DateTime('yesterday'), $exception, $message];
39+
yield 'datetime string' => [new GreaterThanOrEqual('today'), 'yesterday', $exception, $message];
3840
yield 'int' => [new GreaterThanOrEqual(10), 1, $exception, $message];
3941
yield 'float' => [new GreaterThanOrEqual(10.0), 1.0, $exception, $message];
4042
yield 'int with float' => [new GreaterThanOrEqual(10), 1.0, $exception, $message];
@@ -45,6 +47,8 @@ public static function provideRuleSuccessConditionData(): \Generator
4547
{
4648
yield 'datetime' => [new GreaterThanOrEqual(new \DateTime('today')), new \DateTime('tomorrow')];
4749
yield 'same datetime' => [new GreaterThanOrEqual(new \DateTime('today')), new \DateTime('today')];
50+
yield 'datetime string' => [new GreaterThanOrEqual('today'), 'tomorrow'];
51+
yield 'same datetime string' => [new GreaterThanOrEqual('today'), 'today'];
4852
yield 'int' => [new GreaterThanOrEqual(10), 20];
4953
yield 'same int' => [new GreaterThanOrEqual(10), 10];
5054
yield 'float' => [new GreaterThanOrEqual(10.0), 20.0];

0 commit comments

Comments
 (0)