2011-11-25 22:12:12 +01:00
|
|
|
Respect Validation [![Build Status](https://secure.travis-ci.org/Respect/Validation.png)](http://travis-ci.org/Respect/Validation)
|
2011-02-07 02:35:35 +01:00
|
|
|
==================
|
|
|
|
|
|
|
|
Respect\Validation is the most awesome validation engine ever created for PHP. Featuring:
|
|
|
|
|
2011-02-08 23:10:58 +01:00
|
|
|
- Fluent/Chained builders like `v::numeric()->positive()->between(1, 256)->validate($myNumber)` (more samples below)
|
2011-02-07 02:35:35 +01:00
|
|
|
- Composite validation (nested, grouped and related rules)
|
|
|
|
- Informative, awesome exceptions
|
|
|
|
- More than 30 fully tested validators
|
|
|
|
- PHP 5.3 only
|
|
|
|
- Possible integration with Zend 2.0 and Symfony 2.0 validators
|
|
|
|
|
2011-02-07 15:46:08 +01:00
|
|
|
Roadmap
|
|
|
|
-------
|
|
|
|
|
2011-02-08 23:10:58 +01:00
|
|
|
1. Validation message improvements (translation, contextualization)
|
|
|
|
2. Custom validators (create your own validation rules and exceptions)
|
2011-02-08 19:18:49 +01:00
|
|
|
3. PHPDocs for all classes, methods and files
|
|
|
|
4. End user complete docs
|
2011-02-07 15:46:08 +01:00
|
|
|
|
2011-02-08 23:10:58 +01:00
|
|
|
Installation
|
|
|
|
============
|
|
|
|
|
|
|
|
**CAUTION**, this is not ready for production! Use it just for fun until a
|
|
|
|
stable version comes out.
|
|
|
|
|
|
|
|
1. PEAR Package
|
|
|
|
|
2011-05-04 17:09:08 +02:00
|
|
|
Instructions on [our PEAR Channel](http://respect.github.com/pear)
|
2011-02-08 23:10:58 +01:00
|
|
|
|
|
|
|
2. Direct Download
|
|
|
|
|
|
|
|
Just click "Download" up there, in GitHub and use the library folder.
|
|
|
|
|
|
|
|
Autoloading
|
|
|
|
-----------
|
|
|
|
|
|
|
|
You can set up Respect\Validation for autoloading. We recommend using the
|
|
|
|
SplClassLoader. Here's a nice sample:
|
|
|
|
|
|
|
|
|
|
|
|
set_include_path('/my/library' . PATH_SEPARATOR . get_include_path());
|
|
|
|
require_once 'SplClassLoader.php';
|
|
|
|
$respectLoader = new \SplClassLoader();
|
|
|
|
$respectLoader->register();
|
|
|
|
|
|
|
|
|
|
|
|
Running Tests
|
|
|
|
-------------
|
|
|
|
|
|
|
|
We didn't created hundreds of tests just for us to apreciate. To run them,
|
|
|
|
you'll need phpunit 3.5 or greater. Then, just chdir into the `/tests` folder
|
|
|
|
we distribute and run them like this:
|
|
|
|
|
|
|
|
cd /my/RespectValidation/tests
|
|
|
|
phpunit .
|
|
|
|
|
|
|
|
You can tweak the phpunit.xml under that `/tests` folder to your needs.
|
|
|
|
|
2011-02-07 15:46:08 +01:00
|
|
|
Feature Guide
|
|
|
|
=============
|
2011-02-07 02:35:35 +01:00
|
|
|
|
|
|
|
Namespace import
|
|
|
|
----------------
|
|
|
|
|
2011-02-07 15:46:08 +01:00
|
|
|
Respect\Validation is namespaced, but you can make your life easier by importing
|
|
|
|
a single class into your context:
|
|
|
|
|
2011-02-07 15:22:30 +01:00
|
|
|
<?php
|
2011-02-07 02:35:35 +01:00
|
|
|
use Respect\Validation\Validator as v;
|
|
|
|
|
|
|
|
Simple validation
|
|
|
|
-----------------
|
|
|
|
|
2011-02-07 15:46:08 +01:00
|
|
|
The Hello World validator is something like this:
|
|
|
|
|
2011-02-07 15:22:30 +01:00
|
|
|
$number = 123;
|
|
|
|
v::numeric()->validate($number); //true
|
2011-02-07 02:35:35 +01:00
|
|
|
|
|
|
|
Chained validation
|
|
|
|
------------------
|
|
|
|
|
2011-02-07 15:46:08 +01:00
|
|
|
It is possible to group and chain several validators:
|
|
|
|
|
2011-02-07 02:35:35 +01:00
|
|
|
//From 1 to 15 non-whitespace alphanumeric characters
|
|
|
|
$validUsername = v::alnum()
|
|
|
|
->noWhitespace()
|
2011-02-07 15:22:30 +01:00
|
|
|
->length(1,15);
|
2011-02-07 02:35:35 +01:00
|
|
|
|
2011-02-07 15:22:30 +01:00
|
|
|
$validUsername->validate('alganet'); //true
|
2011-02-07 02:35:35 +01:00
|
|
|
|
|
|
|
Validating object attributes
|
|
|
|
----------------------------
|
2011-02-07 15:46:08 +01:00
|
|
|
|
|
|
|
You can validate attributes of objects or keys of arrays and its values too:
|
2011-02-07 15:22:30 +01:00
|
|
|
|
|
|
|
$validUser = v::attribute('username', $validUsername) //reusing!
|
|
|
|
->attribute('birthdate', v::date('Y-m-d'));
|
2011-02-07 02:35:35 +01:00
|
|
|
|
|
|
|
$user = new \stdClass;
|
2011-02-07 15:22:30 +01:00
|
|
|
$user->username = 'alganet';
|
2011-02-07 02:35:35 +01:00
|
|
|
$user->birthdate = '1987-07-01';
|
2011-02-07 15:22:30 +01:00
|
|
|
|
|
|
|
$validUser->validate($user); //true
|
2011-02-07 02:35:35 +01:00
|
|
|
|
|
|
|
Validator reuse (works on nested, big validators too!)
|
|
|
|
------------------------------------------------------
|
|
|
|
|
2011-02-07 15:46:08 +01:00
|
|
|
Once created, you can reuse your validator anywhere:
|
|
|
|
|
2011-02-07 15:22:30 +01:00
|
|
|
$validUsername->validate('respect'); //true
|
|
|
|
$validUsername->validate('alexandre gaigalas'); //false
|
|
|
|
$validUsername->validate('#$%'); //false
|
2011-02-07 02:35:35 +01:00
|
|
|
|
|
|
|
Cool, informative exceptions
|
|
|
|
----------------------------
|
|
|
|
|
2011-02-07 15:46:08 +01:00
|
|
|
Respect\Validation produces a tree of validation messages that reflects
|
|
|
|
the groups, nests and composite validators you declared. The following code:
|
2011-02-07 15:22:30 +01:00
|
|
|
|
2011-02-07 02:35:35 +01:00
|
|
|
try {
|
2011-02-07 15:22:30 +01:00
|
|
|
$validUsername->assert('really messed up screen#name');
|
2011-02-07 02:35:35 +01:00
|
|
|
} catch(\InvalidArgumentException $e) {
|
|
|
|
echo $e->getFullMessage();
|
|
|
|
}
|
|
|
|
|
2011-02-07 15:22:30 +01:00
|
|
|
Produces this message:
|
|
|
|
|
2011-02-08 23:10:58 +01:00
|
|
|
\-All of the 3 required rules must pass
|
|
|
|
|-"really messed up screen#name" must contain only letters (a-z), digits (0-9) and "_"
|
|
|
|
|-"really messed up screen#name" must not contain whitespace
|
|
|
|
\-"really messed up screen#name" must have a length between 1 and 15
|
2011-02-07 15:22:30 +01:00
|
|
|
|
2011-02-07 15:46:08 +01:00
|
|
|
Validation Methods
|
|
|
|
------------------
|
|
|
|
|
|
|
|
There are three different ways to validate something:
|
|
|
|
|
|
|
|
$validUsername->validate('alganet'); //returns true or false (quicker)
|
|
|
|
$validUsername->check('alganet'); //throws only the first error found (quicker)
|
|
|
|
$validUsername->assert('alganet'); //throws all of the errors found (slower)
|
|
|
|
|
2011-02-07 02:35:35 +01:00
|
|
|
Message finding on nested Exceptions
|
|
|
|
------------------------------------
|
|
|
|
|
2011-02-07 15:46:08 +01:00
|
|
|
Nested exceptions are cool, but sometimes you need to retrieve a single message
|
|
|
|
from the validator. In these cases you can use the findRelated() method. Consider
|
|
|
|
the following scenario:
|
2011-02-07 15:22:30 +01:00
|
|
|
|
|
|
|
$validBlogPost = v::object()
|
|
|
|
->attribute('title', v::string()->length(1,32))
|
|
|
|
->attribute('author', $validUser) //reuse!
|
|
|
|
->attribute('date', v::date())
|
|
|
|
->attribute('text', v::string());
|
|
|
|
|
|
|
|
$blogPost = new \stdClass;
|
|
|
|
$blogPost->author = clone $validUser;
|
|
|
|
$blogPost->author->username = '# invalid #';
|
|
|
|
|
2011-02-07 15:46:08 +01:00
|
|
|
Then, the following validation code:
|
2011-02-07 15:22:30 +01:00
|
|
|
|
2011-02-07 02:35:35 +01:00
|
|
|
try {
|
2011-02-07 15:22:30 +01:00
|
|
|
$validBlogPost->assert($blogPost);
|
2011-02-07 02:35:35 +01:00
|
|
|
} catch (\InvalidArgumentException $e) {
|
2011-04-29 21:00:39 +02:00
|
|
|
echo $e->findRelated('author.username.noWhitespace')->getMainMessage();
|
2011-02-07 02:35:35 +01:00
|
|
|
}
|
|
|
|
|
2011-02-07 15:22:30 +01:00
|
|
|
Finds the specific noWhitespace message inside author->username and prints it:
|
|
|
|
|
2011-02-08 23:10:58 +01:00
|
|
|
>"# invalid #" must not contain whitespace
|
2011-02-07 15:22:30 +01:00
|
|
|
|
2011-03-31 00:06:59 +02:00
|
|
|
You can export the messages as a plain array to use in template engines for example:
|
|
|
|
|
|
|
|
try {
|
|
|
|
$validBlogPost->assert($blogPost);
|
|
|
|
} catch (\InvalidArgumentException $e) {
|
|
|
|
$messages = $e->findMessages('author.username.noWhitespace', 'title');
|
|
|
|
}
|
|
|
|
|
2011-04-29 21:00:39 +02:00
|
|
|
You can also set runtime templates for those found messages:
|
|
|
|
|
|
|
|
try {
|
|
|
|
$validBlogPost->assert($blogPost);
|
|
|
|
} catch (\InvalidArgumentException $e) {
|
|
|
|
$messages = $e->findMessages(
|
|
|
|
'author.username.noWhitespace' => 'Author username must not have any whitespace',
|
2011-04-29 21:17:20 +02:00
|
|
|
'title' => 'Article title is invalid. You provided {{input}}'
|
2011-04-29 21:00:39 +02:00
|
|
|
);
|
|
|
|
}
|
2011-03-31 00:06:59 +02:00
|
|
|
|
2011-02-07 02:35:35 +01:00
|
|
|
Using Zend and/or Symfony validators
|
|
|
|
------------------------------------
|
|
|
|
|
2011-02-07 15:46:08 +01:00
|
|
|
It is also possible to reuse validators from other frameworks (you need to put them
|
|
|
|
in your autoload routines):
|
|
|
|
|
2011-05-03 15:32:49 +02:00
|
|
|
$validHostName = v::zend('Hostname')->assert('google.com');
|
|
|
|
$validTime = v::sf('Time')->assert('22:00:01');
|
2011-02-07 02:35:35 +01:00
|
|
|
|
2011-02-07 15:46:08 +01:00
|
|
|
Quick Reference
|
|
|
|
==============
|
2011-02-07 02:35:35 +01:00
|
|
|
|
2011-02-07 15:46:08 +01:00
|
|
|
A quick, possibly incomplete, list of validators and use reference:
|
|
|
|
|
|
|
|
Alphanumeric:
|
|
|
|
|
|
|
|
v::alnum()->assert('abc 123');
|
|
|
|
v::alnum('_|')->assert('a_bc _1|23');
|
|
|
|
|
|
|
|
Alpha chars:
|
|
|
|
|
|
|
|
v::alpha()->assert('ab c');
|
|
|
|
v::alpha('.')->assert('a. b.c');
|
|
|
|
|
|
|
|
Check if it is an array (works on every Traversable, Countable ArrayAccess):
|
|
|
|
|
|
|
|
v::arr()->assert(array());
|
|
|
|
v::arr()->assert(new \ArrayObject);
|
|
|
|
|
|
|
|
An attribute of an object ant its value:
|
|
|
|
|
|
|
|
$myObject = new \stdClass;
|
|
|
|
$myObject->foo = "bar";
|
|
|
|
v::attribute("foo", v::string())->assert($myObject);
|
|
|
|
|
|
|
|
Between (works on numbers, digits and dates):
|
|
|
|
|
|
|
|
v::between(5, 15)->assert(10);
|
|
|
|
v::between('a', 'f')->assert('b');
|
|
|
|
|
|
|
|
A value after a function call (works with closures):
|
|
|
|
|
|
|
|
v::call('implode', v::int())->assert(array(1, 2, 3, 4));
|
|
|
|
|
|
|
|
Validates using the return of a callback:
|
|
|
|
|
|
|
|
v::callback('is_string')->assert('something');
|
|
|
|
|
|
|
|
Dates and date formats:
|
|
|
|
|
|
|
|
v::date('Y-m-d')->assert('2010-10-10');
|
|
|
|
v::date()->assert('Jan 10 2008');
|
|
|
|
|
|
|
|
Strings with digits:
|
2011-02-07 02:35:35 +01:00
|
|
|
|
2011-02-07 15:46:08 +01:00
|
|
|
v::digits()->assert('02384');
|
2011-02-07 02:35:35 +01:00
|
|
|
|
2011-02-07 15:46:08 +01:00
|
|
|
Iterates and validates each element:
|
|
|
|
|
|
|
|
v::each(v::hexa())->assert(array('AF', 'D1', '09'));
|
|
|
|
|
|
|
|
Check for equality:
|
|
|
|
|
|
|
|
v::equals('foobar')->assert('foobar');
|
|
|
|
|
|
|
|
Float numbers
|
|
|
|
|
|
|
|
v::float()->assert(1.5);
|
|
|
|
|
|
|
|
Hexadecimals:
|
|
|
|
|
|
|
|
v::hexa()->assert('FAFAF');
|
|
|
|
|
|
|
|
Checks if a value is inside a set:
|
|
|
|
|
|
|
|
v::in(array(1, 1, 2, 3, 5, 8))->assert(5);
|
|
|
|
|
|
|
|
Checks if an object is instance of a specific class or interface:
|
|
|
|
|
|
|
|
v::instance('\stdClass')->assert(new \stdClass);
|
|
|
|
|
|
|
|
Integer numbers:
|
|
|
|
|
|
|
|
v::int()->assert(1548);
|
|
|
|
|
|
|
|
IP addresses:
|
|
|
|
|
|
|
|
v::ip()->assert('200.226.220.222');
|
|
|
|
|
|
|
|
Length of strings, arrays or everything Countable:
|
|
|
|
|
|
|
|
v::length(5, 10)->assert('foobar');
|
|
|
|
v::length(5, 10)->assert(array(1, 2, 3, 4, 5));
|
|
|
|
|
|
|
|
Max and Min:
|
|
|
|
|
|
|
|
v::max(5)->assert(3);
|
|
|
|
v::min(5)->assert(7);
|
|
|
|
|
|
|
|
Positive and Negative:
|
|
|
|
|
|
|
|
v::negative()->assert(-5);
|
|
|
|
v::positive()->assert(3);
|
|
|
|
|
2011-02-21 01:53:21 +01:00
|
|
|
Starts with and Ends with:
|
|
|
|
|
|
|
|
v::startsWith('Hello')->assert('Hello World');
|
|
|
|
v::endsWith('World')->assert('Hello World');
|
|
|
|
|
2011-02-07 15:46:08 +01:00
|
|
|
Whitespace, empty and null
|
|
|
|
|
|
|
|
v::noWhitespace()->assert('abc');
|
|
|
|
v::notEmpty()->assert('aaa');
|
|
|
|
v::nullValue()->assert(null);
|
|
|
|
|
|
|
|
Numeric values of all kinds:
|
|
|
|
|
|
|
|
v::numeric()->assert(1.56e-5);
|
|
|
|
|
|
|
|
Objects:
|
|
|
|
|
|
|
|
v::object()->assert(new \DateTime());
|
|
|
|
|
|
|
|
Regex evaluations:
|
|
|
|
|
|
|
|
v::regex('^[a-f]+$')->assert('abcdef');
|
|
|
|
|
|
|
|
Strings:
|
|
|
|
|
|
|
|
v::string()->assert('Hello World');
|
|
|
|
|
|
|
|
AllOf (checks all validators inside a composite):
|
|
|
|
|
|
|
|
v::allOf(
|
|
|
|
v::string(), //any string v::length(5, 20), //between 5 and 20 chars
|
|
|
|
v::noWhitespace() //no whitespace allowed
|
|
|
|
)->assert('alganet');
|
|
|
|
|
|
|
|
v::string()
|
|
|
|
->length(5, 20)
|
|
|
|
->noWhitespace()
|
|
|
|
->assert('alganet');
|
|
|
|
|
|
|
|
OneOf (checks for one valid inside of a composite):
|
|
|
|
|
|
|
|
$v = v::oneOf(
|
|
|
|
v::int()->positive(), //positive integer or;
|
|
|
|
v::float()->negative(), //negative float or;
|
|
|
|
v::nullValue() //null
|
|
|
|
);
|
|
|
|
$v->assert(null); //true
|
|
|
|
$v->assert(12); //true
|
|
|
|
$v->assert(-1.1); //true
|
|
|
|
|
2011-03-21 17:24:39 +01:00
|
|
|
License Information
|
|
|
|
===================
|
|
|
|
|
|
|
|
Copyright (c) 2009-2011, Alexandre Gomes Gaigalas.
|
|
|
|
All rights reserved.
|
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without modification,
|
|
|
|
are permitted provided that the following conditions are met:
|
|
|
|
|
2011-03-21 19:30:23 +01:00
|
|
|
* Redistributions of source code must retain the above copyright notice,
|
|
|
|
this list of conditions and the following disclaimer.
|
2011-03-21 17:24:39 +01:00
|
|
|
|
2011-03-21 19:30:23 +01:00
|
|
|
* Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
this list of conditions and the following disclaimer in the documentation
|
|
|
|
and/or other materials provided with the distribution.
|
|
|
|
|
|
|
|
* Neither the name of Alexandre Gomes Gaigalas nor the names of its
|
|
|
|
contributors may be used to endorse or promote products derived from this
|
|
|
|
software without specific prior written permission.
|
2011-03-21 17:24:39 +01:00
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
|
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
|
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
|
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
|
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|