mirror of
https://github.com/Respect/Validation.git
synced 2024-06-15 12:05:30 +02:00
Recreate "Max" rule
The "Max" rule is not a transformation, validating the maximum value in the input against a given rule. Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
This commit is contained in:
parent
81befe8fa1
commit
cea77d2a46
|
@ -51,6 +51,7 @@
|
|||
- [In](rules/In.md)
|
||||
- [LessThan](rules/LessThan.md)
|
||||
- [LessThanOrEqual](rules/LessThanOrEqual.md)
|
||||
- [Max](rules/Max.md)
|
||||
- [Min](rules/Min.md)
|
||||
|
||||
## Composite
|
||||
|
@ -249,6 +250,7 @@
|
|||
|
||||
- [Call](rules/Call.md)
|
||||
- [Each](rules/Each.md)
|
||||
- [Max](rules/Max.md)
|
||||
- [Min](rules/Min.md)
|
||||
|
||||
## Types
|
||||
|
@ -359,6 +361,7 @@
|
|||
- [Lowercase](rules/Lowercase.md)
|
||||
- [Luhn](rules/Luhn.md)
|
||||
- [MacAddress](rules/MacAddress.md)
|
||||
- [Max](rules/Max.md)
|
||||
- [MaxAge](rules/MaxAge.md)
|
||||
- [Mimetype](rules/Mimetype.md)
|
||||
- [Min](rules/Min.md)
|
||||
|
|
|
@ -36,4 +36,5 @@ See also:
|
|||
- [Length](Length.md)
|
||||
- [LessThan](LessThan.md)
|
||||
- [LessThanOrEqual](LessThanOrEqual.md)
|
||||
- [Max](Max.md)
|
||||
- [Min](Min.md)
|
||||
|
|
|
@ -30,4 +30,5 @@ See also:
|
|||
- [Between](Between.md)
|
||||
- [GreaterThanOrEqual](GreaterThanOrEqual.md)
|
||||
- [LessThanOrEqual](LessThanOrEqual.md)
|
||||
- [Max](Max.md)
|
||||
- [Min](Min.md)
|
||||
|
|
|
@ -36,6 +36,7 @@ See also:
|
|||
- [Length](Length.md)
|
||||
- [LessThan](LessThan.md)
|
||||
- [LessThanOrEqual](LessThanOrEqual.md)
|
||||
- [Max](Max.md)
|
||||
- [MaxAge](MaxAge.md)
|
||||
- [Min](Min.md)
|
||||
- [MinAge](MinAge.md)
|
||||
|
|
|
@ -33,3 +33,4 @@ See also:
|
|||
- [Each](Each.md)
|
||||
- [Instance](Instance.md)
|
||||
- [IterableVal](IterableVal.md)
|
||||
- [Max](Max.md)
|
||||
|
|
|
@ -30,4 +30,5 @@ See also:
|
|||
- [Between](Between.md)
|
||||
- [GreaterThanOrEqual](GreaterThanOrEqual.md)
|
||||
- [LessThanOrEqual](LessThanOrEqual.md)
|
||||
- [Max](Max.md)
|
||||
- [Min](Min.md)
|
||||
|
|
|
@ -35,6 +35,7 @@ See also:
|
|||
- [GreaterThan](GreaterThan.md)
|
||||
- [GreaterThanOrEqual](GreaterThanOrEqual.md)
|
||||
- [LessThan](LessThan.md)
|
||||
- [Max](Max.md)
|
||||
- [MaxAge](MaxAge.md)
|
||||
- [Min](Min.md)
|
||||
- [MinAge](MinAge.md)
|
||||
|
|
47
docs/rules/Max.md
Normal file
47
docs/rules/Max.md
Normal file
|
@ -0,0 +1,47 @@
|
|||
# Max
|
||||
|
||||
- `Max(Validatable $rule)`
|
||||
|
||||
Validates the maximum value of the input against a given rule.
|
||||
|
||||
```php
|
||||
v::max(v::equals(30))->validate([10, 20, 30]); // true
|
||||
|
||||
v::max(v::between('e', 'g'))->validate(['b', 'd', 'f']); // true
|
||||
|
||||
v::max(v::greaterThan(new DateTime('today')))
|
||||
->validate([new DateTime('yesterday'), new DateTime('tomorrow')]); // true
|
||||
|
||||
v::max(v::greaterThan(15))->validate([4, 8, 12]); // false
|
||||
```
|
||||
|
||||
## Note
|
||||
|
||||
This rule uses [IterableType](IterableType.md) and [NotEmpty](NotEmpty.md) internally. If an input is non-iterable or
|
||||
empty, the validation will fail.
|
||||
|
||||
## Categorization
|
||||
|
||||
- Comparisons
|
||||
- Transformations
|
||||
|
||||
## Changelog
|
||||
|
||||
| Version | Description |
|
||||
|--------:|-----------------------------|
|
||||
| 3.0.0 | Became a transformation |
|
||||
| 2.0.0 | Became always inclusive |
|
||||
| 1.0.0 | Became inclusive by default |
|
||||
| 0.3.9 | Created |
|
||||
|
||||
***
|
||||
See also:
|
||||
|
||||
- [Between](Between.md)
|
||||
- [GreaterThan](GreaterThan.md)
|
||||
- [GreaterThanOrEqual](GreaterThanOrEqual.md)
|
||||
- [IterableType](IterableType.md)
|
||||
- [LessThan](LessThan.md)
|
||||
- [LessThanOrEqual](LessThanOrEqual.md)
|
||||
- [Min](Min.md)
|
||||
- [NotEmpty](NotEmpty.md)
|
|
@ -43,4 +43,5 @@ See also:
|
|||
- [GreaterThanOrEqual](GreaterThanOrEqual.md)
|
||||
- [LessThan](LessThan.md)
|
||||
- [LessThanOrEqual](LessThanOrEqual.md)
|
||||
- [Max](Max.md)
|
||||
- [NotEmpty](NotEmpty.md)
|
||||
|
|
|
@ -49,6 +49,7 @@ Version | Description
|
|||
See also:
|
||||
|
||||
- [Each](Each.md)
|
||||
- [Max](Max.md)
|
||||
- [Min](Min.md)
|
||||
- [NoWhitespace](NoWhitespace.md)
|
||||
- [NotBlank](NotBlank.md)
|
||||
|
|
|
@ -198,6 +198,8 @@ interface ChainedValidator extends Validatable
|
|||
|
||||
public function lessThanOrEqual(mixed $compareTo): ChainedValidator;
|
||||
|
||||
public function max(Validatable $rule): ChainedValidator;
|
||||
|
||||
public function maxAge(int $age, ?string $format = null): ChainedValidator;
|
||||
|
||||
public function min(Validatable $rule): ChainedValidator;
|
||||
|
|
32
library/Rules/Max.php
Normal file
32
library/Rules/Max.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Message\Template;
|
||||
use Respect\Validation\Result;
|
||||
use Respect\Validation\Rules\Core\FilteredNonEmptyArray;
|
||||
|
||||
use function max;
|
||||
|
||||
#[Template('As the maximum of {{name}},', 'As the maximum of {{name}},')]
|
||||
#[Template('The maximum of', 'The maximum of', self::TEMPLATE_NAMED)]
|
||||
final class Max extends FilteredNonEmptyArray
|
||||
{
|
||||
public const TEMPLATE_NAMED = '__named__';
|
||||
|
||||
/** @param non-empty-array<mixed> $input */
|
||||
protected function evaluateNonEmptyArray(array $input): Result
|
||||
{
|
||||
$result = $this->rule->evaluate(max($input));
|
||||
$template = $this->getName() === null ? self::TEMPLATE_STANDARD : self::TEMPLATE_NAMED;
|
||||
|
||||
return (new Result($result->isValid, $input, $this, [], $template))->withNextSibling($result);
|
||||
}
|
||||
}
|
|
@ -200,6 +200,8 @@ interface StaticValidator
|
|||
|
||||
public static function lessThanOrEqual(mixed $compareTo): ChainedValidator;
|
||||
|
||||
public static function max(Validatable $rule): ChainedValidator;
|
||||
|
||||
public static function maxAge(int $age, ?string $format = null): ChainedValidator;
|
||||
|
||||
public static function min(Validatable $rule): ChainedValidator;
|
||||
|
|
100
tests/integration/rules/max.phpt
Normal file
100
tests/integration/rules/max.phpt
Normal file
|
@ -0,0 +1,100 @@
|
|||
--FILE--
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
use Respect\Validation\Validator as v;
|
||||
|
||||
$empty = [];
|
||||
$nonIterable = null;
|
||||
$default = [1, 2, 3];
|
||||
$negative = [-3, -2, -1];
|
||||
|
||||
|
||||
run([
|
||||
// Simple
|
||||
'Non-iterable' => [v::max(v::negative()), $nonIterable],
|
||||
'Empty' => [v::max(v::negative()), $empty],
|
||||
'Default' => [v::max(v::negative()), $default],
|
||||
'Negative' => [v::not(v::max(v::negative())), $negative],
|
||||
'With wrapped name, default' => [v::max(v::negative()->setName('Wrapped'))->setName('Wrapper'), $default],
|
||||
'With wrapper name, default' => [v::max(v::negative())->setName('Wrapper'), $default],
|
||||
'With wrapped name, negative' => [v::not(v::max(v::negative()->setName('Wrapped')))->setName('Wrapper'), $negative],
|
||||
'With wrapper name, negative' => [v::not(v::max(v::negative()))->setName('Wrapper'), $negative],
|
||||
'With template, default' => [v::max(v::negative()), $default, 'The maximum of the value is not what we expect'],
|
||||
]);
|
||||
?>
|
||||
--EXPECT--
|
||||
Non-iterable
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
`null` must be of type iterable
|
||||
- `null` must be of type iterable
|
||||
[
|
||||
'max' => '`null` must be of type iterable',
|
||||
]
|
||||
|
||||
Empty
|
||||
⎺⎺⎺⎺⎺
|
||||
The value must not be empty
|
||||
- The value must not be empty
|
||||
[
|
||||
'max' => 'The value must not be empty',
|
||||
]
|
||||
|
||||
Default
|
||||
⎺⎺⎺⎺⎺⎺⎺
|
||||
As the maximum of `[1, 2, 3]`, 3 must be negative
|
||||
- As the maximum of `[1, 2, 3]`, 3 must be negative
|
||||
[
|
||||
'max' => 'As the maximum of `[1, 2, 3]`, 3 must be negative',
|
||||
]
|
||||
|
||||
Negative
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
As the maximum of `[-3, -2, -1]`, -1 must not be negative
|
||||
- As the maximum of `[-3, -2, -1]`, -1 must not be negative
|
||||
[
|
||||
'max' => 'As the maximum of `[-3, -2, -1]`, -1 must not be negative',
|
||||
]
|
||||
|
||||
With wrapped name, default
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
The maximum of Wrapped must be negative
|
||||
- The maximum of Wrapped must be negative
|
||||
[
|
||||
'Wrapped' => 'The maximum of Wrapped must be negative',
|
||||
]
|
||||
|
||||
With wrapper name, default
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
The maximum of Wrapper must be negative
|
||||
- The maximum of Wrapper must be negative
|
||||
[
|
||||
'Wrapper' => 'The maximum of Wrapper must be negative',
|
||||
]
|
||||
|
||||
With wrapped name, negative
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
The maximum of Wrapped must not be negative
|
||||
- The maximum of Wrapped must not be negative
|
||||
[
|
||||
'Wrapped' => 'The maximum of Wrapped must not be negative',
|
||||
]
|
||||
|
||||
With wrapper name, negative
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
The maximum of Wrapper must not be negative
|
||||
- The maximum of Wrapper must not be negative
|
||||
[
|
||||
'Wrapper' => 'The maximum of Wrapper must not be negative',
|
||||
]
|
||||
|
||||
With template, default
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
The maximum of the value is not what we expect
|
||||
- The maximum of the value is not what we expect
|
||||
[
|
||||
'max' => 'The maximum of the value is not what we expect',
|
||||
]
|
85
tests/unit/Rules/MaxTest.php
Normal file
85
tests/unit/Rules/MaxTest.php
Normal file
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use Respect\Validation\Test\Rules\Stub;
|
||||
use Respect\Validation\Test\TestCase;
|
||||
|
||||
#[Group('rule')]
|
||||
#[CoversClass(Max::class)]
|
||||
final class MaxTest extends TestCase
|
||||
{
|
||||
#[Test]
|
||||
#[DataProvider('providerForNonIterableValues')]
|
||||
public function itShouldInvalidateNonIterableValues(mixed $input): void
|
||||
{
|
||||
$rule = new Max(Stub::daze());
|
||||
|
||||
self::assertInvalidInput($rule, $input);
|
||||
}
|
||||
|
||||
/** @param iterable<mixed> $input */
|
||||
#[Test]
|
||||
#[DataProvider('providerForEmptyIterableValues')]
|
||||
public function itShouldInvalidateEmptyIterableValues(iterable $input): void
|
||||
{
|
||||
$rule = new Max(Stub::daze());
|
||||
|
||||
self::assertInvalidInput($rule, $input);
|
||||
}
|
||||
|
||||
/** @param iterable<mixed> $input */
|
||||
#[Test]
|
||||
#[DataProvider('providerForNonEmptyIterableValues')]
|
||||
public function itShouldValidateNonEmptyIterableValuesWhenWrappedRulePasses(iterable $input): void
|
||||
{
|
||||
$rule = new Max(Stub::pass(1));
|
||||
|
||||
self::assertValidInput($rule, $input);
|
||||
}
|
||||
|
||||
/** @param iterable<mixed> $input */
|
||||
#[Test]
|
||||
#[DataProvider('providerForMaxValues')]
|
||||
public function itShouldValidateWithTheMaximumValue(iterable $input, mixed $min): void
|
||||
{
|
||||
$wrapped = Stub::pass(1);
|
||||
|
||||
$rule = new Max($wrapped);
|
||||
$rule->evaluate($input);
|
||||
|
||||
self::assertSame($min, $wrapped->inputs[0]);
|
||||
}
|
||||
|
||||
/** @return array<string, array{iterable<mixed>, mixed}> */
|
||||
public static function providerForMaxValues(): array
|
||||
{
|
||||
$yesterday = new DateTimeImmutable('yesterday');
|
||||
$today = new DateTimeImmutable('today');
|
||||
$tomorrow = new DateTimeImmutable('tomorrow');
|
||||
|
||||
return [
|
||||
'3 DateTime objects' => [[$yesterday, $today, $tomorrow], $tomorrow],
|
||||
'2 DateTime objects' => [[$yesterday, $today], $today],
|
||||
'1 DateTime objects' => [[$yesterday], $yesterday],
|
||||
'3 integers' => [[1, 2, 3], 3],
|
||||
'2 integers' => [[1, 2], 2],
|
||||
'1 integer' => [[1], 1],
|
||||
'3 characters' => [['a', 'b', 'c'], 'c'],
|
||||
'2 characters' => [['a', 'b'], 'b'],
|
||||
'1 character' => [['a'], 'a'],
|
||||
];
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue