https://github.com/lezhnev74/pasvl
Array Validator (regular expressions for arrays, sort of)
https://github.com/lezhnev74/pasvl
array php php71 php72 php73 php74 validation
Last synced: 12 months ago
JSON representation
Array Validator (regular expressions for arrays, sort of)
- Host: GitHub
- URL: https://github.com/lezhnev74/pasvl
- Owner: lezhnev74
- License: mit
- Created: 2018-01-05T17:53:45.000Z (about 8 years ago)
- Default Branch: master
- Last Pushed: 2022-01-29T10:58:21.000Z (about 4 years ago)
- Last Synced: 2025-04-09T20:04:20.501Z (12 months ago)
- Topics: array, php, php71, php72, php73, php74, validation
- Language: PHP
- Homepage:
- Size: 2.8 MB
- Stars: 50
- Watchers: 2
- Forks: 6
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
[](https://packagist.org/packages/lezhnev74/pasvl)
[](https://travis-ci.org/lezhnev74/pasvl)
[](https://packagist.org/packages/lezhnev74/pasvl)
[](https://packagist.org/packages/lezhnev74/pasvl)
# PASVL - PHP Array Structure Validation Library
Think of a regular expression `[ab]+` which matches a string `abab`. Now imaging the same for arrays.
The purpose of this library is to validate an existing (nested) array against a template and report a mismatch.
It has the object-oriented extendable architecture to write and add custom validators.
**Note to current users**: this version is not backwards compatible with the previous 0.5.6.
## Installation
```
composer require lezhnev74/pasvl
```
## Example
Refer to files in `Example` folder.
## Usage
### Array Validation
```php
// Define the pattern of the data, define keys and values separately
$pattern = [
'*' => [
'type' => 'book',
'title' => ':string :contains("book")',
'chapters' => [
':string :len(2) {1,3}' => [
'title' => ':string',
':exact("interesting") ?' => ':bool',
],
],
],
];
// Provide the data to match against the above pattern.
$data = [
[
'type' => 'book',
'title' => 'Geography book',
'chapters' => [
'eu' => ['title' => 'Europe', 'interesting' => true],
'as' => ['title' => 'America', 'interesting' => false],
],
],
[
'type' => 'book',
'title' => 'Foreign languages book',
'chapters' => [
'de' => ['title' => 'Deutsch'],
],
],
];
$builder = \PASVL\Validation\ValidatorBuilder::forArray($pattern);
$validator = $builder->build();
try {
$validator->validate($data);
} catch (ArrayFailedValidation $e) {
// If data cannot be matched against the pattern, then exception is thrown.
// It is not always easy to detect why the data failed matching, the exception MAY sometimes give you extra hints.
echo "failed: " . $e->getMessage() . "\n";
}
```
### Optional String Validation
```php
$pattern = ":string :regexp('#^[ab]+$#')";
$builder = \PASVL\Validation\ValidatorBuilder::forString($pattern);
$validator = $builder->build();
$validator->validate("abab"); // the string is valid
$validator->validate("abc"); // throws RuleFailed exception with the message: "string does not match regular expression ^[ab]+$"
```
## Validation Language
This package supports a special dialect for validation specification.
It looks like this:

#### Short language reference:
- **Rule Name**
Specify zero or one Rule Name to apply to the data. Optinal postfix `?` allows data to be `null`.
Refer to the set of built-in rules in `src/Validation/Rules/Library`. For custom rules read below under `Custom Rules`.
For example, `:string?` describes strings and `null`.
- **Sub-Rule Name**
Specify zero or more Sub-Rule Names to apply to the data AFTER the Rule is applied. Sub Rules are extra methods of the main Rule.
For example, `:number :float` describes floats.
- **Quantifier**
Specify quantity expectations for data keys. If none is set then default is assumed - `!`.
Available quantifiers:
- `!` - one key required (default)
- `?` - optional key
- `*` - any count of keys
- `{2}` - strict keys count
- `{2,4}` - range of keys count
For example:
```php
$pattern = [":string *" => ":number"];
// the above pattern matches data:
$data = ["june"=>10, "aug" => "11"];
```
#### Pattern Definitions
- as exact value
```php
$pattern = ["name" => ":any"]; // here the key is the exact value
$pattern = ["name?" => ":any"]; // here the key is the exact value, can be absent as well
$pattern = [":exact('name')" => ":any"]; // this is the same
```
- as nullable rule
```php
$pattern = ["name" => ":string?"]; // the value must be a string or null
```
- as rule with subrules
```php
$pattern = ["name" => ":string :regexp('#\d*#')"]; // the value must be a string which contains only digits
```
- as rule with quantifiers
```php
$pattern = [":string {2}" => ":any"]; // data must have exactly two string keys
```
#### Compound Definitions
This package supports combinations of rules, expressed in a natural language.
Examples:
- `:string or :number`
- `:string and :number`
- `(:string and :number) or :array`
There are two combination operators: `and`, `or`.
`and` operator has precedence.
Both are left-associative.
## Custom Rules
By default, the system uses only the built-in rules. However you can extend them with your own implementations.
To add new custom rules, follow these steps:
- implement your new rule as a class and extend it from `\PASVL\Validation\Rules\Rule`
- implement a new rule locator by extending a class `\PASVL\Validation\Rules\RuleLocator`
- configure your validator like this:
```php
$builder = ValidatorBuilder::forArray($pattern)->withLocator(new MyLocator()); // set your new locator
$validator = $builder->build();
```
## Built-in Rules
This package comes with a few built-in rules and their corresponding sub-rules (see in folder `src/Validation/Rules/Library`):
- `:string` - the value must be string
- `:regexp()` - provide a regular expression(the same as for `preg_match()`)
- `:url`
- `:email`
- `:uuid`
- `:contains()`
- `:starts()`
- `:ends()`
- `:in(,,...)`
- `:len()`
- `:max()`
- `:min()`
- `:between(,)`
- `:number`
- `:max()`
- `:min()`
- `:between(, )`
- `:int` - the number must be an integer
- `:float` - the number must be a float
- `:positive`
- `:negative`
- `:in(,,)` - the number must be within values (type coercion possible)
- `:inStrict(,,)` - the number must be within values (type coercion disabled)
- `:exact()`
- `:bool()` - the value must be boolean, if optional argument is given the value must be exactly it
- `:object`
- `:instance()`
- `:propertyExists()`
- `:methodExists()`
- `:array`
- `:count()`
- `:keys(,,...)`
- `:min()` - min count
- `:max()` - max count
- `:between(, )` - count must be within
- `:any` - a placeholder, any value will match
## Hints
- PHP casts "1" to 1 for array keys:
```php
$data = ["12" => ""];
$pattern_invalid = [":string" => ""];
$pattern_valid = [":number :int" => ""];
```
- Technically speaking PASVL is a non-deterministic backtracking parser, and thus it can't always show you what exact key did not match the pattern. That is because, say, a key can match different patterns and there is no way of knowing which one was meant to be correct. In such cases it returns a message like "no matches found at X level".
## 🏆 Contributors
- **[Greg Corrigan](https://github.com/corrigang)**. Greg spotted a problem with nullable values reported as invalid.
- **Henry Combrinck**. Henry tested the library extensively on real data and found tricky bugs and edge cases. Awesome contribution to make the package valuable to the community.
- **[@Averor](https://github.com/Averor)**. Found a bug in parentheses parsing.
- **[Julien Gidel](https://github.com/JuGid)**. Improved `regexp` sub-rule.
## License
This project is licensed under the terms of the MIT license.