From df78fe188c53cf29ffae7773e899fd9318113c9a Mon Sep 17 00:00:00 2001 From: Matteo Kloiber Date: Sun, 6 Nov 2016 01:46:17 +0100 Subject: [PATCH] Added support for instance rules Instance rules are not shared among other validator objects (thus they are not static). This is useful if you have a rule you do not want your other validators to use (because it is very special to this validator). The parameter given to addInstanceRule is identically to addRule: public function addInstanceRule(string $name, callable $callback [, string message]) Instead of appending to the static variables $_rules, and $_ruleMessages, it now appends to $_instanceRules and $_instanceRuleMessages. A new getter for the rules and ruleMessage has also been added: public array getRules() public array getRuleMessages() All existing code has been updated to use getRules(), and getRuleMessages() instead of $_rules, and $_ruleMessages. --- src/Valitron/Validator.php | 78 +++++++++++++++++-- .../Valitron/ValidateAddInstanceRuleTest.php | 56 +++++++++++++ 2 files changed, 126 insertions(+), 8 deletions(-) create mode 100644 tests/Valitron/ValidateAddInstanceRuleTest.php diff --git a/src/Valitron/Validator.php b/src/Valitron/Validator.php index 7c76738..f57cc08 100644 --- a/src/Valitron/Validator.php +++ b/src/Valitron/Validator.php @@ -37,6 +37,21 @@ class Validator */ protected $_labels = array(); + /** + * Contains all rules that are available to the current valitron instance. + * + * @var array + */ + protected $_instanceRules = array(); + + /** + * Contains all rule messages that are available to the current valitron + * instance + * + * @var array + */ + protected $_instanceRuleMessage = array(); + /** * @var string */ @@ -503,7 +518,7 @@ class Validator foreach ($this->validUrlPrefixes as $prefix) { if (strpos($value, $prefix) !== false) { $host = parse_url(strtolower($value), PHP_URL_HOST); - + return checkdnsrr($host, 'A') || checkdnsrr($host, 'AAAA') || checkdnsrr($host, 'CNAME'); } } @@ -921,8 +936,9 @@ class Validator } // Callback is user-specified or assumed method on class - if (isset(static::$_rules[$v['rule']])) { - $callback = static::$_rules[$v['rule']]; + $errors = $this->getRules(); + if (isset($errors[$v['rule']])) { + $callback = $errors[$v['rule']]; } else { $callback = array($this, 'validate' . ucfirst($v['rule'])); } @@ -945,6 +961,26 @@ class Validator return count($this->errors()) === 0; } + /** + * Returns all rule callbacks, the static and instance ones. + * + * @return array + */ + protected function getRules() + { + return array_merge($this->_instanceRules, static::$_rules); + } + + /** + * Returns all rule message, the static and instance ones. + * + * @return array + */ + protected function getRuleMessages() + { + return array_merge($this->_instanceRuleMessage, static::$_ruleMessages); + } + /** * Determine whether a field is being validated by the given rule. * @@ -952,6 +988,7 @@ class Validator * @param string $field The name of the field * @return boolean */ + protected function hasRule($name, $field) { foreach ($this->_validations as $validation) { @@ -965,6 +1002,31 @@ class Validator return false; } + protected static function assertRuleCallback($callback) + { + if (!is_callable($callback)) { + throw new \InvalidArgumentException('Second argument must be a valid callback. Given argument was not callable.'); + } + } + + + /** + * Adds a new validation rule callback that is tied to the current + * instance only. + * + * @param string $name + * @param mixed $callback + * @param string $message + * @throws \InvalidArgumentException + */ + public function addInstanceRule($name, $callback, $message = self::ERROR_DEFAULT) + { + static::assertRuleCallback($callback); + + $this->_instanceRules[$name] = $callback; + $this->_instanceRuleMessage[$name] = $message; + } + /** * Register new validation rule callback * @@ -975,9 +1037,7 @@ class Validator */ public static function addRule($name, $callback, $message = self::ERROR_DEFAULT) { - if (!is_callable($callback)) { - throw new \InvalidArgumentException('Second argument must be a valid callback. Given argument was not callable.'); - } + static::assertRuleCallback($callback); static::$_rules[$name] = $callback; static::$_ruleMessages[$name] = $message; @@ -993,7 +1053,8 @@ class Validator */ public function rule($rule, $fields) { - if (!isset(static::$_rules[$rule])) { + $errors = $this->getRules(); + if (!isset($errors[$rule])) { $ruleMethod = 'validate' . ucfirst($rule); if (!method_exists($this, $ruleMethod)) { throw new \InvalidArgumentException("Rule '" . $rule . "' has not been registered with " . __CLASS__ . "::addRule()."); @@ -1001,7 +1062,8 @@ class Validator } // Ensure rule has an accompanying message - $message = isset(static::$_ruleMessages[$rule]) ? static::$_ruleMessages[$rule] : self::ERROR_DEFAULT; + $msgs = $this->getRuleMessages(); + $message = isset($msgs[$rule]) ? $msgs[$rule] : self::ERROR_DEFAULT; // Get any other arguments passed to function $params = array_slice(func_get_args(), 2); diff --git a/tests/Valitron/ValidateAddInstanceRuleTest.php b/tests/Valitron/ValidateAddInstanceRuleTest.php new file mode 100644 index 0000000..796902c --- /dev/null +++ b/tests/Valitron/ValidateAddInstanceRuleTest.php @@ -0,0 +1,56 @@ +validate(); + foreach ($v->errors() as $label => $messages) + { + foreach ($messages as $theMessage) + { + $msg .= "\n\t{$label}: {$theMessage}"; + } + } + + $this->assertTrue($v->validate(), $msg); + } + + public function testAddInstanceRule() + { + $v = new Validator(array( + "foo" => "bar", + "fuzz" => "bazz", + )); + + $v->addInstanceRule("fooRule", function($field, $value) + { + return $field !== "foo" || $value !== "barz"; + }); + + Validator::addRule("fuzzerRule", function($field, $value) + { + return $field !== "fuzz" || $value === "bazz"; + }); + + $v->rule("required", array("foo", "fuzz")); + $v->rule("fuzzerRule", "fuzz"); + $v->rule("fooRule", "foo"); + + + $this->assertValid($v); + } + + public function testAddInstanceRuleFail() + { + $v = new Validator(array("foo" => "bar")); + $v->addInstanceRule("fooRule", function($field) + { + return $field === "for"; + }); + $v->rule("fooRule", "foo"); + $this->assertFalse($v->validate()); + } +}