Fluent interface for Valitation\Validator, draft string validator, better tests, composite validation improvements

This commit is contained in:
Alexandre Gomes Gaigalas 2010-09-24 21:28:03 -03:00
parent 5850afdad5
commit d25f7220dc
12 changed files with 246 additions and 79 deletions

View file

@ -18,7 +18,9 @@ abstract class AbstractCompositeValidator extends AbstractNode
public function addValidator($validator, $arguments=array())
{
$this->appendValidator(Validator::buildValidator($validator, $arguments));
$this->appendValidator(
Validator::buildValidator($validator, $arguments)
);
}
public function hasValidator($validator)
@ -72,7 +74,7 @@ abstract class AbstractCompositeValidator extends AbstractNode
$exceptions = array();
foreach ($validators as $v)
try {
$v->validate($input);
$v->assert($input);
} catch (InvalidException $e) {
$exceptions[] = $e;
}

View file

@ -8,18 +8,18 @@ use Respect\Validation\InvalidException;
class All extends AbstractCompositeValidator
{
public function isValid($input)
public function is($input)
{
$validators = $this->getValidators();
return count($validators) === count(array_filter(
$validators,
function($v) use($input) {
return $v->isValid($input);
return $v->is($input);
}
));
}
public function validate($input)
public function assert($input)
{
$exceptions = $this->iterateValidation($input);
if (!empty($exceptions))
@ -27,5 +27,4 @@ class All extends AbstractCompositeValidator
return true;
}
}

View file

@ -8,7 +8,7 @@ use Respect\Validation\InvalidException;
class One extends AbstractCompositeValidator
{
public function validate($input)
public function assert($input)
{
$validators = $this->getValidators();
$exceptions = $this->iterateValidation($input);
@ -17,12 +17,12 @@ class One extends AbstractCompositeValidator
return true;
}
public function isValid($input)
public function is($input)
{
return (boolean) array_filter(
$this->getValidators(),
function($v) use($input) {
return $v->isValid($input);
return $v->is($input);
}
);
}

View file

@ -15,8 +15,6 @@ class Between extends AbstractDateValidator implements Validatable
self::MSG_OUT_OF_BOUNDS => '%s is not between %s and %s.'
);
public function __construct($min, $max, $format=null)
{
@ -31,10 +29,10 @@ class Between extends AbstractDateValidator implements Validatable
$this->setFormat($format);
}
public function validate($input)
public function assert($input)
{
$target = $this->getDateObject($input);
if (!$this->isValid($target))
if (!$this->is($target))
throw new OutOfBoundsException(
sprintf(
$this->getMessage(self::MSG_OUT_OF_BOUNDS),
@ -45,7 +43,7 @@ class Between extends AbstractDateValidator implements Validatable
return true;
}
public function isValid($input)
public function is($input)
{
$target = $this->getDateObject($input);
return $target >= $this->min and $target <= $this->max;

View file

@ -0,0 +1,23 @@
<?php
namespace Respect\Validation\String;
use Respect\Validation\Validatable;
use Respect\Validation\AbstractNode;
class NotEmpty extends AbstractNode implements Validatable
{
public function is($input)
{
$trimmed = trim($input);
return!empty($trimmed);
}
public function assert($input)
{
if (!$this->is($input))
throw new Exception();
}
}

View file

@ -5,9 +5,9 @@ namespace Respect\Validation;
interface Validatable
{
public function validate($input);
public function assert($input);
public function isValid($input);
public function is($input);
public function getMessages();

View file

@ -4,41 +4,148 @@ namespace Respect\Validation;
use ReflectionClass;
abstract class Validator
class Validator
{
public static function validate($input, $validatorName)
protected $input;
protected $subject;
protected $validator;
protected $arguments;
protected $operation;
public function getOperation()
{
$arguments = func_get_args();
$arguments = array_slice($arguments, 2);
return static::buildValidator($validatorName, $arguments)->validate($input);
return $this->operation;
}
public static function is($input, $validatorName)
public function getInput()
{
$arguments = func_get_args();
$arguments = array_slice($arguments, 2);
return static::buildValidator($validatorName, $arguments)->isValid($input);
return $this->input;
}
public function getSubject()
{
return $this->subject;
}
public function getValidator()
{
return $this->validator;
}
public function getArguments()
{
return $this->arguments;
}
public function setInput($input)
{
$this->input = $input;
}
public function setSubject($subject)
{
$this->subject = $subject;
}
public function setValidator($validator)
{
$this->validator = $validator;
}
public function setArguments(array $arguments)
{
$this->arguments = $arguments;
}
public function addArgument($argument)
{
$this->arguments[] = $argument;
}
public function setOperation($operation)
{
$this->operation = $operation;
}
public function isComplete()
{
return isset($this->operation, $this->input, $this->subject,
$this->validator);
}
protected function applySteps(array $stepData)
{
foreach ($stepData as $p) {
if (!isset($this->operation)) {
$this->setOperation($p);
continue;
}
if (!isset($this->input)) {
$this->setInput($p);
continue;
}
if (!isset($this->subject)) {
$this->setSubject($p);
continue;
}
if (!isset($this->validator)) {
$this->setValidator($p);
continue;
}
$this->addArgument($p);
}
if ($this->isComplete())
return $this->execute();
else
return $this;
}
public function __call($method, $arguments)
{
array_unshift($arguments, $method);
return $this->applySteps($arguments);
}
public function __get($property)
{
return $this->applySteps(array($property));
}
public function execute()
{
if (!$this->isComplete())
throw new ComponentException('Validator not complete');
$validatorSpec = array($this->subject, $this->validator);
$validatorInstance = static::buildValidator($validatorSpec,
$this->arguments);
$operationSpec = array($validatorInstance, $this->operation);
return call_user_func($operationSpec, $this->input);
}
public function __construct($operation=null, $input=null, $subject=null,
$validator=null, $arguments=array())
{
$this->operation = $operation;
$this->input = $input;
$this->subject = $subject;
$this->validator = $validator;
$this->arguments = $arguments;
}
public static function __callStatic($method, $arguments)
{
if (2 > count($arguments))
return false;
if (0 === strpos($method, 'valid')) {
$arguments[1] = substr($method, 5) . '\\' . $arguments[1];
$arguments[1] = trim($arguments[1], '\\');
return call_user_func_array(
array(get_called_class(), 'validate'), $arguments
);
} elseif (0 === strpos($method, 'is')) {
$arguments[1] = substr($method, 2) . '\\' . $arguments[1];
$arguments[1] = trim($arguments[1], '\\');
return call_user_func_array(
array(get_called_class(), 'is'), $arguments
);
}
return false;
preg_match('#^(is|assert)([[:alnum:]]+)?$#', $method, $matches);
array_shift($matches);
$input = array_shift($arguments);
$operation = array_shift($matches);
$subject = array_shift($matches) ? : array_shift($arguments);
$validator = array_shift($arguments);
$v = new static($operation, $input, $subject, $validator, $arguments);
if ($v->isComplete())
return $v->execute();
else
return $v;
}
public static function buildValidator($validator, $arguments=array())
@ -53,7 +160,9 @@ abstract class Validator
);
$validatorFqn = explode('\\', get_called_class());
array_pop($validatorFqn);
$validatorFqn = array_merge($validatorFqn, explode('\\', $validator));
if (!is_array($validator))
$validator = explode('\\', $validator);
$validatorFqn = array_merge($validatorFqn, $validator);
$validatorFqn = array_map('ucfirst', $validatorFqn);
$validatorFqn = implode('\\', $validatorFqn);
$validatorClass = new ReflectionClass($validatorFqn);

View file

@ -20,7 +20,7 @@ class AllTest extends ValidatorTestCase
public function testValidateManyValid($a, $b, $c)
{
$this->object->addValidators(func_get_args());
$this->assertTrue($this->object->validate('any'));
$this->assertTrue($this->object->assert('any'));
}
/**
@ -29,7 +29,7 @@ class AllTest extends ValidatorTestCase
public function testManyIsValid($a, $b, $c)
{
$this->object->addValidators(func_get_args());
$this->assertTrue($this->object->isValid('any'));
$this->assertTrue($this->object->is('any'));
}
/**
@ -38,7 +38,7 @@ class AllTest extends ValidatorTestCase
public function testManyIsInvalid($a, $b, $c)
{
$this->object->addValidators(func_get_args());
$this->assertFalse($this->object->isValid('any'));
$this->assertFalse($this->object->is('any'));
}
/**
@ -50,7 +50,7 @@ class AllTest extends ValidatorTestCase
$this->object->addValidator(
$this->buildMockValidator('Aids', array('Aids_1' => 'aesfg'))
);
$this->assertFalse($this->object->isValid('any'));
$this->assertFalse($this->object->is('any'));
}
/**
@ -60,7 +60,7 @@ class AllTest extends ValidatorTestCase
{
$this->object->addValidators(func_get_args());
try {
$this->object->validate('any');
$this->object->assert('any');
} catch (InvalidException $e) {
$this->assertEquals(3, count($e->getExceptions()));
}

View file

@ -23,7 +23,7 @@ class OneTest extends ValidatorTestCase
$valid = $this->buildMockValidator('Darth', array('Darth_1' => 'o54n'));
$this->object->addValidators(func_get_args());
$this->object->addValidator($valid);
$this->assertTrue($this->object->validate('any'));
$this->assertTrue($this->object->assert('any'));
}
/**
@ -33,7 +33,7 @@ class OneTest extends ValidatorTestCase
{
$this->object->addValidators(func_get_args());
try {
$this->object->validate('any');
$this->object->assert('any');
} catch (InvalidException $e) {
$this->assertEquals(3, count($e->getExceptions()));
}
@ -47,7 +47,7 @@ class OneTest extends ValidatorTestCase
$valid = $this->buildMockValidator('Darth', array('Darth_1' => 'o54n'));
$this->object->addValidators(func_get_args());
$this->object->addValidator($valid);
$this->assertTrue($this->object->isValid('any'));
$this->assertTrue($this->object->is('any'));
}
/**
@ -56,7 +56,7 @@ class OneTest extends ValidatorTestCase
public function testIsValidOneAllRotten($invalidA, $invalidB, $invalidC)
{
$this->object->addValidators(func_get_args());
$this->assertFalse($this->object->isValid('any'));
$this->assertFalse($this->object->is('any'));
}
}

View file

@ -13,8 +13,8 @@ class BetweenTest extends \PHPUnit_Framework_TestCase
public function testBetweenValid($input, $min, $max)
{
$between = new Between($min, $max);
$this->assertTrue($between->isValid($input));
$this->assertTrue($between->validate($input));
$this->assertTrue($between->is($input));
$this->assertTrue($between->assert($input));
}
/**
@ -25,8 +25,8 @@ class BetweenTest extends \PHPUnit_Framework_TestCase
{
$between = new Between($min, $max);
$this->assertFalse($between->isValid($input));
$this->assertFalse($between->validate($input));
$this->assertFalse($between->is($input));
$this->assertFalse($between->assert($input));
}
/**

View file

@ -5,40 +5,76 @@ namespace Respect\Validation;
class ValidatorTest extends ValidatorTestCase
{
public function testSimpleValidateCall()
public function testPartialEmpty()
{
$valid = Validator::valid('now', 'Date\Between', 'yesterday', 'tomorrow');
$this->assertTrue($valid);
$v = Validator::is();
$this->assertType('Respect\Validation\Validator', $v);
$this->assertSame('is', $v->getOperation());
}
public function testDynamicValidateCall()
public function testPartialInputOnly()
{
$valid = Validator::validDate('now', 'Between', 'yesterday', 'tomorrow');
$this->assertTrue($valid);
$v = Validator::is('something');
$this->assertType('Respect\Validation\Validator', $v);
$this->assertSame('is', $v->getOperation());
$this->assertSame('something', $v->getInput());
}
public function testSimpleIsValidCall()
public function testPartialInputSubject()
{
$valid = Validator::is('now', 'Date\Between', 'yesterday', 'tomorrow');
$this->assertTrue($valid);
$v = Validator::is('now', 'date');
$this->assertType('Respect\Validation\Validator', $v);
$this->assertSame('is', $v->getOperation());
$this->assertSame('now', $v->getInput());
$this->assertSame('date', $v->getSubject());
}
public function testDynamicIsValidCall()
public function testValidateSimple()
{
$valid = Validator::isDate('now', 'Between', 'yesterday', 'tomorrow');
$this->assertTrue($valid);
$v = Validator::is('foo', 'string', 'notEmpty');
$this->assertTrue($v);
}
public function testNodeName()
public function testValidateArguments()
{
$valid = Validator::isDate('now', 'between', 'yesterday', 'tomorrow');
$this->assertTrue($valid);
$v = Validator::is('now', 'date', 'between', 'yesterday', 'tomorrow');
$this->assertTrue($v);
}
public function testNodeName2()
public function testFluentSubjectGetter()
{
$valid = Validator::is('now', 'date\between', 'yesterday', 'tomorrow');
$this->assertTrue($valid);
$v = Validator::is('now')->date;
$this->assertType('Respect\Validation\Validator', $v);
$this->assertSame('is', $v->getOperation());
$this->assertSame('now', $v->getInput());
$this->assertSame('date', $v->getSubject());
}
public function testFluentSubjectCall()
{
$v = Validator::is('now')->date();
$this->assertType('Respect\Validation\Validator', $v);
$this->assertSame('is', $v->getOperation());
$this->assertSame('now', $v->getInput());
$this->assertSame('date', $v->getSubject());
}
public function testFluentSubjectGetterMixed()
{
$v = Validator::is('now')->date->between('yesterday', 'tomorrow');
$this->assertTrue($v);
}
public function testFluentSubjectCallMixed()
{
$v = Validator::is('now', 'date')->between('yesterday', 'tomorrow');
$this->assertTrue($v);
}
public function testFluentSubjectCallMixed2()
{
$v = Validator::is('now')->date('between', 'yesterday', 'tomorrow');
$this->assertTrue($v);
}
}

View file

@ -22,13 +22,13 @@ abstract class ValidatorTestCase extends \PHPUnit_Framework_TestCase
{
$validator = Mockery::mock('Respect\Validation\Validatable');
if ($invalid) {
$validator->shouldReceive('validate')->andThrow(
$validator->shouldReceive('assert')->andThrow(
new InvalidException('Always invalid, man.')
);
$validator->shouldReceive('isValid')->andReturn(false);
$validator->shouldReceive('is')->andReturn(false);
} else {
$validator->shouldReceive('isValid')->andReturn(true);
$validator->shouldReceive('validate')->andReturn(true);
$validator->shouldReceive('is')->andReturn(true);
$validator->shouldReceive('assert')->andReturn(true);
}
$validator->shouldReceive('getMessages')->andReturn(
$messages
@ -38,8 +38,8 @@ abstract class ValidatorTestCase extends \PHPUnit_Framework_TestCase
eval("
namespace Respect\Validation\Foo;
class $name implements \Respect\Validation\Validatable {
public function validate(\$input) {}
public function isValid(\$input) {}
public function assert(\$input) {}
public function is(\$input) {}
public function setMessages(array \$messages) {}
public function getMessages() {
return " . var_export($messages,