-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:
Alexandre 2011-02-08 20:10:58 -02:00
parent 51ad2948ac
commit 4e068bf204
60 changed files with 484 additions and 176 deletions

View file

@ -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
------------------------------------

View file

@ -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();
}

View file

@ -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',
);
}

View file

@ -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"'
);
}

View file

@ -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;
}

View file

@ -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',
);
}

View file

@ -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',
);
}

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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();
}
}

View file

@ -6,7 +6,7 @@ class CallbackException extends ValidationException
{
public static $defaultTemplates = array(
self::STANDARD => '"%s" is invalid',
self::STANDARD => '%s must be valid',
);
}

View file

@ -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;
}

View file

@ -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)',
);
}

View file

@ -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',
);
}

View file

@ -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;
}

View file

@ -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',
);
}

View file

@ -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',
);
}

View file

@ -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)',
);
}

View file

@ -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',
);
}

View file

@ -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',
);
}

View file

@ -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',
);
}

View file

@ -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',
);
}

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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',
);
}

View file

@ -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',
);
}

View file

@ -6,7 +6,7 @@ class NoWhitespaceException extends ValidationException
{
public static $defaultTemplates = array(
self::STANDARD => '"%s" contains whitespace',
self::STANDARD => '%s must not contain whitespace',
);
}

View file

@ -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',
);
}

View file

@ -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;
}
}

View file

@ -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',
);
}

View file

@ -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',
);
}

View file

@ -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',
);
}

View file

@ -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',
);
}

View file

@ -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',
);
}

View file

@ -6,7 +6,7 @@ class RegexException extends ValidationException
{
public static $defaultTemplates = array(
self::STANDARD => '"%s" is invalid',
self::STANDARD => '%s must validate against %s',
);
}

View file

@ -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',
);
}

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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)

View file

@ -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;
}

View file

@ -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)

View file

@ -17,7 +17,6 @@ class Attribute extends AbstractRelated
'Invalid attribute/property name'
);
parent::__construct($reference, $referenceValidator, $mandatory);
$this->setName($reference);
}
protected function getReferenceValue($input)

View file

@ -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);
}
}

View file

@ -15,4 +15,5 @@ class Call extends AbstractRelated
return is_callable($this->reference);
}
}

View file

@ -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);

View file

@ -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)

View file

@ -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;
}

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -16,7 +16,6 @@ class Key extends AbstractRelated
'Invalid array key name'
);
parent::__construct($reference, $referenceValidator, $mandatory);
$this->setName($reference);
}
protected function getReferenceValue($input)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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);

View file

@ -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());
}

View 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, '');
}
}

View file

@ -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);
}

View file

@ -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');
}
}