respect-validation/README.md

376 lines
11 KiB
Markdown
Raw Normal View History

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:
- 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
-------
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
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)
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:
<?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:
$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()
->length(1,15);
2011-02-07 02:35:35 +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:
$validUser = v::attribute('username', $validUsername) //reusing!
->attribute('birthdate', v::date('Y-m-d'));
2011-02-07 02:35:35 +01:00
$user = new \stdClass;
$user->username = 'alganet';
2011-02-07 02:35:35 +01:00
$user->birthdate = '1987-07-01';
$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:
$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 02:35:35 +01:00
try {
$validUsername->assert('really messed up screen#name');
2011-02-07 02:35:35 +01:00
} catch(\InvalidArgumentException $e) {
echo $e->getFullMessage();
}
Produces this message:
\-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: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:
$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 02:35:35 +01:00
try {
$validBlogPost->assert($blogPost);
2011-02-07 02:35:35 +01:00
} catch (\InvalidArgumentException $e) {
echo $e->findRelated('author.username.noWhitespace')->getMainMessage();
2011-02-07 02:35:35 +01:00
}
Finds the specific noWhitespace message inside author->username and prints it:
>"# invalid #" must not contain whitespace
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');
}
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-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);
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.