mirror of
https://github.com/Respect/Validation.git
synced 2024-06-04 06:42:22 +02:00
Apply contribution guidelines to "Each" rule
Also removed the possibility of validating keys once it's possible to reach the same behavior by combining this rule with "Call" rule. Co-authored-by: Henrique Moody <henriquemoody@gmail.com>
This commit is contained in:
parent
70eb87bd77
commit
dc3951edf1
32
docs/Each.md
32
docs/Each.md
|
@ -1,11 +1,8 @@
|
|||
# Each
|
||||
|
||||
- `Each(Validatable $ruleForValue)`
|
||||
- `Each(null, Validatable $ruleForKey)`
|
||||
- `Each(Validatable $ruleForValue, Validatable $ruleForKey)`
|
||||
- `Each(Validatable $rule)`
|
||||
|
||||
Iterates over an array or Iterator and validates the value or key
|
||||
of each entry:
|
||||
Validates whether each value in the input is valid according to another rule.
|
||||
|
||||
```php
|
||||
$releaseDates = [
|
||||
|
@ -14,20 +11,37 @@ $releaseDates = [
|
|||
'relational' => '2011-02-05',
|
||||
];
|
||||
|
||||
v::arrayVal()->each(v::dateTime())->validate($releaseDates); // true
|
||||
v::arrayVal()->each(v::dateTime(), v::stringType()->lowercase())->validate($releaseDates); // true
|
||||
v::each(v::dateTime())->validate($releaseDates); // true
|
||||
```
|
||||
|
||||
Using `arrayVal()` before `each()` is a best practice.
|
||||
You can also validate array keys combining this rule with [Call](Call.md):
|
||||
|
||||
```php
|
||||
v::call('array_keys', v::each(v::stringType()))->validate($releaseDates); // true
|
||||
```
|
||||
|
||||
This rule will not validate values that are not iterable, to have a more detailed
|
||||
error message, add [IterableType](IterableType.md) to your chain, for example.
|
||||
|
||||
If the input is empty this rule will consider the value as valid, you use
|
||||
[NotEmpty](NotEmpty.md) if convenient:
|
||||
|
||||
```php
|
||||
v::each(v::dateTime())->validate([]); // true
|
||||
v::notEmpty()->each(v::dateTime())->validate([]); // false
|
||||
```
|
||||
|
||||
## Changelog
|
||||
|
||||
Version | Description
|
||||
--------|-------------
|
||||
2.0.0 | Remove support for key validation
|
||||
0.3.9 | Created
|
||||
|
||||
***
|
||||
See also:
|
||||
|
||||
- [Key](Key.md)
|
||||
- [ArrayVal](ArrayVal.md)
|
||||
- [Call](Call.md)
|
||||
- [IterableType](IterableType.md)
|
||||
- [Key](Key.md)
|
||||
|
|
|
@ -13,8 +13,16 @@ declare(strict_types=1);
|
|||
|
||||
namespace Respect\Validation\Exceptions;
|
||||
|
||||
class EachException extends NestedValidationException
|
||||
/**
|
||||
* @author Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
final class EachException extends NestedValidationException
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $defaultTemplates = [
|
||||
self::MODE_DEFAULT => [
|
||||
self::STANDARD => 'Each item in {{name}} must be valid',
|
||||
|
|
|
@ -17,42 +17,48 @@ use Respect\Validation\Exceptions\ValidationException;
|
|||
use Respect\Validation\Helpers\CanValidateIterable;
|
||||
use Respect\Validation\Validatable;
|
||||
|
||||
class Each extends AbstractRule
|
||||
/**
|
||||
* Validates whether each value in the input is valid according to another rule.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Nick Lombard <github@jigsoft.co.za>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
final class Each extends AbstractRule
|
||||
{
|
||||
use CanValidateIterable;
|
||||
|
||||
public $itemValidator;
|
||||
public $keyValidator;
|
||||
/**
|
||||
* @var Validatable
|
||||
*/
|
||||
private $rule;
|
||||
|
||||
public function __construct(Validatable $itemValidator = null, Validatable $keyValidator = null)
|
||||
/**
|
||||
* Initializes the constructor.
|
||||
*
|
||||
* @param mixed $rule
|
||||
*/
|
||||
public function __construct(Validatable $rule)
|
||||
{
|
||||
$this->itemValidator = $itemValidator;
|
||||
$this->keyValidator = $keyValidator;
|
||||
$this->rule = $rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function assert($input): void
|
||||
{
|
||||
$exceptions = [];
|
||||
|
||||
if (!$this->isIterable($input)) {
|
||||
throw $this->reportError($input);
|
||||
}
|
||||
|
||||
foreach ($input as $key => $item) {
|
||||
if (isset($this->itemValidator)) {
|
||||
try {
|
||||
$this->itemValidator->assert($item);
|
||||
} catch (ValidationException $e) {
|
||||
$exceptions[] = $e;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->keyValidator)) {
|
||||
try {
|
||||
$this->keyValidator->assert($key);
|
||||
} catch (ValidationException $e) {
|
||||
$exceptions[] = $e;
|
||||
}
|
||||
$exceptions = [];
|
||||
foreach ($input as $value) {
|
||||
try {
|
||||
$this->rule->check($value);
|
||||
} catch (ValidationException $exception) {
|
||||
$exceptions[] = $exception;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,39 +67,17 @@ class Each extends AbstractRule
|
|||
}
|
||||
}
|
||||
|
||||
public function check($input): void
|
||||
{
|
||||
if (!$this->isIterable($input)) {
|
||||
throw $this->reportError($input);
|
||||
}
|
||||
|
||||
foreach ($input as $key => $item) {
|
||||
if (isset($this->itemValidator)) {
|
||||
$this->itemValidator->check($item);
|
||||
}
|
||||
|
||||
if (isset($this->keyValidator)) {
|
||||
$this->keyValidator->check($key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!$this->isIterable($input)) {
|
||||
try {
|
||||
$this->assert($input);
|
||||
} catch (ValidationException $exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($input as $key => $item) {
|
||||
if (isset($this->itemValidator) && !$this->itemValidator->validate($item)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($this->keyValidator) && !$this->keyValidator->validate($key)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ use Respect\Validation\Rules\Key;
|
|||
* @method static Validator digit(string $additionalChars = null)
|
||||
* @method static Validator directory()
|
||||
* @method static Validator domain(bool $tldCheck = true)
|
||||
* @method static Validator each(Validatable $itemValidator = null, Validatable $keyValidator = null)
|
||||
* @method static Validator each(Validatable $rule)
|
||||
* @method static Validator email()
|
||||
* @method static Validator endsWith($endValue, bool $identical = false)
|
||||
* @method static Validator equals($compareTo)
|
||||
|
|
38
tests/integration/rules/each.phpt
Normal file
38
tests/integration/rules/each.phpt
Normal file
|
@ -0,0 +1,38 @@
|
|||
--FILE--
|
||||
<?php
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
use Respect\Validation\Exceptions\EachException;
|
||||
use Respect\Validation\Exceptions\NestedValidationException;
|
||||
use Respect\Validation\Validator as v;
|
||||
|
||||
try {
|
||||
v::each(v::dateTime())->check(null);
|
||||
} catch (EachException $exception) {
|
||||
echo $exception->getMessage().PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
v::not(v::each(v::dateTime()))->check(['2018-10-10']);
|
||||
} catch (EachException $exception) {
|
||||
echo $exception->getMessage().PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
v::each(v::dateTime())->assert(null);
|
||||
} catch (NestedValidationException $exception) {
|
||||
echo $exception->getFullMessage().PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
v::not(v::each(v::dateTime()))->assert(['2018-10-10']);
|
||||
} catch (NestedValidationException $exception) {
|
||||
echo $exception->getFullMessage().PHP_EOL;
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Each item in `NULL` must be valid
|
||||
Each item in `{ "2018-10-10" }` must not validate
|
||||
- Each item in `NULL` must be valid
|
||||
- Each item in `{ "2018-10-10" }` must not validate
|
|
@ -126,7 +126,7 @@ abstract class RuleTestCase extends TestCase
|
|||
*/
|
||||
public function shouldValidateValidInput(Validatable $validator, $input): void
|
||||
{
|
||||
self::assertTrue($validator->validate($input));
|
||||
self::assertValidInput($validator, $input);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -139,6 +139,16 @@ abstract class RuleTestCase extends TestCase
|
|||
*/
|
||||
public function shouldValidateInvalidInput(Validatable $validator, $input): void
|
||||
{
|
||||
self::assertFalse($validator->validate($input));
|
||||
self::assertInvalidInput($validator, $input);
|
||||
}
|
||||
|
||||
public static function assertValidInput(Validatable $rule, $input): void
|
||||
{
|
||||
self::assertTrue($rule->validate($input));
|
||||
}
|
||||
|
||||
public static function assertInvalidInput(Validatable $rule, $input): void
|
||||
{
|
||||
self::assertFalse($rule->validate($input));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,44 +14,41 @@ declare(strict_types=1);
|
|||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Test\RuleTestCase;
|
||||
use Respect\Validation\Validatable;
|
||||
use SplStack;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* @group rule
|
||||
* @group rule
|
||||
*
|
||||
* @covers \Respect\Validation\Rules\Each
|
||||
* @covers \Respect\Validation\Exceptions\EachException
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
|
||||
* @author Emmerson <emmersonsiqueira@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
class EachTest extends RuleTestCase
|
||||
final class EachTest extends RuleTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function providerForValidInput(): array
|
||||
{
|
||||
$ruleNotEmpty = new Each($this->createValidatableMock(true));
|
||||
$ruleAlphaItemIntKey = new Each($this->createValidatableMock(true), $this->createValidatableMock(true));
|
||||
$ruleOnlyKeyValidation = new Each(null, $this->createValidatableMock(true));
|
||||
|
||||
$intStack = new \SplStack();
|
||||
$intStack->push(1);
|
||||
$intStack->push(2);
|
||||
$intStack->push(3);
|
||||
$intStack->push(4);
|
||||
$intStack->push(5);
|
||||
|
||||
$stdClass = new \stdClass();
|
||||
$stdClass->name = 'Emmerson';
|
||||
$stdClass->age = 22;
|
||||
$rule = new Each($this->createValidatableMock(true));
|
||||
|
||||
return [
|
||||
[$ruleNotEmpty, [1, 2, 3, 4, 5]],
|
||||
[$ruleNotEmpty, $intStack],
|
||||
[$ruleNotEmpty, $stdClass],
|
||||
[$ruleAlphaItemIntKey, ['a', 'b', 'c', 'd', 'e']],
|
||||
[$ruleOnlyKeyValidation, ['a', 'b', 'c', 'd', 'e']],
|
||||
[$rule, []],
|
||||
[$rule, [1, 2, 3, 4, 5]],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function providerForInvalidInput(): array
|
||||
{
|
||||
$rule = new Each($this->createValidatableMock(false));
|
||||
$ruleOnlyKeyValidation = new Each(null, $this->createValidatableMock(false));
|
||||
|
||||
return [
|
||||
[$rule, 123],
|
||||
|
@ -59,73 +56,67 @@ class EachTest extends RuleTestCase
|
|||
[$rule, null],
|
||||
[$rule, false],
|
||||
[$rule, ['', 2, 3, 4, 5]],
|
||||
[$ruleOnlyKeyValidation, ['age' => 22]],
|
||||
[$rule, ['a', 2, 3, 4, 5]],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @doesNotPerformAssertions
|
||||
* @test
|
||||
*/
|
||||
public function testValidatorShouldPassIfEveryArrayItemPass(): void
|
||||
public function itShouldValidateTraversable(): void
|
||||
{
|
||||
$v = new Each($this->createValidatableMock(true));
|
||||
$v->check([1, 2, 3, 4, 5]);
|
||||
$v->assert([1, 2, 3, 4, 5]);
|
||||
$validatable = $this->createMock(Validatable::class);
|
||||
|
||||
$validatable
|
||||
->expects($this->at(0))
|
||||
->method('check')
|
||||
->with('A');
|
||||
$validatable
|
||||
->expects($this->at(1))
|
||||
->method('check')
|
||||
->with('B');
|
||||
$validatable
|
||||
->expects($this->at(2))
|
||||
->method('check')
|
||||
->with('C');
|
||||
|
||||
$rule = new Each($validatable);
|
||||
|
||||
$input = new SplStack();
|
||||
$input->push('C');
|
||||
$input->push('B');
|
||||
$input->push('A');
|
||||
|
||||
self::assertValidInput($rule, $input);
|
||||
}
|
||||
|
||||
/**
|
||||
* @doesNotPerformAssertions
|
||||
* @test
|
||||
*/
|
||||
public function testValidatorShouldPassIfEveryArrayItemAndKeyPass(): void
|
||||
public function itShouldValidateStdClass(): void
|
||||
{
|
||||
$v = new Each($this->createValidatableMock(true), $this->createValidatableMock(true));
|
||||
$v->check(['a', 'b', 'c', 'd', 'e']);
|
||||
$v->assert(['a', 'b', 'c', 'd', 'e']);
|
||||
}
|
||||
$validatable = $this->createMock(Validatable::class);
|
||||
|
||||
/**
|
||||
* @doesNotPerformAssertions
|
||||
*/
|
||||
public function testValidatorShouldPassWithOnlyKeyValidation(): void
|
||||
{
|
||||
$v = new Each(null, $this->createValidatableMock(true));
|
||||
$v->check(['a', 'b', 'c', 'd', 'e']);
|
||||
$v->assert(['a', 'b', 'c', 'd', 'e']);
|
||||
}
|
||||
$validatable
|
||||
->expects($this->at(0))
|
||||
->method('check')
|
||||
->with(1);
|
||||
$validatable
|
||||
->expects($this->at(1))
|
||||
->method('check')
|
||||
->with(2);
|
||||
$validatable
|
||||
->expects($this->at(2))
|
||||
->method('check')
|
||||
->with(3);
|
||||
|
||||
/**
|
||||
* @expectedException \Respect\Validation\Exceptions\EachException
|
||||
*/
|
||||
public function testValidatorShouldNotPassWithOnlyKeyValidation(): void
|
||||
{
|
||||
$v = new Each(null, $this->createValidatableMock(false));
|
||||
$v->assert(['a', 'b', 'c', 'd', 'e']);
|
||||
}
|
||||
$rule = new Each($validatable);
|
||||
|
||||
/**
|
||||
* @expectedException \Respect\Validation\Exceptions\EachException
|
||||
*/
|
||||
public function testAssertShouldFailOnInvalidItem(): void
|
||||
{
|
||||
$v = new Each($this->createValidatableMock(false));
|
||||
$v->assert(['a', 2, 3, 4, 5]);
|
||||
}
|
||||
$input = new stdClass();
|
||||
$input->foo = 1;
|
||||
$input->bar = 2;
|
||||
$input->baz = 3;
|
||||
|
||||
/**
|
||||
* @expectedException \Respect\Validation\Exceptions\EachException
|
||||
*/
|
||||
public function testAssertShouldFailWithNonIterableInput(): void
|
||||
{
|
||||
$v = new Each($this->createValidatableMock(false));
|
||||
$v->assert('a');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Respect\Validation\Exceptions\EachException
|
||||
*/
|
||||
public function testCheckShouldFailWithNonIterableInput(): void
|
||||
{
|
||||
$v = new Each($this->createValidatableMock(false));
|
||||
$v->check(null);
|
||||
self::assertValidInput($rule, $input);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue