mirror of
https://github.com/Respect/Validation.git
synced 2024-06-08 00:32:16 +02:00
Replace "LazyConsecutive" with "Consecutive"
With this and the Lazy rule, the LazyConsecutive lost its purpose. While working on it, I did refactor the Domain rule a bit, but mainly to check how this rule could behave. Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
This commit is contained in:
parent
78715fb844
commit
2610a380dc
|
@ -40,7 +40,6 @@
|
|||
- [CallableType](rules/CallableType.md)
|
||||
- [Callback](rules/Callback.md)
|
||||
- [Lazy](rules/Lazy.md)
|
||||
- [LazyConsecutive](rules/LazyConsecutive.md)
|
||||
|
||||
## Comparisons
|
||||
|
||||
|
@ -60,12 +59,13 @@
|
|||
|
||||
- [AllOf](rules/AllOf.md)
|
||||
- [AnyOf](rules/AnyOf.md)
|
||||
- [LazyConsecutive](rules/LazyConsecutive.md)
|
||||
- [Consecutive](rules/Consecutive.md)
|
||||
- [NoneOf](rules/NoneOf.md)
|
||||
- [OneOf](rules/OneOf.md)
|
||||
|
||||
## Conditions
|
||||
|
||||
- [Consecutive](rules/Consecutive.md)
|
||||
- [Not](rules/Not.md)
|
||||
- [When](rules/When.md)
|
||||
|
||||
|
@ -161,11 +161,11 @@
|
|||
- [AllOf](rules/AllOf.md)
|
||||
- [AnyOf](rules/AnyOf.md)
|
||||
- [Call](rules/Call.md)
|
||||
- [Consecutive](rules/Consecutive.md)
|
||||
- [Each](rules/Each.md)
|
||||
- [Key](rules/Key.md)
|
||||
- [KeySet](rules/KeySet.md)
|
||||
- [Lazy](rules/Lazy.md)
|
||||
- [LazyConsecutive](rules/LazyConsecutive.md)
|
||||
- [NoneOf](rules/NoneOf.md)
|
||||
- [Not](rules/Not.md)
|
||||
- [Nullable](rules/Nullable.md)
|
||||
|
@ -306,6 +306,7 @@
|
|||
- [Charset](rules/Charset.md)
|
||||
- [Cnh](rules/Cnh.md)
|
||||
- [Cnpj](rules/Cnpj.md)
|
||||
- [Consecutive](rules/Consecutive.md)
|
||||
- [Consonant](rules/Consonant.md)
|
||||
- [Contains](rules/Contains.md)
|
||||
- [ContainsAny](rules/ContainsAny.md)
|
||||
|
@ -362,7 +363,6 @@
|
|||
- [KeySet](rules/KeySet.md)
|
||||
- [LanguageCode](rules/LanguageCode.md)
|
||||
- [Lazy](rules/Lazy.md)
|
||||
- [LazyConsecutive](rules/LazyConsecutive.md)
|
||||
- [LeapDate](rules/LeapDate.md)
|
||||
- [LeapYear](rules/LeapYear.md)
|
||||
- [Length](rules/Length.md)
|
||||
|
|
|
@ -24,7 +24,7 @@ Version | Description
|
|||
See also:
|
||||
|
||||
- [AnyOf](AnyOf.md)
|
||||
- [LazyConsecutive](LazyConsecutive.md)
|
||||
- [Consecutive](Consecutive.md)
|
||||
- [NoneOf](NoneOf.md)
|
||||
- [OneOf](OneOf.md)
|
||||
- [When](When.md)
|
||||
|
|
|
@ -29,8 +29,8 @@ Version | Description
|
|||
See also:
|
||||
|
||||
- [AllOf](AllOf.md)
|
||||
- [Consecutive](Consecutive.md)
|
||||
- [ContainsAny](ContainsAny.md)
|
||||
- [LazyConsecutive](LazyConsecutive.md)
|
||||
- [NoneOf](NoneOf.md)
|
||||
- [OneOf](OneOf.md)
|
||||
- [When](When.md)
|
||||
|
|
|
@ -59,5 +59,4 @@ See also:
|
|||
- [Callback](Callback.md)
|
||||
- [Each](Each.md)
|
||||
- [Lazy](Lazy.md)
|
||||
- [LazyConsecutive](LazyConsecutive.md)
|
||||
- [Sorted](Sorted.md)
|
||||
|
|
44
docs/rules/Consecutive.md
Normal file
44
docs/rules/Consecutive.md
Normal file
|
@ -0,0 +1,44 @@
|
|||
# Consecutive
|
||||
|
||||
- `Consecutive(Validatable $rule1, Validatable $rule2, Validatable ...$rule)`
|
||||
|
||||
Validates the input against a series of rules until one fails.
|
||||
|
||||
This rule can be handy for getting the least error messages possible from a chain.
|
||||
|
||||
This rule can be helpful in combinations with [Lazy](Lazy.md). An excellent example is when you want to validate a
|
||||
country code and a subdivision code.
|
||||
|
||||
```php
|
||||
v::consecutive(
|
||||
v::key('countryCode', v::countryCode()),
|
||||
v::lazy(static fn($input) => v::key('subdivisionCode', v::subdivisionCode($input['countryCode']))),
|
||||
)->validate($_POST);
|
||||
```
|
||||
|
||||
You need a valid country code to create a [SubdivisionCode](SubdivisionCode.md), so it makes sense only to validate the
|
||||
subdivision code only if the country code is valid. In this case, you could also have used [When](When.md), but you
|
||||
would then have to write `v::key('countryCode', v::countryCode())` twice in your chain.
|
||||
|
||||
## Categorization
|
||||
|
||||
- Composite
|
||||
- Conditions
|
||||
- Nesting
|
||||
|
||||
## Changelog
|
||||
|
||||
| Version | Description |
|
||||
|--------:|-------------|
|
||||
| 3.0.0 | Created |
|
||||
|
||||
***
|
||||
See also:
|
||||
|
||||
- [AllOf](AllOf.md)
|
||||
- [AnyOf](AnyOf.md)
|
||||
- [Lazy](Lazy.md)
|
||||
- [NoneOf](NoneOf.md)
|
||||
- [OneOf](OneOf.md)
|
||||
- [SubdivisionCode](SubdivisionCode.md)
|
||||
- [When](When.md)
|
|
@ -27,5 +27,4 @@ See also:
|
|||
- [Contains](Contains.md)
|
||||
- [Equivalent](Equivalent.md)
|
||||
- [Identical](Identical.md)
|
||||
- [LazyConsecutive](LazyConsecutive.md)
|
||||
- [Version](Version.md)
|
||||
|
|
|
@ -39,3 +39,4 @@ See also:
|
|||
|
||||
- [Call](Call.md)
|
||||
- [CallableType](CallableType.md)
|
||||
- [Consecutive](Consecutive.md)
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
# LazyConsecutive
|
||||
|
||||
- `LazyConsecutive(callable(mixed $input): Validatable ...$ruleCreators)`
|
||||
|
||||
This executes a series of callbacks that create rules. Those callbacks accept the input as an argument and must return
|
||||
an instance of `Validatable`.
|
||||
|
||||
This is particularly useful when the creation of rules would rely on the input itself. A good example is validating
|
||||
whether a `password_confirmation` field matches the `password` field when processing data from a form.
|
||||
|
||||
```php
|
||||
v::key('password', v::notEmpty())->validate($_POST);
|
||||
v::key('password_confirmation', v::equals($_POST['password'] ?? null))->validate($_POST);
|
||||
```
|
||||
|
||||
The problem with the above code is that you do not know if the `password` is a valid key, so you must check it manually
|
||||
before performing the validation on `password_confirmation`. Besides, it could make it harder to reuse the validator.
|
||||
|
||||
The `lazyConsecutive()` rule makes this job much simpler and more elegantly:
|
||||
|
||||
```php
|
||||
v::lazyConsecutive(
|
||||
static fn() => v::key('password', v::stringType()->notEmpty()),
|
||||
static fn($input) => v::key('password_confirmation', v::equals($input['password'])),
|
||||
)->validate($_POST);
|
||||
```
|
||||
|
||||
The return of the above code will be `true` if `$_POST['password_confirmation']` [equals](Equals.md)
|
||||
`$_POST['password']`. The `lazyConsecutive()` rule will only execute the second callable if the rule from the first
|
||||
callable passes.
|
||||
|
||||
Another typical example is validating country and subdivision codes:
|
||||
|
||||
```php
|
||||
v::lazyConsecutive(
|
||||
static fn() => v::key('countryCode', v::countryCode()),
|
||||
static fn($input) => v::key('subdivisionCode', v::subdivisionCode($input['countryCode'])),
|
||||
)->validate($_POST);
|
||||
```
|
||||
|
||||
The return of the above code will be `true` if `$_POST['subdivisionCode']` is a [subdivision code](SubdivisionCode.md)
|
||||
of `$_POST['countryCode']`.
|
||||
|
||||
## Categorization
|
||||
|
||||
- Callables
|
||||
- Composite
|
||||
- Nesting
|
||||
|
||||
## Changelog
|
||||
|
||||
| Version | Description |
|
||||
| ------: | ----------- |
|
||||
| 3.0.0 | Created |
|
||||
|
||||
***
|
||||
See also:
|
||||
|
||||
- [AllOf](AllOf.md)
|
||||
- [AnyOf](AnyOf.md)
|
||||
- [Call](Call.md)
|
||||
- [Equals](Equals.md)
|
||||
- [NoneOf](NoneOf.md)
|
||||
- [OneOf](OneOf.md)
|
||||
- [SubdivisionCode](SubdivisionCode.md)
|
|
@ -30,7 +30,7 @@ See also:
|
|||
|
||||
- [AllOf](AllOf.md)
|
||||
- [AnyOf](AnyOf.md)
|
||||
- [LazyConsecutive](LazyConsecutive.md)
|
||||
- [Consecutive](Consecutive.md)
|
||||
- [Not](Not.md)
|
||||
- [OneOf](OneOf.md)
|
||||
- [When](When.md)
|
||||
|
|
|
@ -31,6 +31,6 @@ See also:
|
|||
|
||||
- [AllOf](AllOf.md)
|
||||
- [AnyOf](AnyOf.md)
|
||||
- [LazyConsecutive](LazyConsecutive.md)
|
||||
- [Consecutive](Consecutive.md)
|
||||
- [NoneOf](NoneOf.md)
|
||||
- [When](When.md)
|
||||
|
|
|
@ -28,9 +28,9 @@ Version | Description
|
|||
***
|
||||
See also:
|
||||
|
||||
- [Consecutive](Consecutive.md)
|
||||
- [CountryCode](CountryCode.md)
|
||||
- [CurrencyCode](CurrencyCode.md)
|
||||
- [LazyConsecutive](LazyConsecutive.md)
|
||||
- [Nip](Nip.md)
|
||||
- [Pesel](Pesel.md)
|
||||
- [PolishIdCard](PolishIdCard.md)
|
||||
|
|
|
@ -38,5 +38,6 @@ See also:
|
|||
- [AllOf](AllOf.md)
|
||||
- [AlwaysInvalid](AlwaysInvalid.md)
|
||||
- [AnyOf](AnyOf.md)
|
||||
- [Consecutive](Consecutive.md)
|
||||
- [NoneOf](NoneOf.md)
|
||||
- [OneOf](OneOf.md)
|
||||
|
|
|
@ -60,6 +60,8 @@ interface ChainedValidator extends Validatable
|
|||
|
||||
public function cnpj(): ChainedValidator;
|
||||
|
||||
public function consecutive(Validatable $rule1, Validatable $rule2, Validatable ...$rule): ChainedValidator;
|
||||
|
||||
public function control(string ...$additionalChars): ChainedValidator;
|
||||
|
||||
public function consonant(string ...$additionalChars): ChainedValidator;
|
||||
|
@ -175,8 +177,6 @@ interface ChainedValidator extends Validatable
|
|||
/** @param callable(mixed): Validatable $ruleCreator */
|
||||
public function lazy(callable $ruleCreator): ChainedValidator;
|
||||
|
||||
public function lazyConsecutive(callable $ruleCreator, callable ...$ruleCreators): ChainedValidator;
|
||||
|
||||
/** @param "alpha-2"|"alpha-3" $set */
|
||||
public function languageCode(string $set = 'alpha-2'): ChainedValidator;
|
||||
|
||||
|
|
|
@ -62,6 +62,8 @@ interface StaticValidator
|
|||
|
||||
public static function cnpj(): ChainedValidator;
|
||||
|
||||
public static function consecutive(Validatable $rule1, Validatable $rule2, Validatable ...$rule): ChainedValidator;
|
||||
|
||||
public static function control(string ...$additionalChars): ChainedValidator;
|
||||
|
||||
public static function consonant(string ...$additionalChars): ChainedValidator;
|
||||
|
@ -177,8 +179,6 @@ interface StaticValidator
|
|||
/** @param callable(mixed): Validatable $ruleCreator */
|
||||
public static function lazy(callable $ruleCreator): ChainedValidator;
|
||||
|
||||
public static function lazyConsecutive(callable $ruleCreator, callable ...$ruleCreators): ChainedValidator;
|
||||
|
||||
/** @param "alpha-2"|"alpha-3" $set */
|
||||
public static function languageCode(string $set = 'alpha-2'): ChainedValidator;
|
||||
|
||||
|
|
31
library/Rules/Consecutive.php
Normal file
31
library/Rules/Consecutive.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Helpers\CanBindEvaluateRule;
|
||||
use Respect\Validation\Result;
|
||||
use Respect\Validation\Rules\Core\Composite;
|
||||
|
||||
final class Consecutive extends Composite
|
||||
{
|
||||
use CanBindEvaluateRule;
|
||||
|
||||
public function evaluate(mixed $input): Result
|
||||
{
|
||||
foreach ($this->rules as $rule) {
|
||||
$result = $this->bindEvaluate($rule, $this, $input);
|
||||
if (!$result->isValid) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
|
@ -17,7 +17,6 @@ use Respect\Validation\Result;
|
|||
use Respect\Validation\Validatable;
|
||||
|
||||
use function array_filter;
|
||||
use function array_map;
|
||||
use function array_merge;
|
||||
use function array_pop;
|
||||
use function count;
|
||||
|
@ -32,7 +31,7 @@ use function mb_substr_count;
|
|||
)]
|
||||
final class Domain extends AbstractRule
|
||||
{
|
||||
private readonly AllOf $genericRule;
|
||||
private readonly Consecutive $genericRule;
|
||||
|
||||
private readonly Validatable $tldRule;
|
||||
|
||||
|
@ -66,13 +65,9 @@ final class Domain extends AbstractRule
|
|||
|
||||
public function evaluate(mixed $input): Result
|
||||
{
|
||||
$failedGenericResults = array_filter(array_map(
|
||||
static fn (Validatable $rule) => $rule->evaluate($input),
|
||||
$this->genericRule->getRules()
|
||||
), static fn (Result $result) => !$result->isValid);
|
||||
|
||||
if (count($failedGenericResults)) {
|
||||
return (new Result(false, $input, $this))->withChildren(...$failedGenericResults);
|
||||
$genericResult = $this->genericRule->evaluate($input);
|
||||
if (!$genericResult->isValid) {
|
||||
return (new Result(false, $input, $this))->withChildren($genericResult);
|
||||
}
|
||||
|
||||
$children = [];
|
||||
|
@ -80,19 +75,15 @@ final class Domain extends AbstractRule
|
|||
$parts = explode('.', (string) $input);
|
||||
if (count($parts) >= 2) {
|
||||
$tld = array_pop($parts);
|
||||
foreach ($this->tldRule instanceof AllOf ? $this->tldRule->getRules() : [$this->tldRule] as $rule) {
|
||||
$childResult = $rule->evaluate($tld);
|
||||
$valid = $valid && $childResult->isValid;
|
||||
$children[] = $childResult;
|
||||
}
|
||||
$childResult = $this->tldRule->evaluate($tld);
|
||||
$valid = $childResult->isValid;
|
||||
$children[] = $childResult;
|
||||
}
|
||||
|
||||
foreach ($parts as $part) {
|
||||
foreach ($this->partsRule->getRules() as $rule) {
|
||||
$childResult = $rule->evaluate($part);
|
||||
$valid = $valid && $childResult->isValid;
|
||||
$children[] = $childResult;
|
||||
}
|
||||
$partsResult = $this->partsRule->evaluate($part);
|
||||
$valid = $valid && $partsResult->isValid;
|
||||
$children = array_merge($children, $partsResult->children);
|
||||
}
|
||||
|
||||
return (new Result($valid, $input, $this))
|
||||
|
@ -141,9 +132,9 @@ final class Domain extends AbstractRule
|
|||
}
|
||||
}
|
||||
|
||||
private function createGenericRule(): AllOf
|
||||
private function createGenericRule(): Consecutive
|
||||
{
|
||||
return new AllOf(
|
||||
return new Consecutive(
|
||||
new StringType(),
|
||||
new NoWhitespace(),
|
||||
new Contains('.'),
|
||||
|
@ -157,7 +148,7 @@ final class Domain extends AbstractRule
|
|||
return new Tld();
|
||||
}
|
||||
|
||||
return new AllOf(
|
||||
return new Consecutive(
|
||||
new Not(new StartsWith('-')),
|
||||
new NoWhitespace(),
|
||||
new Length(2)
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
use Respect\Validation\Helpers\CanBindEvaluateRule;
|
||||
use Respect\Validation\Result;
|
||||
use Respect\Validation\Rules\Core\Standard;
|
||||
use Respect\Validation\Validatable;
|
||||
|
||||
use function array_merge;
|
||||
|
||||
final class LazyConsecutive extends Standard
|
||||
{
|
||||
use CanBindEvaluateRule;
|
||||
|
||||
/** @var non-empty-array<callable> */
|
||||
private array $ruleCreators;
|
||||
|
||||
/**
|
||||
* @param callable(mixed): Validatable $ruleCreator
|
||||
* @param callable(mixed): Validatable ...$ruleCreators
|
||||
*/
|
||||
public function __construct(callable $ruleCreator, callable ...$ruleCreators)
|
||||
{
|
||||
$this->ruleCreators = array_merge([$ruleCreator], $ruleCreators);
|
||||
}
|
||||
|
||||
public function evaluate(mixed $input): Result
|
||||
{
|
||||
foreach ($this->ruleCreators as $key => $ruleCreator) {
|
||||
$rule = $ruleCreator($input);
|
||||
if (!$rule instanceof Validatable) {
|
||||
throw new ComponentException(
|
||||
'LazyConsecutive failed because it could not create rule #' . ($key + 1)
|
||||
);
|
||||
}
|
||||
|
||||
$result = $this->bindEvaluate($rule, $this, $input);
|
||||
if (!$result->isValid) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
143
tests/integration/rules/consecutive.phpt
Normal file
143
tests/integration/rules/consecutive.phpt
Normal file
|
@ -0,0 +1,143 @@
|
|||
--FILE--
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
use Respect\Validation\Validator as v;
|
||||
|
||||
run([
|
||||
'Default' => [v::consecutive(v::alwaysValid(), v::trueVal()), false],
|
||||
'Negative' => [v::not(v::consecutive(v::alwaysValid(), v::trueVal())), true],
|
||||
'Default with inverted failing rule' => [v::consecutive(v::alwaysValid(), v::not(v::trueVal())), true],
|
||||
'With wrapped name, default' => [
|
||||
v::consecutive(v::alwaysValid(), v::trueVal()->setName('Wrapped'))->setName('Wrapper'),
|
||||
false,
|
||||
],
|
||||
'With wrapper name, default' => [
|
||||
v::consecutive(v::alwaysValid(), v::trueVal())->setName('Wrapper'),
|
||||
false,
|
||||
],
|
||||
'With the name set in the wrapped rule of an inverted failing rule' => [
|
||||
v::consecutive(v::alwaysValid(), v::not(v::trueVal()->setName('Wrapped'))->setName('Not'))->setName('Wrapper'),
|
||||
true,
|
||||
],
|
||||
'With the name set in an inverted failing rule' => [
|
||||
v::consecutive(v::alwaysValid(), v::not(v::trueVal())->setName('Not'))->setName('Wrapper'),
|
||||
true,
|
||||
],
|
||||
'With the name set in the "consecutive" that has an inverted failing rule' => [
|
||||
v::consecutive(v::alwaysValid(), v::not(v::trueVal()))->setName('Wrapper'),
|
||||
true,
|
||||
],
|
||||
'With template' => [
|
||||
v::consecutive(v::alwaysValid(), v::trueVal()),
|
||||
false,
|
||||
'Consecutive cool cats cunningly continuous cookies',
|
||||
],
|
||||
'With multiple templates' => [
|
||||
v::consecutive(v::alwaysValid(), v::trueVal()),
|
||||
false,
|
||||
['trueVal' => 'Clever clowns craft consecutive clever clocks'],
|
||||
],
|
||||
'Real example' => [
|
||||
v::consecutive(
|
||||
v::key('countyCode', v::countryCode()),
|
||||
v::lazy(static fn($input) => v::key('subdivisionCode', v::subdivisionCode($input['countyCode']))),
|
||||
),
|
||||
[
|
||||
'countyCode' => 'BR',
|
||||
'subdivisionCode' => 'CA',
|
||||
],
|
||||
],
|
||||
]);
|
||||
?>
|
||||
--EXPECT--
|
||||
Default
|
||||
⎺⎺⎺⎺⎺⎺⎺
|
||||
`false` must evaluate to `true`
|
||||
- `false` must evaluate to `true`
|
||||
[
|
||||
'trueVal' => '`false` must evaluate to `true`',
|
||||
]
|
||||
|
||||
Negative
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
`true` must not evaluate to `true`
|
||||
- `true` must not evaluate to `true`
|
||||
[
|
||||
'trueVal' => '`true` must not evaluate to `true`',
|
||||
]
|
||||
|
||||
Default with inverted failing rule
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
`true` must not evaluate to `true`
|
||||
- `true` must not evaluate to `true`
|
||||
[
|
||||
'trueVal' => '`true` must not evaluate to `true`',
|
||||
]
|
||||
|
||||
With wrapped name, default
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
Wrapped must evaluate to `true`
|
||||
- Wrapped must evaluate to `true`
|
||||
[
|
||||
'Wrapped' => 'Wrapped must evaluate to `true`',
|
||||
]
|
||||
|
||||
With wrapper name, default
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
Wrapper must evaluate to `true`
|
||||
- Wrapper must evaluate to `true`
|
||||
[
|
||||
'Wrapper' => 'Wrapper must evaluate to `true`',
|
||||
]
|
||||
|
||||
With the name set in the wrapped rule of an inverted failing rule
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
Wrapped must not evaluate to `true`
|
||||
- Wrapped must not evaluate to `true`
|
||||
[
|
||||
'Wrapped' => 'Wrapped must not evaluate to `true`',
|
||||
]
|
||||
|
||||
With the name set in an inverted failing rule
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
Not must not evaluate to `true`
|
||||
- Not must not evaluate to `true`
|
||||
[
|
||||
'Not' => 'Not must not evaluate to `true`',
|
||||
]
|
||||
|
||||
With the name set in the "consecutive" that has an inverted failing rule
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
Wrapper must not evaluate to `true`
|
||||
- Wrapper must not evaluate to `true`
|
||||
[
|
||||
'Wrapper' => 'Wrapper must not evaluate to `true`',
|
||||
]
|
||||
|
||||
With template
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
Consecutive cool cats cunningly continuous cookies
|
||||
- Consecutive cool cats cunningly continuous cookies
|
||||
[
|
||||
'trueVal' => 'Consecutive cool cats cunningly continuous cookies',
|
||||
]
|
||||
|
||||
With multiple templates
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
Clever clowns craft consecutive clever clocks
|
||||
- Clever clowns craft consecutive clever clocks
|
||||
[
|
||||
'trueVal' => 'Clever clowns craft consecutive clever clocks',
|
||||
]
|
||||
|
||||
Real example
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
subdivisionCode must be a subdivision code of Brazil
|
||||
- subdivisionCode must be a subdivision code of Brazil
|
||||
[
|
||||
'subdivisionCode' => 'subdivisionCode must be a subdivision code of Brazil',
|
||||
]
|
|
@ -1,48 +0,0 @@
|
|||
--FILE--
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
use Respect\Validation\Validator as v;
|
||||
|
||||
run([
|
||||
'Password confirmation' => [
|
||||
v::lazyConsecutive(
|
||||
static fn() => v::key('password', v::stringType()),
|
||||
static fn($input) => v::key('password_confirmation', v::equals($input['password']))
|
||||
),
|
||||
[
|
||||
'password' => '123456',
|
||||
'password_confirmation' => '1234s56',
|
||||
],
|
||||
],
|
||||
'Localization confirmation' => [
|
||||
v::lazyConsecutive(
|
||||
static fn() => v::key('countyCode', v::countryCode()),
|
||||
static fn($input) => v::key('subdivisionCode', v::subdivisionCode($input['countyCode'])),
|
||||
),
|
||||
[
|
||||
'countyCode' => 'BR',
|
||||
'subdivisionCode' => 'CA',
|
||||
],
|
||||
],
|
||||
]);
|
||||
?>
|
||||
--EXPECT--
|
||||
Password confirmation
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
password_confirmation must equal "123456"
|
||||
- password_confirmation must equal "123456"
|
||||
[
|
||||
'password_confirmation' => 'password_confirmation must equal "123456"',
|
||||
]
|
||||
|
||||
Localization confirmation
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
subdivisionCode must be a subdivision code of Brazil
|
||||
- subdivisionCode must be a subdivision code of Brazil
|
||||
[
|
||||
'subdivisionCode' => 'subdivisionCode must be a subdivision code of Brazil',
|
||||
]
|
63
tests/unit/Rules/ConsecutiveTest.php
Normal file
63
tests/unit/Rules/ConsecutiveTest.php
Normal file
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
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;
|
||||
|
||||
use function rand;
|
||||
|
||||
#[Group('rule')]
|
||||
#[CoversClass(Consecutive::class)]
|
||||
final class ConsecutiveTest extends TestCase
|
||||
{
|
||||
#[Test]
|
||||
#[DataProvider('providerForAnyValues')]
|
||||
public function itShouldValidateInputWhenAllRulesValidatesTheInput(mixed $input): void
|
||||
{
|
||||
self::assertValidInput(new Consecutive(Stub::pass(1), Stub::pass(1)), $input);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
#[DataProvider('providerForFailingRules')]
|
||||
public function itShouldExecuteRulesInSequenceUntilOneFails(Stub ...$stub): void
|
||||
{
|
||||
$rule = new Consecutive(...$stub);
|
||||
|
||||
self::assertInvalidInput($rule, rand());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function itShouldReturnTheResultOfTheFailingRule(): void
|
||||
{
|
||||
$input = rand();
|
||||
|
||||
$rule = new Consecutive(Stub::fail(1), Stub::daze());
|
||||
|
||||
$actual = $rule->evaluate($input);
|
||||
$expected = Stub::fail(1)->evaluate($input);
|
||||
|
||||
self::assertEquals($expected, $actual);
|
||||
}
|
||||
|
||||
/** @return array<array<Stub>> */
|
||||
public static function providerForFailingRules(): array
|
||||
{
|
||||
return [
|
||||
'first fails' => [Stub::fail(1), Stub::daze()],
|
||||
'second fails' => [Stub::pass(1), Stub::fail(1), Stub::daze()],
|
||||
'third fails' => [Stub::pass(1), Stub::fail(1), Stub::fail(1), Stub::daze(), Stub::daze()],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
use Respect\Validation\Test\Rules\Stub;
|
||||
use Respect\Validation\Test\RuleTestCase;
|
||||
|
||||
use function rand;
|
||||
|
||||
#[Group('rule')]
|
||||
#[CoversClass(LazyConsecutive::class)]
|
||||
final class LazyConsecutiveTest extends RuleTestCase
|
||||
{
|
||||
#[Test]
|
||||
public function itShouldThrowAnExceptionWhenRuleCreatorDoesNotReturnValidatable(): void
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
$rule = new LazyConsecutive(static fn () => null);
|
||||
|
||||
$this->expectException(ComponentException::class);
|
||||
$this->expectExceptionMessage('LazyConsecutive failed because it could not create rule #1');
|
||||
|
||||
$rule->evaluate('something');
|
||||
}
|
||||
|
||||
#[Test]
|
||||
#[DataProvider('providerForAnyValues')]
|
||||
public function itShouldPassInputToTheRuleCreators(mixed $input): void
|
||||
{
|
||||
$rule = new LazyConsecutive(static fn ($creatorInput) => Stub::fail(1));
|
||||
|
||||
self::assertEquals(
|
||||
Stub::fail(1)->evaluate($input),
|
||||
$rule->evaluate($input)
|
||||
);
|
||||
}
|
||||
|
||||
/** @return iterable<string, array{LazyConsecutive, mixed}> */
|
||||
public static function providerForValidInput(): iterable
|
||||
{
|
||||
return [
|
||||
'1st pass' => [new LazyConsecutive(static fn () => Stub::pass(1)), true],
|
||||
'1st pass + 2nd pass' => [
|
||||
new LazyConsecutive(static fn () => Stub::pass(1), static fn () => Stub::pass(1)),
|
||||
true,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/** @return iterable<string, array{LazyConsecutive, mixed}> */
|
||||
public static function providerForInvalidInput(): iterable
|
||||
{
|
||||
return [
|
||||
'1st fail' => [
|
||||
new LazyConsecutive(
|
||||
static fn () => Stub::fail(1),
|
||||
static fn () => Stub::daze(),
|
||||
),
|
||||
rand(),
|
||||
],
|
||||
'1st pass + 2nd fail' => [
|
||||
new LazyConsecutive(
|
||||
static fn () => Stub::pass(1),
|
||||
static fn () => Stub::fail(1),
|
||||
static fn () => Stub::daze(),
|
||||
),
|
||||
rand(),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue