mirror of
https://github.com/Respect/Validation.git
synced 2024-06-03 14:22:16 +02:00
-Messages are now imperative ("foo must be bar") instead of informative ("foo is not bar").
-Several improvements on the messaging system and error reporting, lots of refactored code. -Validators can now be safely named $val->setName('My Field'), and that name will reflect on the validation message ("My Field must be bla bla bla" instead of "incorrect value" must be bla bla bla)
This commit is contained in:
parent
51ad2948ac
commit
4e068bf204
63
README.md
63
README.md
|
@ -3,7 +3,7 @@ Respect Validation
|
|||
|
||||
Respect\Validation is the most awesome validation engine ever created for PHP. Featuring:
|
||||
|
||||
- Fluent/Chained builders
|
||||
- Fluent/Chained builders like `v::numeric()->positive()->between(1, 256)->validate($myNumber)` (more samples below)
|
||||
- Composite validation (nested, grouped and related rules)
|
||||
- Informative, awesome exceptions
|
||||
- More than 30 fully tested validators
|
||||
|
@ -13,11 +13,58 @@ Respect\Validation is the most awesome validation engine ever created for PHP. F
|
|||
Roadmap
|
||||
-------
|
||||
|
||||
1. Custom validators (create your own validation rules and exceptions)
|
||||
2. Validation message improvements (translation, contextualization)
|
||||
1. Validation message improvements (translation, contextualization)
|
||||
2. Custom validators (create your own validation rules and exceptions)
|
||||
3. PHPDocs for all classes, methods and files
|
||||
4. End user complete docs
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
**CAUTION**, this is not ready for production! Use it just for fun until a
|
||||
stable version comes out.
|
||||
|
||||
1. PEAR Package
|
||||
|
||||
Respect\Validation is available under a downloadable PEAR Package. To use it,
|
||||
type the following commands in your terminal:
|
||||
|
||||
git clone git://github.com/Respect/Validation.git RespectValidation
|
||||
cd RespectValidation/library/Respect/Validation/
|
||||
sudo pear install package.xml
|
||||
|
||||
On Ubuntu, this will install it under `/usr/share/php`, make sure you add
|
||||
that to your include_path.
|
||||
|
||||
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.
|
||||
|
||||
Feature Guide
|
||||
=============
|
||||
|
||||
|
@ -87,10 +134,10 @@ the groups, nests and composite validators you declared. The following code:
|
|||
|
||||
Produces this message:
|
||||
|
||||
\-None of 3 required rules passed
|
||||
|-"really messed up screen#name" does not contain only letters, digits and "_"
|
||||
|-"really messed up screen#name" contains whitespace
|
||||
\-"really messed up screen#name" length is not between 1 and 15
|
||||
\-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
|
||||
|
||||
Validation Methods
|
||||
------------------
|
||||
|
@ -128,7 +175,7 @@ Then, the following validation code:
|
|||
|
||||
Finds the specific noWhitespace message inside author->username and prints it:
|
||||
|
||||
>"# invalid #" contains whitespace
|
||||
>"# invalid #" must not contain whitespace
|
||||
|
||||
Using Zend and/or Symfony validators
|
||||
------------------------------------
|
||||
|
|
|
@ -7,11 +7,11 @@ class AbstractCompositeException extends AbstractRelatedException
|
|||
const NONE = 0;
|
||||
const SOME = 1;
|
||||
public static $defaultTemplates = array(
|
||||
self::NONE => 'None of the rules passed',
|
||||
self::SOME => '%2$d rules did not passed',
|
||||
self::NONE => 'All of the %3$d required rules must pass for %1$s',
|
||||
self::SOME => 'These %2$d rules must pass for %1$s',
|
||||
);
|
||||
|
||||
public function chooseTemplate($input, $numFailed, $numRequired, $numTotal)
|
||||
public function chooseTemplate($name, $numFailed, $numRequired, $numTotal)
|
||||
{
|
||||
return $numFailed === $numTotal ? static::NONE : static::SOME;
|
||||
}
|
||||
|
@ -19,7 +19,9 @@ class AbstractCompositeException extends AbstractRelatedException
|
|||
public function getMainMessage()
|
||||
{
|
||||
if (1 === count($this->related))
|
||||
return $this->related[0]->getMainMessage();
|
||||
return $this->related[0]
|
||||
->setName($this->getName())
|
||||
->getMainMessage();
|
||||
else
|
||||
return parent::getMainMessage();
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@ class AllOfException extends AbstractCompositeException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::NONE => 'None of %3$d required rules passed',
|
||||
self::SOME => '%2$d of %3$d required rules did not passed',
|
||||
self::NONE => 'All of the %3$d required rules must pass for %1$s',
|
||||
self::SOME => 'These %2$d rules must pass for %1$s',
|
||||
);
|
||||
|
||||
}
|
|
@ -6,8 +6,8 @@ class AlnumException extends AlphaException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '"%s" does not contain only letters and digits',
|
||||
self::EXTRA => '"%s" does not contain only letters, digits and "%s"'
|
||||
self::STANDARD => '%s must contain only letters (a-z) and digits (0-9)',
|
||||
self::EXTRA => '%s must contain only letters (a-z), digits (0-9) and "%s"'
|
||||
);
|
||||
|
||||
}
|
|
@ -7,11 +7,11 @@ class AlphaException extends ValidationException
|
|||
const EXTRA = 1;
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '"%s" does not contain only letters',
|
||||
self::EXTRA => '"%s" does not contain only letters and "%s"'
|
||||
self::STANDARD => '%s must contain only letters (a-z)',
|
||||
self::EXTRA => '%s must contain only letters (a-z) and "%s"'
|
||||
);
|
||||
|
||||
public function chooseTemplate($input, $additionalCharacters=null)
|
||||
public function chooseTemplate($name, $additionalCharacters=null)
|
||||
{
|
||||
return empty($additionalCharacters) ? static::STANDARD : static::EXTRA;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ class ArrException extends ValidationException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '"%s" is not an array',
|
||||
self::STANDARD => '%s must be an array',
|
||||
);
|
||||
|
||||
}
|
|
@ -6,8 +6,8 @@ class AtLeastException extends AbstractCompositeException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::NONE => 'None of %4$d rules passed (%3$d required)',
|
||||
self::SOME => '%2$d of %4$d rules did not passed (%3$d required)',
|
||||
self::NONE => 'At least %3$d of %4$d rules must pass for %1$s',
|
||||
self::SOME => 'At least %3$d of %4$d rules must pass for %1$s, only %2$d passed',
|
||||
);
|
||||
|
||||
}
|
|
@ -7,11 +7,11 @@ class AttributeException extends AbstractRelatedException
|
|||
const NOT_PRESENT = 0;
|
||||
const INVALID = 1;
|
||||
public static $defaultTemplates = array(
|
||||
self::NOT_PRESENT => '%1$s is not present',
|
||||
self::INVALID => '%1$s is invalid',
|
||||
self::NOT_PRESENT => '%1$s must be present',
|
||||
self::INVALID => 'Attribute %2$s must be valid on %1$s',
|
||||
);
|
||||
|
||||
public function chooseTemplate($input, $attributeName, $hasTheAttribute)
|
||||
public function chooseTemplate($name, $attributeName, $hasTheAttribute)
|
||||
{
|
||||
return $hasTheAttribute ? static::INVALID : static::NOT_PRESENT;
|
||||
}
|
||||
|
|
|
@ -4,9 +4,32 @@ namespace Respect\Validation\Exceptions;
|
|||
|
||||
class BetweenException extends ValidationException
|
||||
{
|
||||
const BOTH = 0;
|
||||
const LOWER = 1;
|
||||
const GREATER = 2;
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '"%s" is out of bounds',
|
||||
self::BOTH => '%s must be between %s and %s',
|
||||
self::LOWER => '%s must be greater than %2$s',
|
||||
self::GREATER => '%s must be lower than %3$s',
|
||||
);
|
||||
|
||||
public function configure($name, $min, $max)
|
||||
{
|
||||
return parent::configure(
|
||||
$name, ValidationException::stringify($min), //TODO find a better way
|
||||
ValidationException::stringify($max)
|
||||
);
|
||||
}
|
||||
|
||||
public function chooseTemplate($name, $min, $max)
|
||||
{
|
||||
if (is_null($min))
|
||||
return static::GREATER;
|
||||
elseif (is_null($max))
|
||||
return static::LOWER;
|
||||
else
|
||||
return static::BOTH;
|
||||
}
|
||||
|
||||
}
|
|
@ -2,15 +2,8 @@
|
|||
|
||||
namespace Respect\Validation\Exceptions;
|
||||
|
||||
class CallException extends AbstractRelatedException
|
||||
class CallException extends AbstractCompositeException
|
||||
{
|
||||
|
||||
public function getMainMessage()
|
||||
{
|
||||
if (1 === count($this->related))
|
||||
return $this->related[0]->getMainMessage();
|
||||
else
|
||||
return parent::getMainMessage();
|
||||
}
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@ class CallbackException extends ValidationException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '"%s" is invalid',
|
||||
self::STANDARD => '%s must be valid',
|
||||
);
|
||||
|
||||
}
|
|
@ -7,11 +7,12 @@ class DateException extends ValidationException
|
|||
const FORMAT = 1;
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '"%s" is not a valid date',
|
||||
self::FORMAT => '"%s" is not a valid date (format: %s)'
|
||||
self::STANDARD => '%s must be a valid date',
|
||||
//TODO reformat to reflect number of digits, so Y-m-d becomes YYYY-mm-dd
|
||||
self::FORMAT => '%s must be a valid date in the format %s'
|
||||
);
|
||||
|
||||
public function chooseTemplate($input, $format)
|
||||
public function chooseTemplate($name, $format)
|
||||
{
|
||||
return empty($format) ? static::STANDARD : static::FORMAT;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ class DigitsException extends ValidationException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '"%s" does not contain only digits',
|
||||
self::STANDARD => '%s must contain only digits (0-9)',
|
||||
);
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@ class EachException extends ValidationException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '%4$d invalid itens found (%3$s)',
|
||||
self::STANDARD => 'Each item in %s must be valid',
|
||||
);
|
||||
|
||||
}
|
|
@ -8,11 +8,11 @@ class EqualsException extends ValidationException
|
|||
const IDENTICAL = 0;
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::EQUALS => '"%s" is not equals "%s"',
|
||||
self::IDENTICAL => '"%s" is not identical to "%s"',
|
||||
self::EQUALS => '%s must be equals %s',
|
||||
self::IDENTICAL => '%s must be identical as %s',
|
||||
);
|
||||
|
||||
public function chooseTemplate($input, $equals, $identical)
|
||||
public function chooseTemplate($name, $equals, $identical)
|
||||
{
|
||||
return ($identical) ? static::IDENTICAL : static::EQUALS;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ class FloatException extends ValidationException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '"%s" is not a valid float',
|
||||
self::STANDARD => '%s must be a float number',
|
||||
);
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@ class HexaException extends ValidationException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '"%s" is not a valid hexadecimal number',
|
||||
self::STANDARD => '%s must be a hexadecimal number',
|
||||
);
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@ class InException extends ValidationException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '"%s" is not in %s',
|
||||
self::STANDARD => '%s must be in (%s)',
|
||||
);
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@ class InstanceException extends ValidationException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '"%s" is not an instance of "%s"',
|
||||
self::STANDARD => '%s must be an instance of %s',
|
||||
);
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@ class IntException extends ValidationException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '"%s" is not a valid integer number',
|
||||
self::STANDARD => '%s must be an integer number',
|
||||
);
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@ class IpException extends ValidationException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '"%s" is not a valid IP address',
|
||||
self::STANDARD => '%s must be an IP address',
|
||||
);
|
||||
|
||||
}
|
|
@ -5,4 +5,8 @@ namespace Respect\Validation\Exceptions;
|
|||
class KeyException extends AttributeException
|
||||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::NOT_PRESENT => '%1$s must be present',
|
||||
self::INVALID => 'Key %2$s must be valid on %1$s',
|
||||
);
|
||||
}
|
|
@ -2,26 +2,13 @@
|
|||
|
||||
namespace Respect\Validation\Exceptions;
|
||||
|
||||
class LengthException extends ValidationException
|
||||
class LengthException extends BetweenException
|
||||
{
|
||||
const BOTH = 0;
|
||||
const LOWER = 1;
|
||||
const GREATER = 2;
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::BOTH => '"%s" length is not between %d and %d',
|
||||
self::LOWER => '"%s" length is lower than %2$d',
|
||||
self::GREATER => '"%s" length is greater than %3$d',
|
||||
self::BOTH => '%s must have a length between %d and %d',
|
||||
self::LOWER => '%s must have a length greater than %2$d',
|
||||
self::GREATER => '%s must have a length lower than %3$d',
|
||||
);
|
||||
|
||||
public function chooseTemplate($input, $min, $max)
|
||||
{
|
||||
if (is_null($min))
|
||||
return static::GREATER;
|
||||
elseif (is_null($max))
|
||||
return static::LOWER;
|
||||
else
|
||||
return static::BOTH;
|
||||
}
|
||||
|
||||
}
|
|
@ -4,14 +4,20 @@ namespace Respect\Validation\Exceptions;
|
|||
|
||||
class MaxException extends ValidationException
|
||||
{
|
||||
const INCLUSIVE =1;
|
||||
const INCLUSIVE = 1;
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '%s is greater than %s',
|
||||
self::INCLUSIVE => '%s is greater than %s (inclusive)',
|
||||
self::STANDARD => '%s must be lower than %s',
|
||||
self::INCLUSIVE => '%s must be lower than %s (inclusive)',
|
||||
);
|
||||
|
||||
public function chooseTemplate($input, $inclusive)
|
||||
public function cnofigure($name, $max, $inclusive)
|
||||
{
|
||||
return parent::configure($name, ValidationException::stringify($max),
|
||||
$inclusive);//TODO find a better way
|
||||
}
|
||||
|
||||
public function chooseTemplate($name, $max, $inclusive)
|
||||
{
|
||||
return $inclusive ? static::INCLUSIVE : static::STANDARD;
|
||||
}
|
||||
|
|
|
@ -6,11 +6,17 @@ class MinException extends ValidationException
|
|||
{
|
||||
const INCLUSIVE = 1;
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '%s is lower than %s',
|
||||
self::INCLUSIVE => '%s is lower than %s (inclusive)',
|
||||
self::STANDARD => '%s must be greater than %s',
|
||||
self::INCLUSIVE => '%s must be greater than %s (inclusive)',
|
||||
);
|
||||
|
||||
public function chooseTemplate($input, $inclusive)
|
||||
public function cnofigure($name, $min, $inclusive)
|
||||
{
|
||||
return parent::configure($name, ValidationException::stringify($min),
|
||||
$inclusive);//TODO find a better way
|
||||
}
|
||||
|
||||
public function chooseTemplate($name, $min, $inclusive)
|
||||
{
|
||||
return $inclusive ? static::INCLUSIVE : static::STANDARD;
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@ class MostOfException extends AbstractCompositeException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::NONE => 'None of %3$d required rules passed',
|
||||
self::SOME => '%2$d of %3$d required rules did not passed',
|
||||
self::NONE => 'At least %3$d of %4$d rules must pass for %1$s',
|
||||
self::SOME => 'At least %3$d of %4$d rules must pass, only %2$d passed for %1$s',
|
||||
);
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@ class NegativeException extends ValidationException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '"%s" is not a negative number',
|
||||
self::STANDARD => '%s must be negative',
|
||||
);
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@ class NoWhitespaceException extends ValidationException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '"%s" contains whitespace',
|
||||
self::STANDARD => '%s must not contain whitespace',
|
||||
);
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@ class NoneOfException extends ValidationException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => 'None of the %4$d rules must pass. %2$d passed',
|
||||
self::STANDARD => 'None of these rules must pass for %1$s',
|
||||
);
|
||||
|
||||
}
|
|
@ -4,9 +4,16 @@ namespace Respect\Validation\Exceptions;
|
|||
|
||||
class NotEmptyException extends ValidationException
|
||||
{
|
||||
|
||||
const STANDARD = 0;
|
||||
const NAMED = 1;
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => 'The provided value is empty',
|
||||
self::STANDARD => 'The value must not be empty',
|
||||
self::NAMED => '%s must not be empty',
|
||||
);
|
||||
|
||||
public function chooseTemplate($name)
|
||||
{
|
||||
return empty($name) ? static::STANDARD : static::NAMED;
|
||||
}
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@ class NullValueException extends ValidationException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '"%s" is not a null value',
|
||||
self::STANDARD => '%s must be null',
|
||||
);
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@ class NumericException extends ValidationException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '"%s" is not a numeric value',
|
||||
self::STANDARD => '%s must be numeric',
|
||||
);
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@ class ObjectException extends ValidationException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '"%s" is not an object',
|
||||
self::STANDARD => '%s must be an object',
|
||||
);
|
||||
|
||||
}
|
|
@ -6,8 +6,8 @@ class OneOfException extends AbstractCompositeException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::NONE => 'None of the %4$d rules passed',
|
||||
self::SOME => '%2$d of the %4$d rules did not passed',
|
||||
self::NONE => 'At least one of %4$d rules must pass for %1$s',
|
||||
self::SOME => 'At least one of %4$d rules must pass for %1$s, only %2$d passed',
|
||||
);
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@ class PositiveException extends ValidationException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '"%s" is not a positive number',
|
||||
self::STANDARD => '%s must be positive',
|
||||
);
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@ class RegexException extends ValidationException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '"%s" is invalid',
|
||||
self::STANDARD => '%s must validate against %s',
|
||||
);
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@ class StringException extends ValidationException
|
|||
{
|
||||
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => '"%s" is not a valid string',
|
||||
self::STANDARD => '%s must be a string',
|
||||
);
|
||||
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Respect\Validation\Exceptions;
|
||||
|
||||
use DateTime;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use RecursiveIteratorIterator;
|
||||
|
@ -15,7 +16,7 @@ class ValidationException extends InvalidArgumentException
|
|||
const ITERATE_TREE = 1;
|
||||
const ITERATE_ALL = 2;
|
||||
public static $defaultTemplates = array(
|
||||
self::STANDARD => 'Data validation failed: "%s"'
|
||||
self::STANDARD => 'Data validation failed for %s'
|
||||
);
|
||||
protected $context = null;
|
||||
protected $id = '';
|
||||
|
@ -23,7 +24,7 @@ class ValidationException extends InvalidArgumentException
|
|||
protected $related = array();
|
||||
protected $template = '';
|
||||
|
||||
public static function create($input=null)
|
||||
public static function create($name=null)
|
||||
{
|
||||
$i = new static;
|
||||
if (func_get_args() > 0)
|
||||
|
@ -32,6 +33,21 @@ class ValidationException extends InvalidArgumentException
|
|||
return $i;
|
||||
}
|
||||
|
||||
public static function stringify($value)
|
||||
{
|
||||
if (is_string($value))
|
||||
return $value;
|
||||
elseif (is_object($value))
|
||||
if (method_exists($value, '__toString'))
|
||||
return (string) $value;
|
||||
elseif ($value instanceof DateTime)
|
||||
return $value->format('Y-m-d H:i:s');
|
||||
else
|
||||
return "Object of class " . get_class($value);
|
||||
else
|
||||
return (string) $value;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->getMainMessage();
|
||||
|
@ -48,11 +64,12 @@ class ValidationException extends InvalidArgumentException
|
|||
return key(static::$defaultTemplates);
|
||||
}
|
||||
|
||||
public function configure($input=null)
|
||||
public function configure($name)
|
||||
{
|
||||
$this->message = $this->getMainMessage();
|
||||
$this->params = func_get_args();
|
||||
$this->stringifyInput();
|
||||
foreach ($this->params as &$p)
|
||||
$p = static::stringify($p);
|
||||
$this->message = $this->getMainMessage();
|
||||
$this->guessId();
|
||||
return $this;
|
||||
}
|
||||
|
@ -74,6 +91,11 @@ class ValidationException extends InvalidArgumentException
|
|||
return implode(PHP_EOL, $message);
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->params[0];
|
||||
}
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
|
@ -90,7 +112,7 @@ class ValidationException extends InvalidArgumentException
|
|||
|
||||
public function getMainMessage()
|
||||
{
|
||||
$sprintfParams = $this->params;
|
||||
$sprintfParams = $this->getParams();
|
||||
if (empty($sprintfParams))
|
||||
return $this->message;
|
||||
array_unshift($sprintfParams, $this->getTemplate());
|
||||
|
@ -99,7 +121,10 @@ class ValidationException extends InvalidArgumentException
|
|||
|
||||
public function getParams()
|
||||
{
|
||||
return $this->params;
|
||||
$params = array_slice($this->params, 1);
|
||||
array_unshift($params, $this->getName());
|
||||
return $params;
|
||||
|
||||
}
|
||||
|
||||
public function getRelated()
|
||||
|
@ -120,7 +145,7 @@ class ValidationException extends InvalidArgumentException
|
|||
if (!empty($this->template))
|
||||
return $this->template;
|
||||
$templateKey = call_user_func_array(
|
||||
array($this, 'chooseTemplate'), $this->params
|
||||
array($this, 'chooseTemplate'), $this->getParams()
|
||||
);
|
||||
if (is_null($this->context))
|
||||
$this->template = static::$defaultTemplates[$templateKey];
|
||||
|
@ -142,6 +167,12 @@ class ValidationException extends InvalidArgumentException
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function setName($name)
|
||||
{
|
||||
$this->params[0] = static::stringify($name);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setRelated(array $relatedExceptions)
|
||||
{
|
||||
foreach ($relatedExceptions as $related)
|
||||
|
@ -163,13 +194,4 @@ class ValidationException extends InvalidArgumentException
|
|||
$this->setId($id);
|
||||
}
|
||||
|
||||
protected function stringifyInput()
|
||||
{
|
||||
$param = &$this->params[0];
|
||||
if (!is_object($param) || method_exists($param, '__toString'))
|
||||
$param = (string) $param;
|
||||
else
|
||||
$param = get_class($param);
|
||||
}
|
||||
|
||||
}
|
|
@ -70,13 +70,6 @@ abstract class AbstractComposite extends AbstractRule implements Validatable
|
|||
});
|
||||
}
|
||||
|
||||
public function setName($name)
|
||||
{
|
||||
foreach ($this->getRules() as $r)
|
||||
$r->setName($name);
|
||||
return parent::setName($name);
|
||||
}
|
||||
|
||||
protected function appendRule(Validatable $validator)
|
||||
{
|
||||
$this->rules[spl_object_hash($validator)] = $validator;
|
||||
|
|
|
@ -38,7 +38,8 @@ abstract class AbstractRelated extends AbstractRule implements Validatable
|
|||
} catch (ValidationException $e) {
|
||||
throw $this->reportError($input, array($e));
|
||||
} catch (ReflectionException $e) {
|
||||
throw $this->reportError($input);
|
||||
if ($this->mandatory)
|
||||
throw $this->reportError($input);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -57,7 +58,7 @@ abstract class AbstractRelated extends AbstractRule implements Validatable
|
|||
public function reportError($input, array $relatedExceptions=array())
|
||||
{
|
||||
return parent::reportError($input, $relatedExceptions, $this->reference,
|
||||
!is_null($relatedExceptions))->setId($this->reference);
|
||||
!empty($relatedExceptions))->setId($this->reference);
|
||||
}
|
||||
|
||||
public function validate($input)
|
||||
|
|
|
@ -57,16 +57,18 @@ abstract class AbstractRule implements Validatable
|
|||
return!empty($this->exception);
|
||||
}
|
||||
|
||||
public function reportError($input, array $relatedExceptions=array())
|
||||
public function reportError($input, array $related=array())
|
||||
{
|
||||
if ($this->hasException())
|
||||
return $this->getException();
|
||||
|
||||
$exception = $this->createException()->setRelated($relatedExceptions);
|
||||
$exception = $this->createException()->setRelated($related);
|
||||
$parameters = array();
|
||||
if (func_num_args() > 2)
|
||||
$parameters = array_slice(func_get_args(), 2);
|
||||
array_unshift($parameters, $this->getName() ? : $input);
|
||||
$input = ValidationException::stringify($input);
|
||||
$exceptionInput = $this->getName() ? : "\"$input\"";
|
||||
array_unshift($parameters, $exceptionInput);
|
||||
call_user_func_array(array($exception, 'configure'), $parameters);
|
||||
return $exception;
|
||||
}
|
||||
|
|
|
@ -19,11 +19,9 @@ class Alpha extends AbstractRule
|
|||
$this->additionalChars = $additionalChars;
|
||||
}
|
||||
|
||||
public function assert($input)
|
||||
public function reportError($input, array $related=array())
|
||||
{
|
||||
if (!$this->validate($input))
|
||||
throw $this->reportError($input, array(), $this->additionalChars);
|
||||
return true;
|
||||
return parent::reportError($input, $related, $this->additionalChars);
|
||||
}
|
||||
|
||||
public function validate($input)
|
||||
|
|
|
@ -17,7 +17,6 @@ class Attribute extends AbstractRelated
|
|||
'Invalid attribute/property name'
|
||||
);
|
||||
parent::__construct($reference, $referenceValidator, $mandatory);
|
||||
$this->setName($reference);
|
||||
}
|
||||
|
||||
protected function getReferenceValue($input)
|
||||
|
|
|
@ -8,8 +8,13 @@ use Respect\Validation\Exceptions\ValidationException;
|
|||
class Between extends AllOf
|
||||
{
|
||||
|
||||
protected $min;
|
||||
protected $max;
|
||||
|
||||
public function __construct($min=null, $max=null, $inclusive=false)
|
||||
{
|
||||
$this->min = $min;
|
||||
$this->max = $max;
|
||||
if (!is_null($min) && !is_null($max) && $min > $max)
|
||||
throw new ComponentException(
|
||||
sprintf(
|
||||
|
@ -22,4 +27,9 @@ class Between extends AllOf
|
|||
$this->addRule(new Max($max, $inclusive));
|
||||
}
|
||||
|
||||
public function reportError($input, array $relatedExceptions=array())
|
||||
{
|
||||
return parent::reportError($input, array(), $this->min, $this->max);
|
||||
}
|
||||
|
||||
}
|
|
@ -15,4 +15,5 @@ class Call extends AbstractRelated
|
|||
return is_callable($this->reference);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -18,6 +18,11 @@ class Callback extends AbstractRule
|
|||
$this->callback = $callback;
|
||||
}
|
||||
|
||||
public function reportError($input, array $related=array())
|
||||
{
|
||||
return parent::reportError($input, $related, $this->callback);
|
||||
}
|
||||
|
||||
public function validate($input)
|
||||
{
|
||||
return call_user_func($this->callback, $input);
|
||||
|
|
|
@ -19,13 +19,10 @@ class Date extends AbstractRule
|
|||
$this->format = $format;
|
||||
}
|
||||
|
||||
public function assert($input)
|
||||
public function reportError($input, array $related=array())
|
||||
{
|
||||
if (!$this->validate($input))
|
||||
throw $this->reportError($input, array(), $this->format);
|
||||
return true;
|
||||
return parent::reportError($input, $related, $this->format);
|
||||
}
|
||||
|
||||
public function validate($input)
|
||||
{
|
||||
if ($input instanceof DateTime)
|
||||
|
|
|
@ -27,26 +27,22 @@ class Each extends AbstractRule
|
|||
if (!is_array($input) || $input instanceof Traversable)
|
||||
throw $this->reportError($input);
|
||||
$exceptions = array();
|
||||
$keys = array();
|
||||
foreach ($input as $key => $item) {
|
||||
if (isset($this->itemValidator))
|
||||
try {
|
||||
$this->itemValidator->assert($item);
|
||||
} catch (ValidationException $e) {
|
||||
$exceptions[] = $e;
|
||||
$keys[$key] = $key;
|
||||
}
|
||||
if (isset($this->keyValidator))
|
||||
try {
|
||||
$this->keyValidator->assert($item);
|
||||
} catch (ValidationException $e) {
|
||||
$exceptions[] = $e;
|
||||
$keys[$key] = $key;
|
||||
}
|
||||
}
|
||||
if (!empty($exceptions))
|
||||
throw $this->reportError($input, array(), $item,
|
||||
implode(', ', $keys), count($exceptions));
|
||||
throw $this->reportError($input, $exceptions, count($exceptions));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,11 +14,10 @@ class Equals extends AbstractRule
|
|||
$this->identical = $identical;
|
||||
}
|
||||
|
||||
public function assert($input)
|
||||
public function reportError($input, array $related=array())
|
||||
{
|
||||
if (!$this->validate($input))
|
||||
throw $this->reportError($input, array(), $this->param,
|
||||
$this->identical);
|
||||
return parent::reportError($input, $related, $this->param,
|
||||
$this->identical);
|
||||
}
|
||||
|
||||
public function validate($input)
|
||||
|
|
|
@ -14,12 +14,14 @@ class In extends AbstractRule
|
|||
$this->strict = $strict;
|
||||
}
|
||||
|
||||
public function assert($input)
|
||||
public function reportError($input, array $related=array())
|
||||
{
|
||||
if (!$this->validate($input))
|
||||
throw $this->reportError($input, array(),
|
||||
print_r($this->options, true), $this->strict);
|
||||
return true;
|
||||
if (is_array($this->options))
|
||||
$options = implode(',', $this->options);
|
||||
else
|
||||
$options = $this->options;
|
||||
return parent::reportError($input, $related,
|
||||
$options, $this->strict);
|
||||
}
|
||||
|
||||
public function validate($input)
|
||||
|
|
|
@ -12,11 +12,9 @@ class Instance extends AbstractRule
|
|||
$this->instance = $instance;
|
||||
}
|
||||
|
||||
public function assert($input)
|
||||
public function reportError($input, array $related=array())
|
||||
{
|
||||
if (!$this->validate($input))
|
||||
throw $this->reportError($input, array(), $this->instance);
|
||||
return true;
|
||||
return parent::reportError($input, $related, $this->instance);
|
||||
}
|
||||
|
||||
public function validate($input)
|
||||
|
|
|
@ -16,7 +16,6 @@ class Key extends AbstractRelated
|
|||
'Invalid array key name'
|
||||
);
|
||||
parent::__construct($reference, $referenceValidator, $mandatory);
|
||||
$this->setName($reference);
|
||||
}
|
||||
|
||||
protected function getReferenceValue($input)
|
||||
|
|
|
@ -40,11 +40,9 @@ class Length extends AbstractRule
|
|||
}
|
||||
}
|
||||
|
||||
public function assert($input)
|
||||
public function reportError($input, array $related=array())
|
||||
{
|
||||
if (!$this->validate($input))
|
||||
throw $this->reportError($input, array(), $this->min, $this->max);
|
||||
return true;
|
||||
return parent::reportError($input, $related, $this->min, $this->max);
|
||||
}
|
||||
|
||||
public function validate($input)
|
||||
|
|
|
@ -14,12 +14,10 @@ class Max extends AbstractRule
|
|||
$this->inclusive = $inclusive;
|
||||
}
|
||||
|
||||
public function assert($input)
|
||||
public function reportError($input, array $related=array())
|
||||
{
|
||||
if (!$this->validate($input))
|
||||
throw $this->reportError($input, array(), $this->max,
|
||||
$this->inclusive);
|
||||
return true;
|
||||
return parent::reportError($input, $related, $this->max,
|
||||
$this->inclusive);
|
||||
}
|
||||
|
||||
public function validate($input)
|
||||
|
|
|
@ -14,12 +14,10 @@ class Min extends AbstractRule
|
|||
$this->inclusive = $inclusive;
|
||||
}
|
||||
|
||||
public function assert($input)
|
||||
public function reportError($input, array $related=array())
|
||||
{
|
||||
if (!$this->validate($input))
|
||||
throw $this->reportError($input, array(), $this->min,
|
||||
$this->inclusive);
|
||||
return true;
|
||||
return parent::reportError($input, $related, $this->min,
|
||||
$this->inclusive);
|
||||
}
|
||||
|
||||
public function validate($input)
|
||||
|
|
|
@ -12,13 +12,10 @@ class Regex extends AbstractRule
|
|||
$this->regex = $regex;
|
||||
}
|
||||
|
||||
public function assert($input)
|
||||
public function reportError($input, array $related=array())
|
||||
{
|
||||
if (!$this->validate($input))
|
||||
throw $this->reportError($input, array(), $this->regex);
|
||||
return true;
|
||||
return parent::reportError($input, $related, $this->regex);
|
||||
}
|
||||
|
||||
public function validate($input)
|
||||
{
|
||||
return preg_match("/{$this->regex}/", $input);
|
||||
|
|
|
@ -7,19 +7,21 @@ class ValidationExceptionTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testCreate()
|
||||
{
|
||||
$e = ValidationException::create(new \stdClass, 'bar', array(),
|
||||
new \stdClass);
|
||||
$this->assertEquals(array('stdClass', 'bar', array(), new \stdClass),
|
||||
$e->getParams());
|
||||
$e = ValidationException::create(new \stdClass, 'bar');
|
||||
$this->assertEquals(
|
||||
array('Object of class stdClass', 'bar'),
|
||||
$e->getParams()
|
||||
);
|
||||
$this->assertEquals('validation', $e->getId());
|
||||
}
|
||||
|
||||
public function testConfigure()
|
||||
{
|
||||
$e = new ValidationException;
|
||||
$e->configure(new \stdClass, 'bar', array(), new \stdClass);
|
||||
$e->configure(new \stdClass, 'bar');
|
||||
$this->assertEquals(
|
||||
array('stdClass', 'bar', array(), new \stdClass), $e->getParams()
|
||||
array('Object of class stdClass', 'bar'),
|
||||
$e->getParams()
|
||||
);
|
||||
$this->assertEquals('validation', $e->getId());
|
||||
}
|
||||
|
|
220
tests/library/Respect/Validation/NegativeTest.php
Normal file
220
tests/library/Respect/Validation/NegativeTest.php
Normal file
|
@ -0,0 +1,220 @@
|
|||
<?php
|
||||
|
||||
namespace Respect\Validation;
|
||||
|
||||
use Respect\Validation\Validator as v;
|
||||
use Respect\Validation\Exceptions\ValidationException;
|
||||
|
||||
class NegativeTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/*
|
||||
* Toggle this to show an example of all validation
|
||||
* messages on the PHPUnit console.
|
||||
*/
|
||||
|
||||
protected $showMessages = true;
|
||||
protected $targetName = 'My Field';
|
||||
|
||||
protected function genMessage($validator, $invalidValue)
|
||||
{
|
||||
try {
|
||||
$validator->assert($invalidValue);
|
||||
} catch (ValidationException $e) {
|
||||
if ($this->showMessages)
|
||||
echo 'Default: ' . $e->getFullMessage() . PHP_EOL;
|
||||
}
|
||||
$validator->setName($this->targetName);
|
||||
try {
|
||||
$validator->assert($invalidValue);
|
||||
} catch (ValidationException $e) {
|
||||
if ($this->showMessages)
|
||||
echo 'Named: ' . $e->getFullMessage() . PHP_EOL . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
public function testAlnum()
|
||||
{
|
||||
$this->genMessage(v::alnum(), '#');
|
||||
$this->genMessage(v::alnum('_'), '#');
|
||||
}
|
||||
|
||||
public function testAlpha()
|
||||
{
|
||||
$this->genMessage(v::alpha(), '#');
|
||||
$this->genMessage(v::alpha('.'), '#');
|
||||
}
|
||||
|
||||
public function testArr()
|
||||
{
|
||||
$this->genMessage(v::arr(), '#');
|
||||
}
|
||||
|
||||
public function testAttribute()
|
||||
{
|
||||
$this->genMessage(v::attribute("foo", v::int()),
|
||||
(object) array("foo" => "bar"));
|
||||
$this->genMessage(v::attribute("foo", v::string()), null);
|
||||
}
|
||||
|
||||
public function testBetween()
|
||||
{
|
||||
$this->genMessage(v::between(5, 15), 999);
|
||||
$this->genMessage(v::between('a', 'f'), 15951);
|
||||
$this->genMessage(v::between(new \DateTime('now'),
|
||||
new \DateTime('tomorrow')), new \DateTime('yesterday'));
|
||||
}
|
||||
|
||||
public function testCall()
|
||||
{
|
||||
$this->genMessage(v::call('implode', v::int()), array('x', 2, 3, 4));
|
||||
}
|
||||
|
||||
public function testCallback()
|
||||
{
|
||||
$this->genMessage(v::callback('is_string'), 123);
|
||||
}
|
||||
|
||||
public function testDate()
|
||||
{
|
||||
$this->genMessage(v::date('Y-m-d'), '2010-30-10');
|
||||
$this->genMessage(v::date(), 'Jan 310 2008');
|
||||
}
|
||||
|
||||
public function testDigits()
|
||||
{
|
||||
$this->genMessage(v::digits(), 'x02384');
|
||||
}
|
||||
|
||||
public function testEach()
|
||||
{
|
||||
$this->genMessage(v::each(v::hexa()), array('AF', 'P1', '09'));
|
||||
}
|
||||
|
||||
public function testEquals()
|
||||
{
|
||||
$this->genMessage(v::equals('foobar'), 'aaar');
|
||||
}
|
||||
|
||||
public function testFloat()
|
||||
{
|
||||
$this->genMessage(v::float(), 'dance');
|
||||
}
|
||||
|
||||
public function testHexa()
|
||||
{
|
||||
$this->genMessage(v::hexa(), 'PPAFAF');
|
||||
}
|
||||
|
||||
public function testIn()
|
||||
{
|
||||
$this->genMessage(v::in(array(1, 1, 2, 3, 5, 8)), 9845984);
|
||||
}
|
||||
|
||||
public function testInstance()
|
||||
{
|
||||
$this->genMessage(v::instance('\ss'), new \stdClass);
|
||||
}
|
||||
|
||||
public function testInt()
|
||||
{
|
||||
$this->genMessage(v::int(), 15.48);
|
||||
}
|
||||
|
||||
public function testIp()
|
||||
{
|
||||
$this->genMessage(v::ip(), '200.999.220.222');
|
||||
}
|
||||
|
||||
public function testLength()
|
||||
{
|
||||
$this->genMessage(v::length(5, 10), 'foobarbalzobihbiy');
|
||||
$this->genMessage(v::length(2, 3), array(1, 2, 3, 4, 5));
|
||||
$this->genMessage(v::length(null, 3), array(1, 2, 3, 4, 5));
|
||||
$this->genMessage(v::length(15, null), array(1, 2, 3, 4, 5));
|
||||
}
|
||||
|
||||
public function testMax()
|
||||
{
|
||||
$this->genMessage(v::max(5), 9854);
|
||||
$this->genMessage(v::max(5, true), 9854);
|
||||
}
|
||||
|
||||
public function testMin()
|
||||
{
|
||||
$this->genMessage(v::min(5), -9514);
|
||||
$this->genMessage(v::min(5, true), -9514);
|
||||
}
|
||||
|
||||
public function testNegative()
|
||||
{
|
||||
$this->genMessage(v::negative(), 5);
|
||||
}
|
||||
|
||||
public function testPositive()
|
||||
{
|
||||
$this->genMessage(v::positive(), -3);
|
||||
}
|
||||
|
||||
public function testNoWhitespace()
|
||||
{
|
||||
$this->genMessage(v::noWhitespace(), 'a bc');
|
||||
}
|
||||
|
||||
public function testNotEmpty()
|
||||
{
|
||||
$this->genMessage(v::notEmpty(), '');
|
||||
}
|
||||
|
||||
public function testNullValue()
|
||||
{
|
||||
$this->genMessage(v::nullValue(), true);
|
||||
}
|
||||
|
||||
public function testNumeric()
|
||||
{
|
||||
$this->genMessage(v::numeric(), null);
|
||||
}
|
||||
|
||||
public function testObject()
|
||||
{
|
||||
$this->genMessage(v::object(), null);
|
||||
}
|
||||
|
||||
public function testRegex()
|
||||
{
|
||||
$this->genMessage(v::regex('^[a-f]+$'), 'abcdxxxef');
|
||||
}
|
||||
|
||||
public function testString()
|
||||
{
|
||||
$this->genMessage(v::string(), null);
|
||||
}
|
||||
|
||||
public function testAllOf()
|
||||
{
|
||||
$this->genMessage(v::allOf(
|
||||
v::string(), //any string
|
||||
v::length(5, 20), //between 5 and 20 chars
|
||||
v::noWhitespace() //no whitespace allowed
|
||||
), "# #");
|
||||
|
||||
//same as
|
||||
|
||||
$this->genMessage(v::string()
|
||||
->length(5, 20)
|
||||
->noWhitespace(), '# #');
|
||||
}
|
||||
|
||||
public function testOneOf()
|
||||
{
|
||||
$v = v::oneOf(
|
||||
v::int()->positive(), //positive integer or;
|
||||
v::float()->negative(), //negative float or;
|
||||
v::nullValue() //null
|
||||
);
|
||||
$this->genMessage($v, '');
|
||||
$this->genMessage($v, '');
|
||||
$this->genMessage($v, '');
|
||||
}
|
||||
|
||||
}
|
|
@ -45,8 +45,8 @@ class EachTest extends \PHPUnit_Framework_TestCase
|
|||
*/
|
||||
public function testEachOneInvalidAssertion()
|
||||
{
|
||||
$v = new Each(new NotEmpty());
|
||||
$result = $v->assert(array('', 2, 3, 4, 5));
|
||||
$v = new Each(new Int());
|
||||
$result = $v->assert(array('a', 2, 3, 4, 5));
|
||||
$this->assertFalse($result);
|
||||
}
|
||||
|
||||
|
|
|
@ -263,9 +263,6 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase
|
|||
} catch (\InvalidArgumentException $e) {
|
||||
//echo $e->findRelated('author', 'username', 'noWhitespace')->getMainMessage();
|
||||
}
|
||||
|
||||
$validHostName = v::zend('hostname')->assert('google.com');
|
||||
$validTime = v::sf('time')->assert('22:00:01');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue