Using contexts

Contextual validation is a must for every serious validation library. After all, validation can differ greatly based on the context that's being executed. Take for example the difference between inserting some values into a database, and updating the values:

$v = new Validator;
$v->context('insert', function(Validator $context) {
    $context->required('first_name')->lengthBetween(2, 30);
});

$v->context('update', function(Validator $context) {
    $context->optional('first_name')->lengthBetween(2, 30);
});

$v->validate([], 'update')->isValid(); // bool(true)
$v->validate([], 'insert')->isValid(); // bool(false), because first_name is required.

Copying from another context

In the above example, you'll see that the length condition was written twice, once for insert, and once for update. That's generally not a good idea, because when your rules are updated, you're likely going to forget one of the two places it happened.

To prevent this, Particle\Validator has something called context copying:

$v = new Validator;
$v->context('insert', function(Validator $context) {
    $context->required('first_name')->lengthBetween(2, 30);
});

$v->context('update', function(Validator $context) {
    // copy the rules (and messages) of the "insert" context.
    $context->copyContext('insert');

    // make the "first_name" field optional.
    $context->optional('first_name');
});

$result = $v->validate([], 'update');
$result->isValid(); // bool(true)

Extended example of copying

As you could see in the previous example, it's possible to re-use the rules of an existing context in a new context. However, in the "update" context every key should be optional, so adding a new rule to the "insert" context would probably break the "update" context, because that value is then required. This, too, can be easily fixed.

$v = new Validator;
$v->context('insert', function(Validator $context) {
    $context->required('first_name')->lengthBetween(2, 30);
    $context->required('last_name')->lengthBetween(2, 30);
});

$v->context('update', function(Validator $context) {
    // copy the rules (and messages) of the "insert" context.
    $context->copyContext('insert', function($rules) {
        foreach ($rules as $key => $chain) {
            $context->optional($key);
        }
    });
});