Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel: How to use the ignore rule in Form Request Validation

Laravel has a 'unique' rule with an 'except' clause. From the validation documentation, it takes this form:

unique:table,column,except,idColumn

My application has a 'shop' entity. When the user updates the shop's profile, I have a Form Request, with a validation rule configured as follows:

public function rules()
{
    return [
        'shop.name' => 'required|string|max:100|unique:shops,name,except,id',
    ];
}

(The primary key on my shops table is id).

The problem is that Laravel does not take any notice of the 'except' clause. This makes sense (sort of) since the shop ID is not being injected into the Form Request. I can inject id as just another form value, but that doesn't seem to work.

How can I get this rule working in a Form Request?

like image 698
DatsunBing Avatar asked Dec 05 '17 05:12

DatsunBing


People also ask

How do I ignore validation in laravel?

use Illuminate\Validation\Rule; Validator::make($data, [ 'email' => [ 'required', Rule::unique('users')->ignore($user->id), ], ]);

What is the method used to configure validation rules in form request laravel?

Laravel Form Request class comes with two default methods auth() and rules() . You can perform any authorization logic in auth() method whether the current user is allowed to request or not. And in rules() method you can write all your validation rule.

What is bail in laravel validation?

you can easily use bail validation in laravel 6, laravel 7, laravel 8 and laravel 9. If you added more then one validation on your field like required, integer, min and max then if first is fail then other should stop to display error message. right now by default it print other too.


1 Answers

To use the except clause of the unique rule, we need to provide the value of the field on the record that we want the rule to ignore directly in the rule itself.

So, if we want a unique name field for every record except for on the record that the request updates, we need to add the value of the ID field to ignore:

class UpdateShopRequest extends FormRequest
{
    ...
    public function rules() 
    {
        return [
            'shop.name' => 'unique:shops,name,' . $this->shop['id'],
        ];
    }
}

As shown, this rule will cause validation to fail if any row contains the same shop name unless the row's id matches $this->shop['id']. This example assumes that our form contains a nested input field for the record's ID attribute because this particular question is performing validation on an array input:

<input type="hidden" name="shop[id]" value="{{ $shop->id }}">

...which lets us fetch the value within the request like we can with any other request.

However, most forms do not contain arrays, so—in other cases—the validation rule will likely refer to the input field directly (without nested identifiers):

'name' => 'unique:shops,name,' . $this->id,

More typically, we pass the record ID as a route parameter, which we can retrieve using the request's route() method:

'name' => 'unique:shops,name,' . $this->route('id'),

...which works if we have a route defined similarly to:

Route::post('shops/{id}', ...);

The fourth parameter to the unique validation rule lets us specify which column the except clause applies to, and defaults to id, so we can leave it off if we're just comparing the record's ID.

The rule looks a bit clumsy when we just concatenate the column value, especially for a field with a lot of other rules. Since version 5.3, Laravel provides a more elegant syntax to create a unique rule with an except clause:

use Illuminate\Validation\Rule;
...
return [
    'name' => [ 
        'required', 
        'string', 
        'max:100', 
        Rule::unique('shops', 'name')->ignore($this->id, 'optional_column'), 
    ],
];
        
like image 157
Cy Rossignol Avatar answered Sep 20 '22 10:09

Cy Rossignol