PHPackages                             lezhnev74/pasvl - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. lezhnev74/pasvl

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

lezhnev74/pasvl
===============

Array Validator (regular expressions for nested array, sort of)

1.1.0(1mo ago)5259.7k↑22.8%63MITPHPPHP &gt;=8.2CI failing

Since Jan 5Pushed 4y ago2 watchersCompare

[ Source](https://github.com/lezhnev74/pasvl)[ Packagist](https://packagist.org/packages/lezhnev74/pasvl)[ RSS](/packages/lezhnev74-pasvl/feed)WikiDiscussions master Synced 2w ago

READMEChangelog (1)Dependencies (8)Versions (27)Used By (3)

[![Latest Stable Version](https://camo.githubusercontent.com/debfeb443ed0c63d372e89629bbc6dec95eb656c09b70dc81b779672b0b02e96/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6c657a686e657637342f706173766c2e737667)](https://packagist.org/packages/lezhnev74/pasvl)[![CI](https://github.com/lezhnev74/pasvl/actions/workflows/ci.yml/badge.svg)](https://github.com/lezhnev74/pasvl/actions/workflows/ci.yml)[![codecov](https://camo.githubusercontent.com/b40a8d1ac3c5129700e10ba45b96031ff04ee47574505d0c124926ee690606c2/68747470733a2f2f636f6465636f762e696f2f67682f6c657a686e657637342f706173766c2f6272616e63682f6d61737465722f67726170682f62616467652e737667)](https://codecov.io/gh/lezhnev74/pasvl)[![PHPStan](https://camo.githubusercontent.com/0729e562e10fac943b16dbb271b4af26488f779a33fc82cc3eef1e37a432c0b4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c253230352d627269676874677265656e2e737667)](https://phpstan.org/)[![Total Downloads](https://camo.githubusercontent.com/dd9478d314a728ad2726048fa6fb39c4c6a20d29eb7b1b58a2403d7594c4c461/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6c657a686e657637342f706173766c2e737667)](https://packagist.org/packages/lezhnev74/pasvl)[![License](https://camo.githubusercontent.com/5ef6f3ba4cd477635c50251214e635974547535571a347a72f45eba04723bf93/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6c657a686e657637342f706173766c2e737667)](https://packagist.org/packages/lezhnev74/pasvl)

PASVL - PHP Array Structure Validation Library
==============================================

[](#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
------------

[](#installation)

```
composer require lezhnev74/pasvl

```

Example
-------

[](#example)

Refer to files in `Example` folder.

Usage
-----

[](#usage)

### Array Validation

[](#array-validation)

```
// 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.
    // The message names the closest pattern key and the reason it failed,
    // e.g. "at [user->age]: the value is not a number (got 30x)".
    echo "failed: " . $e->getMessage() . "\n";

    // Structured access is also available for programmatic handling:
    $e->path;   // ['user', 'age'] - full path to the failing element (may be null)
    $e->reason; // "the value is not a number" - the underlying rule message (may be null)
}
```

### Optional String Validation

[](#optional-string-validation)

```
$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
-------------------

[](#validation-language)

This package supports a special dialect for validation specification. It looks like this:

[![](pasvl.jpg)](pasvl.jpg)

#### Short language reference:

[](#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:

    ```
      $pattern = [":string *" => ":number"];
      // the above pattern matches data:
      $data = ["june"=>10, "aug" => "11"];
    ```

#### Pattern Definitions

[](#pattern-definitions)

- as exact value ```
    $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 ```
    $pattern = ["name" => ":string?"]; // the value must be a string or null
    ```
- as rule with subrules ```
    $pattern = ["name" => ":string :regexp('#\d*#')"]; // the value must be a string which contains only digits
    ```
- as rule with quantifiers ```
    $pattern = [":string {2}" => ":any"]; // data must have exactly two string keys
    ```

#### Compound Definitions

[](#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
------------

[](#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: ```
    $builder = ValidatorBuilder::forArray($pattern)->withLocator(new MyLocator()); // set your new locator
    $validator = $builder->build();
    ```

Built-in Rules
--------------

[](#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` - accepts numeric strings by default (e.g. `'1'` passes) due to `is_numeric` coercion
    - `:strict` - reject numeric strings; only real int/float pass (e.g. `'1'` fails)
    - `: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(
