Recreate "IterableType" rule

The difference with this rule is that it matches the behavior of
`is_iterable()`, which is different from `IterableVal` that also allows
instances of `stdClass.`

This is a necessary change because PHP will trigger an error when trying
to pass any object to anything typed as `iterable`

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
This commit is contained in:
Henrique Moody 2024-03-02 13:16:08 +01:00
parent 980ab28707
commit 210aa4ac01
No known key found for this signature in database
GPG key ID: 221E9281655813A6
14 changed files with 173 additions and 2 deletions

View file

@ -263,6 +263,7 @@
- [FloatVal](rules/FloatVal.md)
- [IntType](rules/IntType.md)
- [IntVal](rules/IntVal.md)
- [IterableType](rules/IterableType.md)
- [IterableVal](rules/IterableVal.md)
- [NullType](rules/NullType.md)
- [NumericVal](rules/NumericVal.md)
@ -342,6 +343,7 @@
- [IntVal](rules/IntVal.md)
- [Ip](rules/Ip.md)
- [Isbn](rules/Isbn.md)
- [IterableType](rules/IterableType.md)
- [IterableVal](rules/IterableVal.md)
- [Json](rules/Json.md)
- [Key](rules/Key.md)

View file

@ -30,6 +30,7 @@ See also:
- [Countable](Countable.md)
- [FloatType](FloatType.md)
- [IntType](IntType.md)
- [IterableType](IterableType.md)
- [IterableVal](IterableVal.md)
- [NullType](NullType.md)
- [ObjectType](ObjectType.md)

View file

@ -32,6 +32,7 @@ See also:
- [ArrayType](ArrayType.md)
- [Countable](Countable.md)
- [Each](Each.md)
- [IterableType](IterableType.md)
- [IterableVal](IterableVal.md)
- [Key](Key.md)
- [KeySet](KeySet.md)

View file

@ -27,4 +27,5 @@ See also:
- [ArrayType](ArrayType.md)
- [ArrayVal](ArrayVal.md)
- [Instance](Instance.md)
- [IterableType](IterableType.md)
- [IterableVal](IterableVal.md)

View file

@ -49,6 +49,7 @@ See also:
- [ArrayVal](ArrayVal.md)
- [Call](Call.md)
- [IterableType](IterableType.md)
- [IterableVal](IterableVal.md)
- [Key](Key.md)
- [NotEmpty](NotEmpty.md)

View file

@ -25,6 +25,7 @@ Version | Description
See also:
- [Countable](Countable.md)
- [IterableType](IterableType.md)
- [IterableVal](IterableVal.md)
- [ObjectType](ObjectType.md)
- [Type](Type.md)

View file

@ -0,0 +1,35 @@
# IterableType
- `IterableType()`
Validates whether the input is iterable, meaning that it matches the built-in compile time type alias `iterable`.
```php
v::iterableType()->validate([]); // true
v::iterableType()->validate(new ArrayObject()); // true
v::iterableType()->validate(new stdClass()); // false
v::iterableType()->validate('string'); // false
```
## Categorization
- Types
## Changelog
| Version | Description |
|---------:|-------------------------------------------|
| 3.0.0 | Rejected `stdClass` as iterable |
| 1.0.8 | Renamed from `Iterable` to `IterableType` |
| 1.0.0 | Created as `Iterable` |
***
See also:
- [ArrayType](ArrayType.md)
- [ArrayVal](ArrayVal.md)
- [Countable](Countable.md)
- [Each](Each.md)
- [Instance](Instance.md)
- [IterableVal](IterableVal.md)

View file

@ -35,6 +35,7 @@ See also:
- [Countable](Countable.md)
- [Each](Each.md)
- [Instance](Instance.md)
- [IterableType](IterableType.md)
[is_iterable()]: https://www.php.net/is_iterable
[foreach]: http://php.net/foreach

View file

@ -157,6 +157,8 @@ interface ChainedValidator extends Validatable
public function isbn(): ChainedValidator;
public function iterableType(): ChainedValidator;
public function iterableVal(): ChainedValidator;
public function json(): ChainedValidator;

View file

@ -0,0 +1,26 @@
<?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 function is_iterable;
#[Template(
'{{name}} must be of type iterable',
'{{name}} must not of type iterable',
)]
final class IterableType extends Simple
{
public function validate(mixed $input): bool
{
return is_iterable($input);
}
}

View file

@ -159,6 +159,8 @@ interface StaticValidator
public static function isbn(): ChainedValidator;
public static function iterableType(): ChainedValidator;
public static function iterableVal(): ChainedValidator;
public static function json(): ChainedValidator;

View file

@ -0,0 +1,49 @@
--FILE--
<?php
declare(strict_types=1);
require 'vendor/autoload.php';
use Respect\Validation\Validator as v;
run([
'Default' => [v::iterableType(), null],
'Negative' => [v::not(v::iterableType()), [1, 2, 3]],
'With template' => [v::iterableType(), null, 'Not an iterable at all'],
'With name' => [v::iterableType()->setName('Options'), null],
]);
?>
--EXPECT--
Default
⎺⎺⎺⎺⎺⎺⎺
`null` must be of type iterable
- `null` must be of type iterable
[
'iterableType' => '`null` must be of type iterable',
]
Negative
⎺⎺⎺⎺⎺⎺⎺⎺
`[1, 2, 3]` must not of type iterable
- `[1, 2, 3]` must not of type iterable
[
'iterableType' => '`[1, 2, 3]` must not of type iterable',
]
With template
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
Not an iterable at all
- Not an iterable at all
[
'iterableType' => 'Not an iterable at all',
]
With name
⎺⎺⎺⎺⎺⎺⎺⎺⎺
Options must be of type iterable
- Options must be of type iterable
[
'Options' => 'Options must be of type iterable',
]

View file

@ -120,7 +120,16 @@ abstract class TestCase extends PHPUnitTestCase
);
}
/** @return array<array{mixed}> */
/** @return array<array{iterable<mixed>}> */
public static function providerForIterableValues(): array
{
return array_merge(
self::providerForNonEmptyIterableValues(),
self::providerForEmptyIterableValues(),
);
}
/** @return array<array{iterable<mixed>}> */
public static function providerForNonEmptyIterableValues(): array
{
return [
@ -130,7 +139,7 @@ abstract class TestCase extends PHPUnitTestCase
];
}
/** @return array<array{mixed}> */
/** @return array<array{iterable<mixed>}> */
public static function providerForEmptyIterableValues(): array
{
return [

View file

@ -0,0 +1,40 @@
<?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\TestCase;
#[Group('rule')]
#[CoversClass(IterableType::class)]
final class IterableTypeTest extends TestCase
{
/** @param iterable<mixed> $input */
#[Test]
#[DataProvider('providerForIterableValues')]
public function itShouldValidateIterableTypes(iterable $input): void
{
$rule = new IterableType();
self::assertValidInput($rule, $input);
}
#[Test]
#[DataProvider('providerForNonIterableValues')]
public function itShouldInvalidateNonIterableTypes(mixed $input): void
{
$rule = new IterableType();
self::assertInvalidInput($rule, $input);
}
}