diff --git a/src/Valitron/Validator.php b/src/Valitron/Validator.php index f57cc08..54f6bf5 100644 --- a/src/Valitron/Validator.php +++ b/src/Valitron/Validator.php @@ -1019,7 +1019,7 @@ class Validator * @param string $message * @throws \InvalidArgumentException */ - public function addInstanceRule($name, $callback, $message = self::ERROR_DEFAULT) + public function addInstanceRule($name, $callback, $message = null) { static::assertRuleCallback($callback); @@ -1035,24 +1035,63 @@ class Validator * @param string $message * @throws \InvalidArgumentException */ - public static function addRule($name, $callback, $message = self::ERROR_DEFAULT) + public static function addRule($name, $callback, $message = null) { + if ($message === null) + { + $message = static::ERROR_DEFAULT; + } + static::assertRuleCallback($callback); static::$_rules[$name] = $callback; static::$_ruleMessages[$name] = $message; } + public function getUniqueRuleName($fields) + { + if (is_array($fields)) + { + $fields = implode("_", $fields); + } + + $orgName = "{$fields}_rule"; + $name = $orgName; + $rules = $this->getRules(); + while (isset($rules[$name])) + { + $name = $orgName . "_" . rand(0, 10000); + } + + return $name; + } + /** * Convenience method to add a single validation rule * - * @param string $rule + * @param string|callback $rule * @param array $fields * @return $this * @throws \InvalidArgumentException */ public function rule($rule, $fields) { + // Get any other arguments passed to function + $params = array_slice(func_get_args(), 2); + + // Note: we cannot use is_callable here since max, int, and many + // other string can also be callables but aren't really rule callbacks. + // + // If a closure is used, we can be sure that the user actually + // wants $rule to be a custom rule check. + if (is_object($rule) && ($rule instanceof \Closure)) + { + $name = $this->getUniqueRuleName($fields); + $msg = isset($params[0]) ? $params[0] : null; + $this->addInstanceRule($name, $rule, $msg); + $rule = $name; + } + $errors = $this->getRules(); if (!isset($errors[$rule])) { $ruleMethod = 'validate' . ucfirst($rule); @@ -1065,9 +1104,6 @@ class Validator $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); - $this->_validations[] = array( 'rule' => $rule, 'fields' => (array) $fields, diff --git a/tests/Valitron/ValidateAddInstanceRuleTest.php b/tests/Valitron/ValidateAddInstanceRuleTest.php index 796902c..c1f759e 100644 --- a/tests/Valitron/ValidateAddInstanceRuleTest.php +++ b/tests/Valitron/ValidateAddInstanceRuleTest.php @@ -39,7 +39,6 @@ class ValidateAddInstanceRuleTest extends BaseTestCase $v->rule("fuzzerRule", "fuzz"); $v->rule("fooRule", "foo"); - $this->assertValid($v); } @@ -53,4 +52,50 @@ class ValidateAddInstanceRuleTest extends BaseTestCase $v->rule("fooRule", "foo"); $this->assertFalse($v->validate()); } + + public function testAddAddRuleWithCallback() + { + $v = new Validator(array("foo" => "bar")); + $v->rule(function($field, $value) { + return $field === "foo" && $value === "bar"; + }, "foo"); + + $this->assertValid($v); + } + + public function testAddAddRuleWithCallbackFail() + { + $v = new Validator(array("foo" => "baz")); + $v->rule(function($field, $value) { + return $field === "foo" && $value === "bar"; + }, "foo"); + + $this->assertFalse($v->validate()); + } + + public function testAddAddRuleWithCallbackFailMessage() + { + $v = new Validator(array("foo" => "baz")); + $v->rule(function($field, $value) { + return $field === "foo" && $value === "bar"; + }, "foo", "test error message"); + + $this->assertFalse($v->validate()); + $errors = $v->errors(); + $this->assertArrayHasKey("foo", $errors); + $this->assertCount(1, $errors["foo"]); + $this->assertEquals("Foo test error message", $errors["foo"][0]); + } + + public function testUniqueRuleName() + { + $v = new Validator(array()); + $args = array("foo", "bar"); + $this->assertEquals("foo_bar_rule", $v->getUniqueRuleName($args)); + $this->assertEquals("foo_rule", $v->getUniqueRuleName("foo")); + + $v->addInstanceRule("foo_rule", function() {}); + $u = $v->getUniqueRuleName("foo"); + $this->assertRegExp("/^foo_rule_[0-9]{1,5}$/", $u); + } }