krak/validation

Functional validation library

v0.3.11 2018-08-05 10:29 UTC

This package is auto-updated.

Last update: 2024-04-18 16:28:07 UTC


README

The Krak Validation library is a functional and simple approach and interface to validation. It was made out of the need a validation library with a simple interface and configuration. Other leading validators like Respect, Zend, or Symfony have a lot of complexity in their API and adding an actual validator will require adding several classes in some instances.

Krak Validation changes all of this by taking a functional approach to validation where every validator is just a function or instance of Krak\Validation\Validator. This design lends itself easily for extending, custom validators, and decorators. It comes bundled with a Krak\Validation\Kernel which manages validators to provide a simple, fluent, and customizable interface for utilizing validators.

Installation

Install with composer at krak/validation

Usage

<?php

$validation = new Krak\Validation\Kernel();
$validator = $validation->make([
    'name' => 'required|string',
    'age' => 'optional|integer|between:18,25',
]);
$violations = $validator->validate([
    'name' => 'RJ',
    'age' => 17,
]);

if ($violations) { // you can also check $validator->failed()
    print_r($violations->format()); // format into an array of error messages
}

This will print something like this:

Array
(
    [age] => Array
        (
            [0] => The Age field must be between 18 and 25
        )

)

Validators

A validator can be a Krak\Validation\Validator, or any callable that accepts a value and returns null on success and a violation on failure.

Validators implement the following signature:

function($value, array $ctx = [])

The second parameter can typically be left out, but is used to pass additional information into the validator. A good example is a PSR Container so that dependencies can be lazy loaded at time of actual validation.

Violations

Creating violations is easy with the violate or violations function. For most validators, you'll simply be creating one violation.

<?php

use Krak\Validation;

/** enforces that a value equals a specific value */
function equalsStringValidator($match) {
    return function($value, array $ctx = []) use ($match) {
        if ($value == $match) {
            return;
        }

        return Validation\violate('equals_string', [
            'match' => $match
        ]);
    };
}

$v = equalsStringValidator('foo');
$v('foo'); // returns null
$violation = $v('bar'); // return a Krak\Validation\Violation

In some cases, one validator can return multiple violations. In that case, we just use the violations to create a violation collection. You can checkout the Krak\Validation\Validators\collection validator to see how to create a violation collection.

Throwing Violations

Once you have a violation or a violation collection, you can optionally throw them as exceptions to be handled upstream.

<?php

try {
    $violation->abort();
} catch (Krak\Validation\Exception\ViolationException $e) {
    assert($e->violation === $violation);
}

Asserting Data

A very common practice is using the Validation Kernel to make and validate domain data and then throw a ViolationException if any violations occur. This can be done simply via the assert method.

$validation = new Krak\Validation\Kernel();
$validation->make([
    'name' => 'required|string',
    'age' => 'optional|integer|between:18,25',
])->assert(['name' => 'RJ', 'age' => 100]);
// this will have thrown a ViolationException due to the age constraint

You can then easily catch the ViolationException upstream and format the violation into readable errors:

try {
    return response($storeUser($userData), 201);
} catch (Krak\Validation\Exception\ViolationException $e) {
    return response([
        'errors' => $e->violation->format(),
    ], 422);
}

Validation Packages

Validation Packages are simple extensions to the Validation\Kernel that register validators and messages into the system.

Creating a Validation Package

To create a validation package, you need to extend the ValidationPackage interface.

interface ValidationPackage
{
    public function withValidation(Kernel $validation);
}

From there, you can configure the validation kernel any which way you need.

Typically, you'll just use the validators, messages, and aliases methods to add keyed validations and corresponding methods or aliases.

An example Validation Package would look like:

<?php

use Krak\Validation;

class AcmeValidationPackage implements Validation\ValidationPackage
{
    public function withValidation(Validation\Kernel $v) {
        $v->validators([
            'integer' => 'intValidator', // name of intValidator func
            'min' => MinValidator::class // name of MinValidator class
        ]);
        $v->messages([
            'integer' => 'The {{attribute}} is not a valid integer',
            'min' => 'The {{attribute}} size must be greater than or equal to {{min}}',
        ]);
        $v->aliases([
            'int' => 'integer',
        ]);
    }
}

The validators would be defined in different files like so:

use Krak\Validation;

// intValidator.php
function intValidator() {
    return function($v) {
        return !is_int($v) ? Validation\violate('integer') : null;
    };
}

// MinValidator.php
class MinValidator implements Validation\Validator
{
    private $min;

    public function __construct($min) {
        $this->min = $min;
    }

    public function validate($value, array $context = []) {
        return $value < $min ? Validation\violate('min', ['min' => $this->min]) : null;
    }
}

Core Validation Package

The Core Validation package defines a bunch of the normal useful validators.

all alpha alpha_num array
between boolean date digits
double email exists float
in integer length max
min null nullable number
numeric optional regex regex_exclude
required string

all

Validates an array with the given validator. If any element in the array fails the validation, a violation will be returned.

Definition: Krak\Validation\Validators\forAll($validator)

Simple Usage:

$validator->make('all:integer')->validate([1,2,3]);

Advanced Usage:

use function Krak\Validation\Validators\{forAll};
$validator->make(forAll('integer|between:1,3'))->validate([1,2,3])

Standalone Usage:

use function Krak\Validation\Validators\{forAll, typeInteger};

forAll(typeInteger())([2,3]);

alpha

Wraps the ctype_alpha function and validates a string to verify only alpha characteres.

Definition: Krak\Validation\Validators\alpha()

Simple Usage:

$validator->make('alpha')->validate('abc');

Standalone Usage:

use function Krak\Validation\Validators\{alpha};

alpha()('123');

alpha_num

Wraps the ctype_alnum function and validates a string to make sure it's alpha numeric.

Definition: Krak\Validation\Validators\alphaNum()

Simple Usage:

$validator->make('alpah_num')->validate('abc123');

Standalone Usage:

use function Krak\Validation\Validators\{alphaNum};
alphaNum()('abc123');

array

Verifies that the value is an array using is_array.

Definition: Krak\Validation\Validators\typeArray()

Simple Usage:

$validator->make('array')->validate();

Standalone Usage:

use function Krak\Validation\Validators\{typeArray};

typeArray()([]);

between

Validates a value's size is between two values inclusively.

Definition: Krak\Validation\Validators\between($min, $max)

Simple Usage:

$validator->make('between:1,2')->validate(2);

Standalone Usage:

use function Krak\Validation\Validators\{between};

between(1, 2)(2);

boolean

Validates a value is a boolean. true, false, "0", "1", 0, 1 are all instances of boolean.

Definition: Krak\Validation\Validators\typeBoolean()

Simple Usage:

$validator->make('boolean')->validate(true);

Standalone Usage:

use function Krak\Validation\Validators\{typeBoolean};

typeBoolean()(true);

date

Validates a string is a valid date using strototime. Anything that strtotime accepts is accepted here.

Definition: Krak\Validation\Validators\date()

Simple Usage:

$validator->make('date')->validate('2017-08-11');

Standalone Usage:

use function Krak\Validation\Validators\{date};

date()('2017-08-11');

digits

Validates a string is of type digits using the ctype_digits function.

Definition: Krak\Validation\Validators\digits()

Simple Usage:

$validator->make('digits')->validate('123');

Standalone Usage:

use function Krak\Validation\Validators\{digits};

digits()('123');

double

Validates a value is a double using is_double.

Definition: Krak\Validation\Validators\double()

Simple Usage:

$validator->make('double')->validate(4.2);

Standalone Usage:

use function Krak\Validation\Validators\{double};

double()(4.2);

email

Validates that a string matches an email regex.

Definition: Krak\Validation\Validators\regexEmail()

Simple Usage:

$validator->make('email')->validate('username@gmail.com');

Standalone Usage:

use function Krak\Validation\Validators\{regexEmail};

regexEmail()('username@gmail.com');

exists

Alias of required.

float

Validates a value is a float using is_float.

Definition: Krak\Validation\Validators\float()

Simple Usage:

$validator->make('float')->validate(4.2);

Standalone Usage:

use function Krak\Validation\Validators\{float};

float()(4.2);

in

Validates if a values is within a given array.

Definition: Krak\Validation\Validators\inArray

Simple Usage:

$validator->make('in:a,b,c')->validate('b');

Standalone Usage:

use function Krak\Validation\Validators\{inArray};

inArray(['a', 'b', 'c'])('b');

integer

Validates that a value is an integer.

Definition: Krak\Validation\Validators\typeInteger()

Simple Usage:

$validator->make('integer')->validate(1);

Standalone Usage:

use function Krak\Validation\Validators\{typeInteger};

typeInteger()(1);

length

Validates that a value's size is exactly the given length.

Definition: Krak\Validation\Validators\length($size)

Simple Usage:

$validator->make('length:3')->validate('abc');

Standalone Usage:

use function Krak\Validation\Validators\{length};

length()('abc');

max

Validates that a value's size is less than or equal to a given max.

Definition: Krak\Validation\Validators\max($max)

Simple Usage:

$validator->make('max:5')->validate(4);

Standalone Usage:

use function Krak\Validation\Validators\{max};

max(5)(4);

min

Validates that a value's size is greater than or equal to a given min.

Definition: Krak\Validation\Validators\min($min)

Simple Usage:

$validator->make('min:2')->validate(3);

Standalone Usage:

use function Krak\Validation\Validators\{min};

min(2)(3);

null

Validates that a value's type is null.

Definition: Krak\Validation\Validators\typeNull()

Simple Usage:

$validator->make('null')->validate(null);

Standalone Usage:

use function Krak\Validation\Validators\{typeNull};

typeNull()(null);

nullable

Validates that a type is null or not. This is typically used in a chain of validators and will stop validation if the value is null or let the validation continue on else.

Definition: Krak\Validation\Validators\nullable()

Simple Usage:

$v = $validator->make('nullable|integer');
$v->validate(null);
$v->validate(1);

Standalone Usage:

use function Krak\Validation\Validators\{pipe, nullable, typeInteger};

$v = pipe([nullable(), typeInteger()]);
$v(null);
$v(1);

number

Validates that a given value is either a float, double, or integer. This is not the same as is_numeric.

Definition: Krak\Validation\Validators\number()

Simple Usage:

$validator->make('number')->validate(1);

Standalone Usage:

use function Krak\Validation\Validators\{number};

number()(1);

numeric

Validates that a given value is numeric using the is_numeric function.

Definition: Krak\Validation\Validators\typeNumeric()

Simple Usage:

$validator->make('numeric')->validate('1.5');

Standalone Usage:

use function Krak\Validation\Validators\{typeNumeric};

typeNumeric()('1.5');

optional

Validates that a keyed array is optional and is not required to be present in the array. This validator only make sense within the context of a collection.

Definition: Krak\Validation\Validators\optional()

Simple Usage:

$v = $validator->make([
    'id' => 'optional|integer'
]);
$v->validate([]);
$v->validate(['id' => 1])

Standalone Usage:

use function Krak\Validation\Validators\{collection, optional, typeInteger, pipe};

$v = collection([
    'id' => pipe([optional(), typeInteger()])
]);
$v([]);
$v(['id' => 1]);

regex

Validates that a given value is either a float, double, or integer. This is not the same as is_numeric.

Definition: Krak\Validation\Validators\regexMatch($regex, $exclude = false)

Simple Usage:

$validator->make('regex:/a+b/')->validate('aaab');

Note defining a regex via the string can be tricky because of how the validation rule parser will validate |, :, and ,. You'll almost always want to call use actual validator itself.

Advanced Usage:

use function Krak\Validation\Validators\{regexMatch};

$validator->make(regexMatch('/(aa|bb)/'))->validate('aa');

Standalone Usage:

use function Krak\Validation\Validators\{regexMatch};

regexMatch('/(aa|bb)/')('aa');

regex_exclude

Exactly like regex except it matches that the value excludes the specific regular expression.

Definition: Krak\Validation\Validators\regexExclude($regex)

Simple Usage:

$validator->make('regex:/a+b/')->validate('c');

Note defining a regex via the string can be tricky because of how the validation rule parser will validate |, :, and ,. You'll almost always want to call use actual validator itself.

Advanced Usage:

use function Krak\Validation\Validators\{regexExclude};

$validator->make(regexExclude('/(aa|bb)/'))->validate('cc');

Standalone Usage:

use function Krak\Validation\Validators\{regexExclude};

regexExclude('/(aa|bb)/')('cc');

required

Validates that a given value is required in a collection. This validator only makes sense within the context of a collection.

Definition: Krak\Validation\Validators\required()

Simple Usage:

$validator->make([
    'id' => 'required|integer',
])->validate(['id' => 1]);

Standalone Usage:

use function Krak\Validation\Validators\{collection, pipe, typeInteger, required};

collection([
    'id' => pipe([required(), typeInteger()])
])(['id' => 1]);

string

Validates that a given value is a string.

Definition: Krak\Validation\Validators\typeString()

Simple Usage:

$validator->make('string')->validate('a');

Standalone Usage:

use function Krak\Validation\Validators\{typeString};

typeString()('a');

Doctrine Validation Package

The Doctrine Validation Package defines doctrine related validators.

doctrine_all_exist doctrine_entities doctrine_entity doctrine_exists
doctrine_unique doctrine_unique_entity

To enable the doctrine package, you can do the following:

$validation = new Krak\Validation\Kernel();
$validation->withDoctrineValidators();
// only needed for doctrine_entities, doctrine_entity, and doctrine_unique_entity
$validation['Doctrine\Common\Persistence\ObjectManager'] = function() {
    // return a configured entity manager here...
};
$validation['Doctrine\DBAL\Connection'] = function() {
    // return a dbal connection here
};
$validation->context([
    'doctrine.model_prefix' => Acme\Model::class,
]);

doctrine_all_exist

Validates that a set of strings or integers all exist in a given table.

Definition: class Krak\Validation\Validators\Doctrine\AllExist($table_name, $field = 'id', $type = 'int')

Simple Usage:

$validator->make('array|all:integer|doctrine_all_exist:users')->validate([1,2,3]);

Standalone Usage:

use Krak\Validation\Validators\Doctrine\AllExist;
use function Krak\Validation\Validators\{pipe, typeInteger, forAll};

pipe([forAll(typeInteger), new AllExist('users')])([1,2,3]);

doctrine_entities

Validates that a a set of ORM Entities exist from a unique key. The given entity name is joined with the doctrine.model_prefix if one is given.

Definition: class Krak\Validation\Validators\Doctrine\Entities($entity_name, $field = 'id')

Simple Usage:

$validator->make('array|all:integer|doctrine_entities:User')->validate([1,2,3]);

Standalone Usage:

use Krak\Validation\Validators\Doctrine\Entities;
use function Krak\Validation\Validators\{pipe, typeInteger, forAll};

pipe([forAll(typeInteger), new Entities('User')])([1,2,3]);

doctrine_entity

Validates that an entity exists in the db with the given value.

Definition: class Krak\Validation\Validators\Doctrine\Entity($entity_name, $field = 'id')

Simple Usage:

$validator->make('doctrine_entity:User')->validate(1);

Standalone Usage:

use Krak\Validation\Validators\Doctrine\Entity;

(new Entity('User'))->validate(1);

doctrine_exists

Validates that a given value exists in a table in a certain field.

Definition: class Krak\Validation\Validators\Doctrine\Exists($table_name, $field = 'id')

Simple Usage:

$validator->make('doctrine_entity:users')->validate(5);

Standalone Usage:

use Krak\Validation\Validators\Doctrine\Exists;

(new Exists('users'))->validate(5);

doctrine_unique

Validates that a given value is unique and doesn't exist in a table in a field.

Definition: class Krak\Validation\Validators\Doctrine\Unique($table_name, $field = 'id')

Simple Usage:

$validator->make('doctrine_unique:users,email')->validate('username@gmail.com');

Standalone Usage:

use Krak\Validation\Validators\Doctrine\Unique;

(new Unique('users', 'email'))->validate('username@gmail.com');

doctrine_unique_entity

Validates that a given value exists in a table in a certain field.

Definition: class Krak\Validation\Validators\Doctrine\UniqueEntity($entity_name, $field = 'id')

Simple Usage:

$validator->make('doctrine_unique_entity:User,email')->validate('username@gmail.com');

Standalone Usage:

use Krak\Validation\Validators\Doctrine\UniqueEntity;

(new UniqueEntity('User', 'email'))->validate('username@gmail.com');

API

All of the following are defined in the Krak\Validation\Validators namespace.

collection($validators, $err_on_extra = true)

Validates a map of validators with attribute names mapping to other validators. $err_on_extra is a flag that will determine whether or not to validate if extra fields are in the input array.

This function will return either a Violation, ViolationCollection, or null depending on the input value.

toSize($value)

Gets the size of a variable. If string, it returns the string length. If array, it returns the count, else it assumes numeric and returns the value itself.