Create a Factory to create rules

It also provide a way to define namespaces/prefixes to use the custom
rules on Respect\Validation.
This commit is contained in:
Henrique Moody 2014-05-07 00:51:54 -03:00
parent 3e467261ca
commit a4cb20810d
4 changed files with 180 additions and 11 deletions

View file

@ -174,6 +174,23 @@ $errors = $exception->findMessages(array(
For all messages, the `{{name}}` and `{{input}}` variable is available for templates.
### Custom Rules
You also can use your own rules:
```php
v::with('My\\Validation\\Rules\\');
v::myRule(); // Try to load "My\Validation\Rules\MyRule" if any
```
By default `with()` appends the given prefix, but you can change this behavior
in order to overwrite default rules:
```php
v::with('My\\Validation\\Rules\\', true);
v::alnum(); // Try to use "My\Validation\Rules\Alnum" if any
```
### Validator Name
On `v::attribute()` and `v::key()`, `{{name}}` is the attribute/key name. For others,

49
library/Factory.php Normal file
View file

@ -0,0 +1,49 @@
<?php
namespace Respect\Validation;
use ReflectionClass;
use Respect\Validation\Exceptions\ComponentException;
class Factory
{
protected $rulePrefixes = array('Respect\\Validation\\Rules\\');
public function getRulePrefixes()
{
return $this->rulePrefixes;
}
public function appendRulePrefix($rulePrefix)
{
array_push($this->rulePrefixes, $rulePrefix);
}
public function prependRulePrefix($rulePrefix)
{
array_unshift($this->rulePrefixes, $rulePrefix);
}
public function rule($ruleName, array $arguments = array())
{
if ($ruleName instanceof Validatable) {
return $ruleName;
}
foreach ($this->getRulePrefixes() as $prefix) {
$className = $prefix.ucfirst($ruleName);
if (! class_exists($className)) {
continue;
}
$reflection = new ReflectionClass($className);
if (! $reflection->isSubclassOf('Respect\\Validation\\Validatable')) {
throw new ComponentException(sprintf('"%s" is not a valid respect rule', $className));
}
return $reflection->newInstanceArgs($arguments);
}
throw new ComponentException(sprintf('"%s" is not a valid rule name', $ruleName));
}
}

View file

@ -106,6 +106,45 @@ use Respect\Validation\Rules\AllOf;
*/
class Validator extends AllOf
{
protected static $factory;
/**
* @return Factory
*/
protected static function getFactory()
{
if (! static::$factory instanceof Factory) {
static::$factory = new Factory();
}
return static::$factory;
}
/**
* @param Factory $factory
*
* @return null
*/
public static function setFactory($factory)
{
static::$factory = $factory;
}
/**
* @param string $rulePrefix
* @param bool $prepend
*
* @return null
*/
public static function with($rulePrefix, $prepend = false)
{
if (false === $prepend) {
self::getFactory()->appendRulePrefix($rulePrefix);
} else {
self::getFactory()->prependRulePrefix($rulePrefix);
}
}
/**
* @param string $ruleName
* @param array $arguments
@ -131,18 +170,10 @@ class Validator extends AllOf
*/
public static function buildRule($ruleSpec, $arguments = array())
{
if ($ruleSpec instanceof Validatable) {
return $ruleSpec;
}
try {
$validatorFqn = 'Respect\\Validation\\Rules\\'.ucfirst($ruleSpec);
$validatorClass = new ReflectionClass($validatorFqn);
$validatorInstance = $validatorClass->newInstanceArgs($arguments);
return $validatorInstance;
} catch (ReflectionException $e) {
throw new ComponentException($e->getMessage());
return static::getFactory()->rule($ruleSpec, $arguments);
} catch (\Exception $exception) {
throw new ComponentException($exception->getMessage(), $exception->getCode(), $exception);
}
}

72
tests/FactoryTest.php Normal file
View file

@ -0,0 +1,72 @@
<?php
namespace Respect\Validation;
/**
* @covers Respect\Validation\Factory
*/
class FactoryTest extends \PHPUnit_Framework_TestCase
{
public function testShouldHaveRulePrefixesByDefault()
{
$factory = new Factory();
$this->assertEquals(array('Respect\\Validation\\Rules\\'), $factory->getRulePrefixes());
}
public function testShouldBeAbleToAppendANewPrefix()
{
$factory = new Factory();
$factory->appendRulePrefix('My\\Validation\\Rules\\');
$this->assertEquals(array('Respect\\Validation\\Rules\\', 'My\\Validation\\Rules\\'), $factory->getRulePrefixes());
}
public function testShouldBeAbleToPrependANewRulePrefix()
{
$factory = new Factory();
$factory->prependRulePrefix('My\\Validation\\Rules\\');
$this->assertEquals(array('My\\Validation\\Rules\\', 'Respect\\Validation\\Rules\\'), $factory->getRulePrefixes());
}
public function testShouldCreateARuleByName()
{
$factory = new Factory();
$this->assertInstanceOf('Respect\\Validation\\Rules\\Uppercase', $factory->rule('uppercase'));
}
public function testShouldDefineConstructorArgumentsWhenCreatingARule()
{
$factory = new Factory();
$rule = $factory->rule('date', array('Y-m-d'));
$this->assertEquals('Y-m-d', $rule->format);
}
/**
* @expectedException Respect\Validation\Exceptions\ComponentException
* @expectedExceptionMessage "uterere" is not a valid rule name
*/
public function testShouldThrowsAnExceptionWhenRuleNameIsNotValid()
{
$factory = new Factory();
$factory->rule('uterere');
}
/**
* @expectedException Respect\Validation\Exceptions\ComponentException
* @expectedExceptionMessage "Respect\Validation\TestNonRule" is not a valid respect rule
*/
public function testShouldThrowsAnExceptionWhenRuleIsNotInstanceOfRuleInterface()
{
$factory = new Factory();
$factory->appendRulePrefix('Respect\\Validation\\Test');
$factory->rule('nonRule');
}
}
class TestNonRule
{
}