From a4cb20810d09252303584b78e83e6589798f5577 Mon Sep 17 00:00:00 2001 From: Henrique Moody Date: Wed, 7 May 2014 00:51:54 -0300 Subject: [PATCH] Create a Factory to create rules It also provide a way to define namespaces/prefixes to use the custom rules on Respect\Validation. --- README.md | 17 ++++++++++ library/Factory.php | 49 +++++++++++++++++++++++++++++ library/Validator.php | 53 ++++++++++++++++++++++++------- tests/FactoryTest.php | 72 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 180 insertions(+), 11 deletions(-) create mode 100644 library/Factory.php create mode 100644 tests/FactoryTest.php diff --git a/README.md b/README.md index aeb0c53ab..befba0bd1 100755 --- a/README.md +++ b/README.md @@ -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, diff --git a/library/Factory.php b/library/Factory.php new file mode 100644 index 000000000..52b368053 --- /dev/null +++ b/library/Factory.php @@ -0,0 +1,49 @@ +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)); + } +} diff --git a/library/Validator.php b/library/Validator.php index a346a8195..66af9f11b 100644 --- a/library/Validator.php +++ b/library/Validator.php @@ -106,6 +106,45 @@ */ 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 @@ public static function __callStatic($ruleName, $arguments) */ 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); } } diff --git a/tests/FactoryTest.php b/tests/FactoryTest.php new file mode 100644 index 000000000..01f629450 --- /dev/null +++ b/tests/FactoryTest.php @@ -0,0 +1,72 @@ +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 +{ +}