-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #60 from programmatordev/YAPV-34-create-collection…
…-rule Create Collection rule
- Loading branch information
Showing
10 changed files
with
376 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
# Collection | ||
|
||
Validates each key of an `array`, or object implementing `\Traversable`, with a set of validation constraints. | ||
|
||
```php | ||
/** @var array<mixed, Validator> $fields */ | ||
Collection( | ||
array $fields, | ||
bool $allowExtraFields = false, | ||
?string $message = null, | ||
?string $extraFieldsMessage = null, | ||
?string $missingFieldsMessage = null | ||
); | ||
``` | ||
|
||
## Basic Usage | ||
|
||
```php | ||
Validator::collection(fields: [ | ||
'name' => Validator::notBlank(), | ||
'age' => Validator::type('int')->greaterThanOrEqual(18) | ||
])->validate([ | ||
'name' => 'Name', | ||
'age' => 25 | ||
]); // true | ||
|
||
Validator::collection(fields: [ | ||
'name' => Validator::notBlank(), | ||
'age' => Validator::type('int')->greaterThanOrEqual(18) | ||
])->validate([ | ||
'name' => '', | ||
'age' => 25 | ||
]); // false ("name" is blank) | ||
|
||
// by default, unknown keys are not allowed | ||
Validator::collection(fields: [ | ||
'name' => Validator::notBlank(), | ||
'age' => Validator::type('int')->greaterThanOrEqual(18) | ||
])->validate([ | ||
'name' => 'Name', | ||
'age' => 25, | ||
'email' => 'mail@example.com' | ||
]); // false ("email" field is not allowed) | ||
|
||
// to allow extra fields, set option to true | ||
Validator::collection( | ||
fields: [ | ||
'name' => Validator::notBlank(), | ||
'age' => Validator::type('int')->greaterThanOrEqual(18) | ||
], | ||
allowExtraFields: true | ||
)->validate([ | ||
'name' => 'Name', | ||
'age' => 25, | ||
'email' => 'mail@example.com' | ||
]); // true | ||
``` | ||
|
||
> [!NOTE] | ||
> An `UnexpectedValueException` will be thrown when a value in the `fields` associative array is not an instance of `Validator`. | ||
> [!NOTE] | ||
> An `UnexpectedValueException` will be thrown when the input value is not an `array` or an object implementing `\Traversable`. | ||
## Options | ||
|
||
### `fields` | ||
|
||
type: `array<mixed, Validator>` `required` | ||
|
||
Associative array with a set of validation constraints for each key. | ||
|
||
### `allowExtraFields` | ||
|
||
type: `bool` default: `false` | ||
|
||
By default, it is not allowed to have fields (array keys) that are not defined in the `fields` option. | ||
If set to `true`, it will be allowed (but not validated). | ||
|
||
### `message` | ||
|
||
type: `?string` default: `{{ message }}` | ||
|
||
Message that will be shown when one of the fields is invalid. | ||
|
||
The following parameters are available: | ||
|
||
| Parameter | Description | | ||
|-----------------|---------------------------------------| | ||
| `{{ name }}` | Name of the invalid value | | ||
| `{{ field }}` | Name of the invalid field (array key) | | ||
| `{{ message }}` | The rule message of the invalid field | | ||
|
||
### `extraFieldsMessage` | ||
|
||
type: `?string` default: `The {{ field }} field is not allowed.` | ||
|
||
Message that will be shown when the input value has a field that is not defined in the `fields` option | ||
and `allowExtraFields` is set to `false`. | ||
|
||
The following parameters are available: | ||
|
||
| Parameter | Description | | ||
|-----------------|---------------------------------------| | ||
| `{{ name }}` | Name of the invalid value | | ||
| `{{ field }}` | Name of the invalid field (array key) | | ||
|
||
### `missingFieldsMessage` | ||
|
||
type: `?string` default: `The {{ field }} field is missing.` | ||
|
||
Message that will be shown when the input value *does not* have a field that is defined in the `fields` option. | ||
|
||
The following parameters are available: | ||
|
||
| Parameter | Description | | ||
|-----------------|---------------------------------------| | ||
| `{{ name }}` | Name of the invalid value | | ||
| `{{ field }}` | Name of the invalid field (array key) | | ||
|
||
## Changelog | ||
|
||
- `1.0.0` Created |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<?php | ||
|
||
namespace ProgrammatorDev\Validator\Exception; | ||
|
||
class CollectionException extends ValidationException {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
<?php | ||
|
||
namespace ProgrammatorDev\Validator\Rule; | ||
|
||
use ProgrammatorDev\Validator\Exception\CollectionException; | ||
use ProgrammatorDev\Validator\Exception\UnexpectedTypeException; | ||
use ProgrammatorDev\Validator\Exception\UnexpectedValueException; | ||
use ProgrammatorDev\Validator\Exception\ValidationException; | ||
use ProgrammatorDev\Validator\Validator; | ||
|
||
class Collection extends AbstractRule implements RuleInterface | ||
{ | ||
private string $message = '{{ message }}'; | ||
private string $extraFieldsMessage = 'The {{ field }} field is not allowed.'; | ||
private string $missingFieldsMessage = 'The {{ field }} field is missing.'; | ||
|
||
/** @param array<mixed, Validator> $fields */ | ||
public function __construct( | ||
private readonly array $fields, | ||
private readonly bool $allowExtraFields = false, | ||
?string $message = null, | ||
?string $extraFieldsMessage = null, | ||
?string $missingFieldsMessage = null | ||
) | ||
{ | ||
$this->message = $message ?? $this->message; | ||
$this->extraFieldsMessage = $extraFieldsMessage ?? $this->extraFieldsMessage; | ||
$this->missingFieldsMessage = $missingFieldsMessage ?? $this->missingFieldsMessage; | ||
} | ||
|
||
public function assert(mixed $value, ?string $name = null): void | ||
{ | ||
try { | ||
Validator::eachValue( | ||
validator: Validator::type(Validator::class), | ||
message: 'At field {{ key }}: {{ message }}' | ||
)->assert($this->fields); | ||
} | ||
catch (ValidationException $exception) { | ||
throw new UnexpectedValueException($exception->getMessage()); | ||
} | ||
|
||
if (!\is_iterable($value)) { | ||
throw new UnexpectedTypeException('array|\Traversable', get_debug_type($value)); | ||
} | ||
|
||
foreach ($this->fields as $field => $validator) { | ||
if (!isset($value[$field])) { | ||
throw new CollectionException( | ||
message: $this->missingFieldsMessage, | ||
parameters: [ | ||
'name' => $name, | ||
'field' => $field | ||
] | ||
); | ||
} | ||
|
||
try { | ||
$validator->assert($value[$field], \sprintf('"%s"', $field)); | ||
} | ||
catch (ValidationException $exception) { | ||
throw new CollectionException( | ||
message: $this->message, | ||
parameters: [ | ||
'name' => $name, | ||
'field' => $field, | ||
'message' => $exception->getMessage() | ||
] | ||
); | ||
} | ||
} | ||
|
||
if (!$this->allowExtraFields) { | ||
foreach ($value as $field => $fieldValue) { | ||
if (!isset($this->fields[$field])) { | ||
throw new CollectionException( | ||
message: $this->extraFieldsMessage, | ||
parameters: [ | ||
'name' => $name, | ||
'field' => $field | ||
] | ||
); | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.