2
Php

Laravel – Manually Invalidate A Validation

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.

Latest Blog

0
Php

PHP – 8.0 Match Expression

In PHP 8.0 there is a new feature or I should say a new language construct (keyword) going to be introduced,  which has been implemented depending […]