Reputation: 1167
Okay, I've got in a very difficult situation here and I think I'm either missing on something crucial that's already present or Laravel doesn't provide a way to achieve that as of right now.
I'd like to specify a custom validation error message with a custom placeholder I'd like to replace in the message. The problem with that: I'm using the regex
validation rule, about which Laravel documentation explicitly points out, that it should be better passed in an array to avoid unwanted separator behavior. The situation is the following: I'd like to specify a global multilingual message for validating name.regex
, which I've done so:
'custom' => [
'name' => [
'regex' => 'The :attribute must corespond to the given format: :format!'
]
]
As you can see, I've put a custom placeholder :format
in that message, because for the name
attribute of different classes I'm going to be matching different regular expressions. So I'd like to be able to input a custom human readable description of each given regex along the validation (as a parameter).
So I'm doin the following in my controller:
$input = Input::all();
$validator = Validator::make($input, [
'name' => ['required', 'regex:/^\p{Lu}\p{L}+ \p{Lu}\p{L}+$/u']
]);
I've also got a Validator::replacer()
method in my AppServiceProvider.php
which should replace the :format
placeholder in the message:
Validator::replacer('regex', function($message, $attr, $rule, $parameters){
return str_replace(':format', "I would like to be able to somehow retrieve the custom format description here, but using \$parameters[] is not an option", $message);
});
The problem with the regex
validation rule is that I'm really not allowed to pass a parameter to it in the validator, like for example so:
$validator = Validator::make($input, [
'name' => ['required', 'regex:/^\p{Lu}\p{L}+ \p{Lu}\p{L}+$/u,Thats my custom validator format description']
]);
because it completely messes up the regular expression (which should be that way). So I can't user $parameters1$ in my replacer()
to replace the placeholder. Furthermore it would be really inconvenient to have to pass a whole sentence as a comma-separated parameter of a validation rule. So that concept doesn't fit the needs.
The :format
value will be dynamic and will severely vary throughout different classes' name
fields requirements, so I really need that dynamic multilingual description to be set as a property of the current validator instance. I thought maybe the most convenient scenario would be the something like this:
$validator = Validator::make($input, [
'name' => ['required', 'regex:/^\p{Lu}\p{L}+ \p{Lu}\p{L}+$/u', 'format:Current name requirements described here.']
]);
and Laravel somehow knows that :format
should be replaced by the present rule somewhere in the messages of that instance. I thought about explicitly adding this additional parameter as a validation rule and later on manage it, but I'm really unable to achieve the cross-rule connection (in other words, to get the parameter of the new format
rule and use it in the regex
rule).
I really don't know how to approach that issue and any help would be greatly appreciated. Thanks in advance!
P.S. I'm aware I could specify the whole message each time this way:
$input = Input::all();
$validator = Validator::make($input, [
'name' => ['required', 'regex:/^\p{Lu}\p{L}+ \p{Lu}\p{L}+$/u']
],
[
'name.regex' => 'My custom message here'
]);
but I don't want to have to input the whole message each time, because it might later on contain other placeholders (that might be global or so) in it and I want to use the multilingual base message provided via the validator.php
files, so I really need to replace the :format
only.
Upvotes: 3
Views: 5650
Reputation: 14921
You can create a custom rule:
php artisan make:rule CustomRegex
Then update the constructor to support both the regex and description of the format.
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class CustomRegex implements Rule
{
/** @var string $attribute The attribute of we are validating. */
public $attribute;
/** @var string $description The description of the regex format. */
public $description;
/** @var string $regex The regex to validate. */
public $regex;
/**
* Create a new rule instance.
*
* @param string $regex The regex to validate.
* @param string $description The description of the regex format.
* @return void
*/
public function __construct(string $regex, string $description)
{
$this->regex = $regex;
$this->description = $description;
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
$this->attribute = $attribute;
return preg_match($this->regex, $value);
}
/**
* Get the validation error message.
*
* @return string
*/
public function message()
{
return trans('validation.custom.name', [
'attribute' => $this->attribute,
'format' => $this->description
]);
}
}
And then when you validate:
use App\Rules\CustomRegex;
request()->validate([
'name' => [
'required', new CustomRegex('/^\p{Lu}\p{L}+ \p{Lu}\p{L}+$/u', 'The description of your format')
]
]);
Then the output message would look like this:
The name must corespond to the given format: The description of your format!
Upvotes: 6
Reputation: 312
The simplest way as i can figured out in Laravel 5.6 is to use closure:
$validator = Validator::make($input,
[
'name' =>
[
'required',
function($attribute, $value, $fail) {
$regex = '/^\p{Lu}\p{L}+ \p{Lu}\p{L}+$/u';
if (!preg_match($regex, $value)) {
return $fail('Your custom message with' .
$attribute . ' name and its value = ' . $value);
}
},
]
]);
Inside this closure you can add whatever you want. You can calculate readable format form and adds it to error message.
Upvotes: 0