You may not know that the most awesome validation engine for PHP out there is Respect/Validation. If you do, this is tailored for you!
All rules on Respect/Validation are meant to be used together, composing a more complex validation rule that is closer to the domain of your application than the existing ones, let's try an example:
<?php
use Respect\Validation\Validator as v;
// Value Object of some imaginary application
$user = new StdClass;
$user->name = 'augustohp';
$user->id = 1;
$user->twitter = 'augustohp';
$usernameRule = v::stringType()->alnum()->between(3,35);
$userRule = v::attribute('name', $usernameRule)
->attribute('id', v::intType()->positive())
->attribute('twitter', $usernameRule);
$userRule->validate($user); // `true`
If you don't understand anything above, go to Respect\Validation documentation. If you never seen the documentation, take an overview of the existing rules there, you are definitely want to build yours upon them.
The "important" thing I want you to notice is the $usernameRule
and the way
we re-use it on two different occasions. Every chain of rules return a new
validator which can be used to compose others. Having a composite of many rules
is useful when a validation fails: you have a very specific error message
on why it failed.
So, chaining existing rules together is easy. After you get used to it you will start composing your rules to validate stuff more coherent with you business, and you will want these rules everywhere!
Every Respect\Validation validation rule follows this criteria:
- Implements the
Respect\Validation\Validatable
interface. - Belongs to a
<vendor>\Rules
namespace. - Has a counterpart Exception class:
- Inside
<vendor>\Exceptions
namespace. - Named
<Rule Name>Exception
. - Implements
Respect\Validation\Exceptions\ExceptionInterface
.
- Inside
Every rule on Respect\Validation can be instantiated alone as a regular object, so keep this in mind while creating yours. You basically have two ways of creating you rule:
- Implementing interfaces and having full control of what you want.
- Extending existing rules made to compose others.
Generally you probably want to extend an existing rule which will enable you to compose existing rules much like you are used to. If you want to do something fancy and have full control of it, you can (and should probably share with us also).
We will cover both methods, in the future. Let's do the easy one first.
As we said before, rules were meant to be composed and used together. Rules are
also stand alone instances. It is pretty easy to think everything is static due
to the static builder providing the fluent interface (v::int()->positive()
),
that first call is static just for the sake of usage, what it is really doing
is:
<?php
use Respect\Validation\Rules;
$rule = new Rules\AllOf(
new Rules\Int(),
new Rules\Positive
);
Everything passed to AllOf
rule as an argument to its constructor is added to
a rule list which must pass validation. As you are probably used to v::
all
the things, you probably want to extend that class and create you own:
<?php
namespace Acme\Validation\Rules;
use Respect\Validation\Rules;
class Twitter extends Rules\AllOf
{
public function __construct()
{
parent::__construct(
new Rules\StringType(),
new Rules\NoWithespace(),
new Rules\Alnum('_'),
new Rules\Between(1, 15, $inclusive = true)
);
}
}
That should provide you the means of using v::twitter()
in next minutes, we
still need a fancy and great message when things go bad, so:
<?php
namespace Acme\Validation\Rules;
use Respect\Validation\Exceptions;
class TwitterException extends Exceptions\AllOfException
{
/**
* We will use the same messages templates as
* the "AllOf" exception, so nothing is needed
* here.
*
* Just. The silence.
* http://tardis.wikia.com/wiki/The_Silence
*/
}
You have everything to go, you just need to tell Respect\Validation of your new fancy namespace with rules:
<?php
use Respect\Validation\Validator as v;
v::with('Acme\\Validation\\Rules');
After that, you are ready to v::twitter()
all the things now. And of course,
still use old rules together with new ones and so on.
Hey, take a look at existing rules. Really. You may find interesting stuff
like OneOf
, NoneOf
, In
, etc.
I did everything, Respect/Validation says it cannot find my custom rule.
Make sure you rule follows all required criteria:
- It belongs on a namespace
<My Name>\Rules\<Rule Name>
(the rule must belong to aRules
namespace). - It has an exception following the criteria.
Also, be sure that Respect\Validation\Validator::with()
method is called before you try using the rule.
Why every rule should have its own Exception?
It is way too little effort to create a new class and be able to catch specific exceptions of specific rules anywhere. If anywhere in the chain of rules you create you try to cheat this, probability has you will regret that soon enough you want to catch that bastard coming from below into the stack.
my custom rule works fine on my local machine, but on live server it says
Type: Respect\Validation\Exceptions\ComponentException
Message: "customRule" is not a valid rule name
File: /home/project/vendor/respect/validation/library/Validator.php
Line: 231
I can't figure it out.