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 —