diff --git a/src/Forms/Helpers.php b/src/Forms/Helpers.php index 55d701076..6d4702b67 100644 --- a/src/Forms/Helpers.php +++ b/src/Forms/Helpers.php @@ -102,6 +102,9 @@ public static function exportRules(Rules $rules): array } $op = Nette\Utils\Callback::toString($op); } + if (is_callable($rule->message)) { + continue; + } if ($rule->branch) { $item = [ 'op' => ($rule->isNegative ? '~' : '') . $op, diff --git a/src/Forms/Rules.php b/src/Forms/Rules.php index 6c2c8c9da..6c1b40311 100644 --- a/src/Forms/Rules.php +++ b/src/Forms/Rules.php @@ -69,7 +69,7 @@ public function isRequired(): bool /** * Adds a validation rule for the current control. * @param callable|string $validator - * @param string|object $errorMessage + * @param string|callable|object $errorMessage * @return static */ public function addRule($validator, $errorMessage = null, $arg = null) diff --git a/src/Forms/Validator.php b/src/Forms/Validator.php index cb618a4fe..6ae8a7e88 100644 --- a/src/Forms/Validator.php +++ b/src/Forms/Validator.php @@ -51,6 +51,15 @@ class Validator public static function formatMessage(Rule $rule, bool $withValue = true) { $message = $rule->message; + if (is_callable($message)) { + $params = Nette\Utils\Callback::toReflection($message)->getParameters(); + if (isset($params[1])) { + $message = $message($rule->control, $rule->arg); + } else { + $message = $message($rule->control); + } + } + if ($message instanceof Nette\Utils\IHtmlString) { return $message; diff --git a/tests/Forms/Helpers.exportRules.phpt b/tests/Forms/Helpers.exportRules.phpt index 5fc76976d..670ae121a 100644 --- a/tests/Forms/Helpers.exportRules.phpt +++ b/tests/Forms/Helpers.exportRules.phpt @@ -6,6 +6,7 @@ declare(strict_types=1); +use Nette\Forms\Controls\TextInput; use Nette\Forms\Form; use Nette\Forms\Helpers; use Tester\Assert; @@ -91,3 +92,13 @@ test(function () { ], ], Helpers::exportRules($input2->getRules())); }); + + +test(function () { + $form = new Form; + $input = $form->addText('text'); + $input->addRule(Form::EMAIL, function (TextInput $input, $arg) { + return $input->getValue() . ' is not valid e-mail address.'; + }); + Assert::same([], Helpers::exportRules($input->getRules())); +}); diff --git a/tests/Forms/Rules.formatMessage.phpt b/tests/Forms/Rules.formatMessage.phpt index 942d19202..c40fbed59 100644 --- a/tests/Forms/Rules.formatMessage.phpt +++ b/tests/Forms/Rules.formatMessage.phpt @@ -6,6 +6,7 @@ declare(strict_types=1); +use Nette\Forms\Controls\TextInput; use Nette\Forms\Form; use Tester\Assert; @@ -34,11 +35,36 @@ $form->addText('special', 'Label:') ->addRule(Form::EMAIL, '%label %value is invalid [field %name] %d', $form['special']) ->setDefaultValue('xyz'); +$form->addText('function', 'Label:') + ->setRequired() + ->addRule(function (TextInput $input, string $arg) { + return strpos($input->getValue(), $arg) === false; + }, function (TextInput $input, string $arg) { + return "String “{$input->getValue()}” contains a letter “{$arg}”, which is not allowed"; + }, 'a') + ->setDefaultValue('banana'); + +$form->addText('functionWithoutArg', 'Label:') + ->setRequired() + ->addRule(function (TextInput $input) { + return strpos($input->getValue(), 'e') === false; + }, function (TextInput $input) { + return "String “{$input->getValue()}” contains a letter “e”, which is not allowed"; + }) + ->setDefaultValue('orange'); + $form->validate(); Assert::true($form->hasErrors()); -Assert::same(['1 5', '5 1', '1 ', 'Label xyz is invalid [field special] xyz'], $form->getErrors()); +Assert::same([ + '1 5', + '5 1', + '1 ', + 'Label xyz is invalid [field special] xyz', + 'String “banana” contains a letter “a”, which is not allowed', + 'String “orange” contains a letter “e”, which is not allowed', +], $form->getErrors()); Assert::same([], $form->getOwnErrors());