Skip to content

Commit 53ba399

Browse files
committed
Validator::formatMessage: support dynamic error messages
This is useful when you want to show user an informative error message, whose text depends on some external data that depends on the value of some other field. For example, my form allows user to choose a category of a team. Each category has a different limit for number of allowed members, which is specified in config.neon. I want to show the user the limit as part of the error message when she manages to exceed the limit.
1 parent d9fc6d6 commit 53ba399

File tree

5 files changed

+51
-2
lines changed

5 files changed

+51
-2
lines changed

src/Forms/Helpers.php

+3
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ public static function exportRules(Rules $rules): array
102102
}
103103
$op = Nette\Utils\Callback::toString($op);
104104
}
105+
if (is_callable($rule->message)) {
106+
continue;
107+
}
105108
if ($rule->branch) {
106109
$item = [
107110
'op' => ($rule->isNegative ? '~' : '') . $op,

src/Forms/Rules.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public function isRequired(): bool
6969
/**
7070
* Adds a validation rule for the current control.
7171
* @param callable|string $validator
72-
* @param string|object $errorMessage
72+
* @param string|callable|object $errorMessage
7373
* @return static
7474
*/
7575
public function addRule($validator, $errorMessage = null, $arg = null)

src/Forms/Validator.php

+9
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@ class Validator
5151
public static function formatMessage(Rule $rule, bool $withValue = true)
5252
{
5353
$message = $rule->message;
54+
if (is_callable($message)) {
55+
$params = Nette\Utils\Callback::toReflection($message)->getParameters();
56+
if (isset($params[1])) {
57+
$message = $message($rule->control, $rule->arg);
58+
} else {
59+
$message = $message($rule->control);
60+
}
61+
}
62+
5463
if ($message instanceof Nette\Utils\IHtmlString) {
5564
return $message;
5665

tests/Forms/Helpers.exportRules.phpt

+11
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
declare(strict_types=1);
88

9+
use Nette\Forms\Controls\TextInput;
910
use Nette\Forms\Form;
1011
use Nette\Forms\Helpers;
1112
use Tester\Assert;
@@ -91,3 +92,13 @@ test(function () {
9192
],
9293
], Helpers::exportRules($input2->getRules()));
9394
});
95+
96+
97+
test(function () {
98+
$form = new Form;
99+
$input = $form->addText('text');
100+
$input->addRule(Form::EMAIL, function(TextInput $input, $arg) {
101+
return $input->getValue() . ' is not valid e-mail address.';
102+
});
103+
Assert::same([], Helpers::exportRules($input->getRules()));
104+
});

tests/Forms/Rules.formatMessage.phpt

+27-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
declare(strict_types=1);
88

9+
use Nette\Forms\Controls\TextInput;
910
use Nette\Forms\Form;
1011
use Tester\Assert;
1112

@@ -34,11 +35,36 @@ $form->addText('special', 'Label:')
3435
->addRule(Form::EMAIL, '%label %value is invalid [field %name] %d', $form['special'])
3536
->setDefaultValue('xyz');
3637

38+
$form->addText('function', 'Label:')
39+
->setRequired()
40+
->addRule(function(TextInput $input, string $arg) {
41+
return strpos($input->getValue(), $arg) === false;
42+
}, function(TextInput $input, string $arg) {
43+
return "String “{$input->getValue()}” contains a letter “{$arg}”, which is not allowed";
44+
}, 'a')
45+
->setDefaultValue('banana');
46+
47+
$form->addText('functionWithoutArg', 'Label:')
48+
->setRequired()
49+
->addRule(function(TextInput $input) {
50+
return strpos($input->getValue(), 'e') === false;
51+
}, function(TextInput $input) {
52+
return "String “{$input->getValue()}” contains a letter “e”, which is not allowed";
53+
})
54+
->setDefaultValue('orange');
55+
3756
$form->validate();
3857

3958
Assert::true($form->hasErrors());
4059

41-
Assert::same(['1 5', '5 1', '1 ', 'Label xyz is invalid [field special] xyz'], $form->getErrors());
60+
Assert::same([
61+
'1 5',
62+
'5 1',
63+
'1 ',
64+
'Label xyz is invalid [field special] xyz',
65+
'String “banana” contains a letter “a”, which is not allowed',
66+
'String “orange” contains a letter “e”, which is not allowed',
67+
], $form->getErrors());
4268

4369
Assert::same([], $form->getOwnErrors());
4470

0 commit comments

Comments
 (0)