New validators for numbers (digits, float, hexa, etc), alpha, regex, generic between, ip addresses. Improvements on several existent validators.

This commit is contained in:
Alexandre Gomes Gaigalas 2010-10-18 02:26:02 -02:00
parent d934d5c28e
commit f18d700b9f
43 changed files with 823 additions and 45 deletions

View file

@ -4,7 +4,7 @@ namespace Respect\Validation\Exceptions;
use InvalidArgumentException;
class AttributeNotPresentException extends InvalidArgumentException
class AttributeNotPresentException extends InvalidException
{
}

View file

@ -4,7 +4,7 @@ namespace Respect\Validation\Exceptions;
use Exception;
class CallbackException extends Exception
class CallbackException extends InvalidException
{
}

View file

@ -2,9 +2,9 @@
namespace Respect\Validation\Exceptions;
use Exception;
use InvalidArgumentException;
class ComponentException extends Exception
class ComponentException extends InvalidArgumentException
{
}

View file

@ -2,9 +2,7 @@
namespace Respect\Validation\Exceptions;
use OutOfBoundsException;
class DateOutOfBoundsException extends OutOfBoundsException
class DateOutOfBoundsException extends InvalidException
{
}

View file

@ -2,9 +2,7 @@
namespace Respect\Validation\Exceptions;
use LengthException;
class EmptyStringException extends LengthException
class EmptyStringException extends InvalidException
{
}

View file

@ -2,9 +2,7 @@
namespace Respect\Validation\Exceptions;
use InvalidArgumentException;
class InvalidDate extends InvalidArgumentException
class InvalidDate extends InvalidException
{
}

View file

@ -0,0 +1,8 @@
<?php
namespace Respect\Validation\Exceptions;
class InvalidIpException extends InvalidException
{
}

View file

@ -0,0 +1,8 @@
<?php
namespace Respect\Validation\Exceptions;
class NotAlphaException extends InvalidException
{
}

View file

@ -2,9 +2,7 @@
namespace Respect\Validation\Exceptions;
use InvalidArgumentException;
class NotAlphanumericException extends InvalidArgumentException
class NotAlphanumericException extends InvalidException
{
}

View file

@ -0,0 +1,8 @@
<?php
namespace Respect\Validation\Exceptions;
class NotBetweenException extends InvalidException
{
}

View file

@ -0,0 +1,8 @@
<?php
namespace Respect\Validation\Exceptions;
class NotDigitsException extends InvalidException
{
}

View file

@ -0,0 +1,8 @@
<?php
namespace Respect\Validation\Exceptions;
class NotFloatException extends InvalidException
{
}

View file

@ -0,0 +1,8 @@
<?php
namespace Respect\Validation\Exceptions;
class NotHexadecimalException extends InvalidException
{
}

View file

@ -2,9 +2,7 @@
namespace Respect\Validation\Exceptions;
use InvalidArgumentException;
class NotNullException extends InvalidArgumentException
class NotNullException extends InvalidException
{
}

View file

@ -2,9 +2,7 @@
namespace Respect\Validation\Exceptions;
use InvalidArgumentException;
class NotNumericException extends InvalidArgumentException
class NotNumericException extends InvalidException
{
}

View file

@ -2,8 +2,7 @@
namespace Respect\Validation\Exceptions;
use OutOfBoundsException;
class NumberOutOfBoundsException extends OutOfBoundsException
class NumberOutOfBoundsException extends InvalidException
{
}

View file

@ -0,0 +1,10 @@
<?php
namespace Respect\Validation\Exceptions;
use Exception;
class RegexException extends InvalidException
{
}

View file

@ -2,9 +2,7 @@
namespace Respect\Validation\Exceptions;
use LengthException;
class StringLengthException extends LengthException
class StringLengthException extends InvalidException
{
}

View file

@ -2,9 +2,7 @@
namespace Respect\Validation\Exceptions;
use InvalidArgumentException;
class WhitespaceFoundException extends InvalidArgumentException
class WhitespaceFoundException extends InvalidException
{
}

View file

@ -23,7 +23,7 @@ class Alnum extends AbstractRule
public function validate($input)
{
return (boolean) preg_match(
"#^[a-zA-Z0-9\s{$this->additionalChars}]+$#", $input
"#^[a-zA-Z0-9{$this->additionalChars}]+$#", $input
);
}

View file

@ -0,0 +1,48 @@
<?php
namespace Respect\Validation\Rules;
use Respect\Validation\Rules\AbstractRule;
use Respect\Validation\Exceptions\NotAlphaException;
class Alpha extends AbstractRule
{
const MSG_NOT_ALPHA = 'Alpha_1';
const MSG_NOT_ALPHA_ADDITIONAL = 'Alpha_2';
protected $messageTemplates = array(
self::MSG_NOT_ALPHA => '%s does not contains only letters',
self::MSG_NOT_ALPHA_ADDITIONAL => '%s does not contains only letters (including %s)'
);
protected $additionalChars = '';
public function __construct($additionalChars='')
{
$this->additionalChars = $additionalChars;
}
public function validate($input)
{
return (boolean) preg_match(
"#^[a-zA-Z{$this->additionalChars}]+$#", $input
);
}
public function assert($input)
{
if (!$this->validate($input))
if (empty($this->additionalChars))
throw new NotAlphaException(
sprintf($this->getMessageTemplate(self::MSG_NOT_ALPHA),
$input)
);
else
throw new NotAlphaException(
sprintf(
$this->getMessageTemplate(self::MSG_NOT_ALPHA_ADDITIONAL),
$input, $this->additionalChars
)
);
return true;
}
}

View file

@ -0,0 +1,89 @@
<?php
namespace Respect\Validation\Rules;
use \Exception;
use Respect\Validation\Validator;
use Respect\Validation\Rules\AbstractRule;
use Respect\Validation\Exceptions\NotBetweenException;
use Respect\Validation\Exceptions\ComponentException;
use Respect\Validation\Validatable;
class Between extends AbstractRule
{
protected $min;
protected $max;
protected $type;
const MSG_LESS = 'Between_1';
const MSG_MORE = 'Between_2';
protected $messageTemplates = array(
self::MSG_LESS => '%s is less than the specified minimum of %s',
self::MSG_MORE => '%s is more than the specified maximum of %s',
);
public function __construct($min=null, $max=null, Validatable $type=null)
{
$this->min = $min;
$this->max = $max;
$this->type = $type;
if (!is_null($min) && !is_null($max) && $min > $max)
throw new ComponentException(
sprintf(
'%s cannot be less than %s for validation', $this->min,
$this->max
)
);
if (is_null($type))
return;
try {
$type->assert($min);
$type->assert($max);
} catch (Exception $e) {
throw new ComponentException(
$e->getMessage()
);
}
}
public function validateMin($input)
{
return is_null($this->min) || $input >= $this->min;
}
public function validateMax($input)
{
return is_null($this->max) || $input <= $this->max;
}
public function validate($input)
{
return (is_null($this->type) || $this->type->validate($input))
&& $this->validateMin($input)
&& $this->validateMax($input);
}
public function assert($input)
{
if (!is_null($this->type))
$this->type->assert($input);
if (!$this->validateMin($input))
throw new NotBetweenException(
sprintf(
$this->getMessageTemplate(self::MSG_LESS),
$this->getStringRepresentation($input),
$this->getStringRepresentation($this->min)
)
);
if (!$this->validateMax($input))
throw new NotBetweenException(
sprintf(
$this->getMessageTemplate(self::MSG_MORE),
$this->getStringRepresentation($input),
$this->getStringRepresentation($this->max)
)
);
return true;
}
}

View file

@ -2,10 +2,11 @@
namespace Respect\Validation\Rules;
use DateTime;
use Respect\Validation\Rules\AbstractDate;
use Respect\Validation\Exceptions\InvalidDate;
class Date extends AbstractDate
class Date extends AbstractDate
{
const MSG_INVALID_DATE = 'Date_1';
const MSG_INVALID_FORMAT = 'Date_2';
@ -21,6 +22,8 @@ class Date extends AbstractDate
public function validate($input)
{
if ($input instanceof DateTime)
return true;
if (is_null($this->format))
return (boolean) strtotime($input);
else
@ -38,8 +41,8 @@ class Date extends AbstractDate
else
throw new InvalidDate(
sprintf(
$this->getMessageTemplate(static::MSG_INVALID_FORMAT), $input,
$this->format
$this->getMessageTemplate(static::MSG_INVALID_FORMAT),
$input, $this->format
)
);

View file

@ -0,0 +1,29 @@
<?php
namespace Respect\Validation\Rules;
use Respect\Validation\Rules\AbstractRule;
use Respect\Validation\Exceptions\NotDigitsException;
class Digits extends AbstractRule
{
const MSG_NOT_DIGITS = 'Digits_1';
protected $messageTemplates = array(
self::MSG_NOT_DIGITS => '%s does not contain only digits'
);
public function validate($input)
{
return ctype_digit((string) $input);
}
public function assert($input)
{
if (!$this->validate($input))
throw new NotDigitsException(
sprintf($this->getMessageTemplate(self::MSG_NOT_DIGITS), $input)
);
return true;
}
}

View file

@ -0,0 +1,29 @@
<?php
namespace Respect\Validation\Rules;
use Respect\Validation\Rules\AbstractRule;
use Respect\Validation\Exceptions\NotFloatException;
class Float extends AbstractRule
{
const MSG_NOT_FLOAT = 'Float_1';
protected $messageTemplates = array(
self::MSG_NOT_FLOAT => '%s is not a valid float number'
);
public function validate($input)
{
return filter_var($input, FILTER_VALIDATE_FLOAT);
}
public function assert($input)
{
if (!$this->validate($input))
throw new NotFloatException(
sprintf($this->getMessageTemplate(self::MSG_NOT_FLOAT), $input)
);
return true;
}
}

View file

@ -0,0 +1,30 @@
<?php
namespace Respect\Validation\Rules;
use Respect\Validation\Rules\AbstractRule;
use Respect\Validation\Exceptions\NotHexadecimalException;
class Hexa extends AbstractRule
{
const MSG_NOT_HEXADECIMAL = 'Hexa_1';
protected $messageTemplates = array(
self::MSG_NOT_HEXADECIMAL => '%s is not a valid hexadecimal number'
);
public function validate($input)
{
return ctype_xdigit($input);
}
public function assert($input)
{
if (!$this->validate($input))
throw new NotHexadecimalException(
sprintf($this->getMessageTemplate(self::MSG_NOT_HEXADECIMAL),
$input)
);
return true;
}
}

View file

@ -0,0 +1,37 @@
<?php
namespace Respect\Validation\Rules;
use Respect\Validation\Rules\AbstractRule;
use Respect\Validation\Exceptions\InvalidIpException;
class Ip extends AbstractRule
{
const MSG_NOT_IP = 'Ip_1';
public $options;
protected $messageTemplates = array(
self::MSG_NOT_IP => '%s is not a valid IP address'
);
public function __construct($options=null)
{
$this->options = $options;
}
public function validate($input)
{
return filter_var(
$input, FILTER_VALIDATE_IP, array('flags' => $this->options)
);
}
public function assert($input)
{
if (!$this->validate($input))
throw new InvalidIpException(
sprintf($this->getMessageTemplate(self::MSG_NOT_IP), $input)
);
return true;
}
}

View file

@ -5,7 +5,7 @@ namespace Respect\Validation\Rules;
use Respect\Validation\Rules\AbstractRule;
use Respect\Validation\Exceptions\NotNumericException;
class Numeric extends AbstractRule
class Numeric extends AbstractRule
{
const MSG_NOT_NUMERIC = 'Numeric_1';
protected $messageTemplates = array(

View file

@ -0,0 +1,38 @@
<?php
namespace Respect\Validation\Rules;
use Respect\Validation\Rules\AbstractRule;
use Respect\Validation\Exceptions\RegexException;
class Regex extends AbstractRule
{
const MSG_REGEX = 'Regex_1';
protected $messageTemplates = array(
self::MSG_REGEX => '%s does not validate against the provided regular expression: %s.'
);
protected $regex;
public function __construct($regex)
{
$this->regex = $regex;
}
public function validate($input)
{
return preg_match("/{$this->regex}/", $input);
}
public function assert($input)
{
if (!$this->validate($input))
throw new RegexException(
sprintf(
$this->getMessageTemplate(self::MSG_REGEX),
$this->getStringRepresentation($input), $this->regex
)
);
return true;
}
}

View file

@ -22,7 +22,10 @@ class Sf extends AbstractRule
$sfMirrorConstraint = new ReflectionClass(
'Symfony\Component\Validator\Constraints\\' . $this->name
);
$this->constraint = $sfMirrorConstraint->newInstanceArgs($params);
if ($sfMirrorConstraint->hasMethod('__construct'))
$this->constraint = $sfMirrorConstraint->newInstanceArgs($params);
else
$this->constraint = $sfMirrorConstraint->newInstance();
}
public function validate($input)

View file

@ -48,12 +48,14 @@ class StringLength extends AbstractRule
public function validateMin($input)
{
return is_null($this->min) || mb_strlen($input) >= $this->min;
$input = mb_strlen($input);
return is_null($this->min) || $input >= $this->min;
}
public function validateMax($input)
{
return is_null($this->max) || mb_strlen($input) <= $this->max;
$input = mb_strlen($input);
return is_null($this->max) || $input <= $this->max;
}
public function validate($input)

View file

@ -15,8 +15,14 @@ class Zend extends AbstractRule
public function __construct($name, $params=array())
{
$zendMirror = new ReflectionClass('Zend\Validator\\' . ucfirst($name));
$this->zendValidator = $zendMirror->newInstanceArgs($params);
$validatorName = explode('_', $name);
$validatorName = array_map('ucfirst', $validatorName);
$validatorName = implode('\\', $validatorName);
$zendMirror = new ReflectionClass('Zend\Validator\\' . $validatorName);
if ($zendMirror->hasMethod('__construct'))
$this->zendValidator = $zendMirror->newInstanceArgs($params);
else
$this->zendValidator = $zendMirror->newInstance();
}
public function validate($input)

View file

@ -43,6 +43,7 @@ class AlnumTest extends \PHPUnit_Framework_TestCase
array('_', ''),
array('', ''),
array('dgç', ''),
array('alganet alganet', ''),
);
}

View file

@ -0,0 +1,53 @@
<?php
namespace Respect\Validation\Rules;
class AlphaTest extends \PHPUnit_Framework_TestCase
{
/**
* @dataProvider providerForValidAlpha
*/
public function testAlphaValid($validAlpha, $aditional)
{
$validator = new Alpha($aditional);
$this->assertTrue($validator->validate($validAlpha));
}
/**
* @dataProvider providerForInvalidAlpha
* @expectedException Respect\Validation\Exceptions\NotAlphaException
*/
public function testAlphaInvalid($invalidAlpha, $aditional)
{
$validator = new Alpha($aditional);
$validator->assert($invalidAlpha);
}
public function providerForValidAlpha()
{
return array(
array('alganet', ''),
array('a', ''),
array('foobar', ''),
array('rubinho_', '_'),
array('google.com', '.'),
array('al ganet', ' '),
);
}
public function providerForInvalidAlpha()
{
return array(
array('@#$', ''),
array('_', ''),
array('', ''),
array('dgç', ''),
array('1abc', ''),
array('alganet alganet', ''),
array('123', ''),
array(123, ''),
);
}
}

View file

@ -0,0 +1,101 @@
<?php
namespace Respect\Validation\Rules;
use Respect\Validation\Validator;
use \DateTime;
class BetweenTest extends \PHPUnit_Framework_TestCase
{
public function providerValid()
{
$n = Validator::numeric();
$d = Validator::date();
return array(
array(0, 1, 0, $n),
array(0, 1, 1, $n),
array(10, 20, 15, $n),
array(10, 20, 20, $n),
array(-10, 20, -5, $n),
array(-10, 20, 0, $n),
array(
new DateTime('yesterday'),
new DateTime('tomorrow'),
new DateTime('now'),
$d
),
);
}
public function providerInvalid()
{
$n = Validator::numeric();
return array(
array(0, 1, 2, $n),
array(0, 1, -1, $n),
array(10, 20, 999, $n),
array(-10, 20, -11, $n),
);
}
public function providerInvalidComponentParameters()
{
$n = Validator::numeric();
return array(
array('a', 1, 1, $n),
array(0, ' ', 1, $n),
);
}
public function providerInvalidInput()
{
$n = Validator::numeric();
return array(
array(10, 20, 'zas a', $n),
array(-10, 20, ' ', $n)
);
}
/**
* @dataProvider providerValid
*/
public function testBetweenBounds($min, $max, $input, $type)
{
$o = new Between($min, $max, $type);
$this->assertTrue($o->assert($input));
$o = new Between($min, $max);
$this->assertTrue($o->assert($input));
}
/**
* @dataProvider providerInvalid
* @expectedException Respect\Validation\Exceptions\NotBetweenException
*/
public function testNotBetweenBounds($min, $max, $input, $type)
{
$o = new Between($min, $max, $type);
$this->assertTrue($o->assert($input));
}
/**
* @dataProvider providerInvalidComponentParameters
* @expectedException Respect\Validation\Exceptions\ComponentException
*/
public function testComponentParameters($min, $max, $input, $type)
{
$o = new Between($min, $max, $type);
$this->assertTrue($o->assert($input));
}
/**
* @dataProvider providerInvalidInput
* @expectedException Respect\Validation\Exceptions\InvalidException
*/
public function testInvalidInput($min, $max, $input, $type)
{
$o = new Between($min, $max, $type);
$this->assertTrue($o->assert($input));
}
}

View file

@ -2,6 +2,8 @@
namespace Respect\Validation\Rules;
use DateTime;
class DateTest extends \PHPUnit_Framework_TestCase
{
@ -22,6 +24,11 @@ class DateTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($this->object->validate('today'));
}
public function testDateInstance()
{
$this->assertTrue($this->object->validate(new DateTime('today')));
}
public function testInvalidDateWithoutFormat()
{
$this->assertFalse($this->object->validate('aids'));

View file

@ -0,0 +1,57 @@
<?php
namespace Respect\Validation\Rules;
class DigitsTest extends \PHPUnit_Framework_TestCase
{
protected $object;
protected function setUp()
{
$this->object = new Digits;
}
/**
* @dataProvider providerForDigits
*
*/
public function testDigits($input)
{
$this->assertTrue($this->object->assert($input));
}
/**
* @dataProvider providerForNotDigits
* @expectedException Respect\Validation\Exceptions\NotDigitsException
*/
public function testNotDigits($input)
{
$this->assertTrue($this->object->assert($input));
}
public function providerForDigits()
{
return array(
array(165),
array(1650),
array('165'),
array('1650'),
);
}
public function providerForNotDigits()
{
return array(
array(null),
array('a'),
array(' '),
array('Foo'),
array(''),
array('12.1'),
array('-12'),
array(-12),
);
}
}

View file

@ -0,0 +1,53 @@
<?php
namespace Respect\Validation\Rules;
class FloatTest extends \PHPUnit_Framework_TestCase
{
protected $object;
protected function setUp()
{
$this->object = new Float;
}
/**
* @dataProvider providerForFloat
*
*/
public function testFloat($input)
{
$this->assertTrue($this->object->assert($input));
}
/**
* @dataProvider providerForNotFloat
* @expectedException Respect\Validation\Exceptions\NotFloatException
*/
public function testNotFloat($input)
{
$this->assertTrue($this->object->assert($input));
}
public function providerForFloat()
{
return array(
array(165.0),
array('165.7'),
array(1e12),
);
}
public function providerForNotFloat()
{
return array(
array(null),
array('a'),
array(' '),
array('Foo'),
array(''),
);
}
}

View file

@ -0,0 +1,53 @@
<?php
namespace Respect\Validation\Rules;
class HexaTest extends \PHPUnit_Framework_TestCase
{
protected $object;
protected function setUp()
{
$this->object = new Hexa;
}
/**
* @dataProvider providerForHexa
*
*/
public function testHexa($input)
{
$this->assertTrue($this->object->assert($input));
}
/**
* @dataProvider providerForNotHexa
* @expectedException Respect\Validation\Exceptions\NotHexadecimalException
*/
public function testNotHexa($input)
{
$this->assertTrue($this->object->assert($input));
}
public function providerForHexa()
{
return array(
array('FFF'),
array('15'),
array('DE12FA'),
);
}
public function providerForNotHexa()
{
return array(
array(null),
array('j'),
array(' '),
array('Foo'),
array(''),
);
}
}

View file

@ -0,0 +1,54 @@
<?php
namespace Respect\Validation\Rules;
class IpTest extends \PHPUnit_Framework_TestCase
{
protected $object;
protected function setUp()
{
$this->object = new Ip;
}
/**
* @dataProvider providerForIp
*
*/
public function testIp($input, $options=null)
{
$this->object->options = $options;
$this->assertTrue($this->object->assert($input));
}
/**
* @dataProvider providerForNotIp
* @expectedException Respect\Validation\Exceptions\InvalidIpException
*/
public function testNotIp($input, $options=null)
{
$this->object->options = $options;
$this->assertTrue($this->object->assert($input));
}
public function providerForIp()
{
return array(
array('127.0.0.1'),
);
}
public function providerForNotIp()
{
return array(
array(null),
array('j'),
array(' '),
array('Foo'),
array(''),
array('192.168.0.1', FILTER_FLAG_NO_PRIV_RANGE),
);
}
}

View file

@ -12,9 +12,13 @@ class NumericTest extends \PHPUnit_Framework_TestCase
$this->object = new Numeric;
}
public function testNumeric()
/**
* @dataProvider providerForNumeric
*
*/
public function testNumeric($input)
{
$this->assertTrue($this->object->assert(165));
$this->assertTrue($this->object->assert($input));
}
/**
@ -25,7 +29,19 @@ class NumericTest extends \PHPUnit_Framework_TestCase
{
$this->assertTrue($this->object->assert($input));
}
public function providerForNumeric()
{
return array(
array(165),
array(165.0),
array(-165),
array('165'),
array('165.0'),
array('+165.0'),
);
}
public function providerForNotNumeric()
{
return array(

View file

@ -0,0 +1,23 @@
<?php
namespace Respect\Validation\Rules;
class RegexTest extends \PHPUnit_Framework_TestCase
{
public function testRegexOk()
{
$v = new Regex('w+');
$this->assertTrue($v->assert('wpoiur'));
}
/**
* @expectedException Respect\Validation\Exceptions\RegexException
*/
public function testRegexNot()
{
$v = new Regex('^w+$');
$this->assertTrue($v->assert('w poiur'));
}
}

View file

@ -7,7 +7,7 @@ class ZendTest extends \PHPUnit_Framework_TestCase
public function setUp()
{
if ( ! class_exists('Zend\Version') ) {
if (!class_exists('Zend\Version')) {
$this->markTestSkipped('No ZendFramework installed');
}
}
@ -18,6 +18,11 @@ class ZendTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($v->assert('wp2oiur'));
}
public function testNamespaceOk()
{
$v = new Zend('sitemap_lastmod');
}
/**
* @expectedException Respect\Validation\Exceptions\InvalidException
*/