Laravel provides a nice extensible and easy validation class to validate user inputs but Sometimes we may need to forcefully invalidate a passed validation. For example, a few days ago I realized that in one of my projects. I had a table with fields
group_name and
name along with other fields and when inserting data into this table I was checking for unique
group_name but not unique
name because, same name could be available in multiple groups but there was a problem with this requirement and it was that, one group can't contain same name twice and I couldn't use
unique rule for the
name field because several groups may contain same name. To solve this problem I just manually checked the
name field with
group_name filed like:
$hasName = Settings::where('group_name', $groupName)->where('name', $name)->get()->count();
This code gives me an integer (1) if it found a
name under the
group_name supplied in where clause and false when the
name doesn't exist with the
group_name and this way I can determine whether there is any name exists under same group but this is not a very big deal. The problem was to show an error message for the
name form field in the form and I didn't extend the
validator to add a custom rule, just trying to do it in a shortcut way. So, to show the error message on the form for the appropriate form field, I just added an error message in the validator's messaage collection and redirected back to the form (previous route) using
Redirect::back() method with
validator instanse and inputs, like:
$rules = ['group_name' => 'required', 'name' => 'required'];
$validation = Validator::make($inputs, $rules, $messages);
if($validation->passes()) {
// normal validation passed, now check the name field
$hasName = Settings::where('group_name', $groupName)->where('name', $name)->get()->count();
if($hasName) {
// Add an error message in the message collection (MessageBag instance)
$validation->getMessageBag()->add('name', 'Name already exists!');
// redirect back with inputs and validator instance
return Redirect::back()->withErrors($validation)->withInput();
}
else {
// OK, name doesn't exist, save it
}
}
That's it. After adding an error message in the message collection (Symfony MessageBag instance) I manually redirected back to the form and error message displayed for the
name field, telling that, "Name already exists!". Well, this is a shortcut hacky way to do this and it may possible by extending the validator using a custom rule but I used this shortcut. Here,
getMessageBag() public method of
Illuminate\Laravel\Validator class returns the
Protected variable
$messages and this variable is an instance of
Illuminate\Support\MessageBag which has this
add() method along with other methods and the first parameter in the
add() method is the name of the form field, for which I want to show the error message and the second parameter is the message for that field. By default in the view
$errors variable is available and if there is any error messages found in this variable assigned against any form field name using an associative array then Laravel shows that error message for that field where
$errors->first('name') is found and I had the following on my form
{{ Form::text('name', Input::old('name')) }} {{ $errors->first('name') }}
Here
$errors->first('name') will show the first error message found in the
$errors against the
name field, which would look something like this
Illuminate\Support\MessageBag Object
(
[messages:protected] => Array
(
[name] => Array
(
[0] => Name already exists !
)
)
[format:protected] => :message
)
So, the thing is very simple, manually add an error message into
$messages and redirect back with validator and inputs. After adding the message manually, the validation still passes but the error message will be displayed for the appropriate form field that was set.
Update:
This is also possible using
exists rule with additional field name to check in
where clause like this:
'name' => 'exists:settings,name,group_name,' . $groupName
The rule given above will check if the submitted
name (in the name field) exists in the
settings table where
group_name = $groupName and no need to set the message manually but this article demonstrates how to use
MessageBag instanse to set a message manually.
— The End —