Laravel check for unique rule without itself in update
Asked Answered
S

24

69

I am having my validation rules for unique in the update section.

In inserting or adding the unique rule is 'Email' => array('unique:driver_details'), and it will check for the unique coloumn.

But this fails for the update section. While updating it satisfies the other rules and in the unique of email it is checking itself for the unique coloumn and it fails but seeing its own field.

So, how can i check for the unique except its own value in the database ?

Swearingen answered 28/1, 2015 at 17:43 Comment(5)
possible duplicate of Laravel 4 validation email unique constraintGaillardia
@patricus: I got your question, but in your answer you didn't say about how to get the $id, it will be ok if they do validate for their own profile they can get their id by Auth::user()->id and in case of admin doing those part to others parts, should i set session and get inside model ,,, ???Swearingen
How are you currently getting the id of the record you are trying to update?Gaillardia
i am sending all the values to the model, $validation = Validator::make($DriverData, DriverModel::$updaterules);Swearingen
I have posted a new question here, which would be clear, can you have a look at here ,, #28206262Swearingen
C
95

This forces to ignore specific id:

'email' => 'unique:table,email_column_to_check,id_to_ignore'

replace segments table, email_column_to_check, id_to_ignore in above example

You could check it here http://laravel.com/docs/4.2/validation#rule-unique

Coralline answered 28/1, 2015 at 17:48 Comment(3)
But How can i get the id_to_ignore inside the model, I can't get the Auth::user()->id because this is admin part and doing validation for other users..Swearingen
you can get it from the request like this : request()->route('route wildcard')->idDiscreditable
If you defined your route like this: Route::apiresource('car', 'Api\CarController') then you can retrieve the resource's id like this: request()->route('car') or request()->route()->parameters['car]. If you are inside a request object you can use $this instead of request() as well.Fluorescein
L
42

For those using Laravel 5 and Form Requests, you may get the id of the model of the Route-Model Binding directly as a property of the Form Request as $this->name_of_the_model->id and then use it to ignore it from the unique rule.

For instance, if you wanted to have unique emails, but also allow an administrator to edit users, you could do:

Route:

Route::patch('users/{user}', 'UserController@update');

Controller:

public function update(UserRequest $request, User $user) 
{
    // ...
}

Form Request:

class UserRequest extends FormRequest
{
    // ...
    public function rules()
    {
        return [
            'name' => 'required|string',
            'email' => [
                'required',
                'email',
                Rule::unique('users')->ignore($this->user()->id, 'id')
            ],
            //...
        ];
    }
    //...
}

Please note that we are ignoring the user that is being edited, which in this case could be different than the authenticated user.

Lyall answered 9/9, 2017 at 18:4 Comment(3)
Rule::unique('users')->ignoreModel($this->user) may also be used.Foxe
Rule::unique('users')->ignoreModel($this->user()) is the correct syntax as of Laravel 9Caxton
I just tested and these aren't the same: $this->user gives the user as resolved by Route-Model Binding, whereas $this->user() gives the current user (i.e. the same as calling auth()->user())Mofette
B
20

I am using Laravel 5.2

if your primary key is named 'id' table name is users_table and You want to update user_name so do it this way

'user_name'  =>  'required|unique:users_table,user_name,'.$id

if your primary key is not named 'id' In my case my primary key is user_id and table name is users_table and You want to update user_name

so do it this way

'user_name' => 'required|unique:users_table,user_name,'.$id.',user_id'
Boy answered 8/12, 2018 at 10:41 Comment(0)
R
16
$request->validate([
    'email' => 'unique:table_name,email,' . $user->id
]);
Robb answered 23/11, 2018 at 5:44 Comment(1)
Welcome to StackOverflow! Kindly consider adding some explanation with your code as well, so that OP and other users may gain insight as to how and why your answer is applicable. :)Iago
S
10

Try this

'email' => 'unique:table_name,column_name,'.$this->id.',id'

$this->id will be the value from your request

Santosantonica answered 7/1, 2020 at 9:24 Comment(1)
My Question is $this->id will be validated value?? I meant to say what will happen if I pass any string value in id where it is integer field or something like ' or 1=1 ' value. I want to know is it safe from SQL Injection?Olivier
F
7

Include Rule by writing

use Illuminate\Validation\Rule;

and write your validation code as follows:

 'Email' => [required,
            Rule::unique('driver_details')->ignore($id),
            ]

Here $id is the id of the email that you want to ignore during validation which is obtained from the controller.

Flap answered 15/5, 2018 at 3:32 Comment(0)
F
7

Check This,

'email' => [
        'required',
        Rule::unique('users')->ignore($user->id),
    ],

Check here https://laravel.com/docs/7.x/validation#rule-unique.

Frascati answered 16/12, 2020 at 16:34 Comment(0)
M
6

This took me a while to figure out but when you are dealing with update/create requests you also have access to the request object. Here I am enforcing that client names are unique but allowing currently edited client.

class CreateUpdateClientRequest extends FormRequest
{
    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'name' => [
                'required',
                'string',
                'min:3',
                'max:50',
                Rule::unique('clients')->ignore($this->request->get('id'))
            ],
            'primary_contact_name' => 'required|string|min:3|max:50',
            'primary_contact_email' => 'required|string|email|min:5|max:50',
            'primary_contact_phone' => 'nullable|string|min:5|max:50',
            'secondary_contact_name' => 'nullable|string|min:3|max:50',
            'secondary_contact_email' => 'nullable|string|email|min:5|max:50',
            'secondary_contact_phone' => 'nullable|string|min:5|max:50',
            'notes' => 'nullable'
        ];
    }
}
Mordent answered 16/3, 2019 at 17:11 Comment(0)
S
6

In Laravel 6 app it helped me to exclude current user's email from validation:

use Illuminate\Validation\Rule;

public function update(Request $request, $id)
{
    $request->validate([
        'email' => [
            'email',
            'required',
             Rule::unique('claims')->ignore($id),
        ],
    ]);

    // ...
}
Spirochete answered 19/12, 2019 at 7:21 Comment(0)
B
2
<?php

namespace App\Http\Requests\Admin\User;

use App\Model\User;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Request;


class UpdateRequest extends FormRequest
{
    protected $id;

    public function __construct(Request $request)
    {
        $this->id = (integer) $request->route()->user;
    }

    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'first_name' => 'required|max:20',
            'last_name' => 'nullable|max:20',
            'mobile' => 'required|size:10|unique:users,mobile,'.$this->id,
           
        ];
    }
}
Boeotian answered 9/7, 2020 at 12:33 Comment(0)
D
2

there is a shorter way, in my case I'm using route model binding, the URL format is

/something/{user}/something

return [
        'level' => 'required|max:5|unique:users,level,'. optional($this->user)->id,
    ];
Diamonddiamondback answered 30/3, 2021 at 15:25 Comment(0)
T
2

Laravel 8:

    $request->validate([
        'email' => 'required|unique:users,email,'. $user->id,
    ]);
Testate answered 13/3, 2022 at 2:48 Comment(0)
S
2

For my case. I am using laravel 10 and I had the same issue. My table name was suppliers, and here is how I setup the rules for the request

'supplier_name' => 'required|string|max:20',
'supplier_company' => 'required|string|max:25',
'supplier_telephone' => 'required|string|max:13',
'supplier_email' => 'required', 'email',Rule::unique('suppliers')->ignore($supplier->id),
Sergo answered 28/8, 2023 at 17:9 Comment(0)
A
1

Been facing this issue for a while also. Try this:

$v = Validator::make($request->all(), [
    'email' => ['required',
    Rule::unique('<table_name>')->ignore(<your_table_id_to_ignore>),
    ]
]);

Works on Laravel 5.8. I don't know if it does work on lower versions of Laravel.

Arelus answered 2/8, 2019 at 7:18 Comment(0)
S
1

Try to use the Rule::unique('users')->ignore(Auth::id())

    //Validation
    $data = $request->validate([
        'username' => ['required', Rule::unique('users')->ignore(Auth::id()), 'min:4'],               //Verificar que este seleccionado sea único {Exceptuando mi mismo}
        'content' => 'required|min:6',
        'cover' => 'required|image'
    ]);
Shallow answered 13/8, 2020 at 19:40 Comment(1)
Just to add a note to visitors, this method worked on Laravel/Lumen 7.0 :-)Apposition
E
1

I use the same rule for create and update. But for update, I need it to ignore self.

This is what I use:

public function rules()
{
    return [
        'email' => [
            'required',
            'email',
            Rule::unique('users')->ignore($this->user->id ?? 0),
        ],
        // ...other fields
    ];
}

If update, then $this->user->id will be ignored. Otherwise if it's create, it will ignore id 0, which doesn't exist anyway.

Engraft answered 22/10, 2020 at 4:34 Comment(0)
C
1

It'll work...

$this->validate($request, 
    [
        'name' => 'required|unique:your_table_name,column_name,'.$request->auto_increment_id
    ],
    [
        'name.required' => 'Name should not be empty',
        'name.unique' => 'Name Already Exists'
    ]
);
Countrywoman answered 22/10, 2020 at 4:46 Comment(0)
I
1

you can try like this with check if deleted at column is null or not

for example:

$this->validate($request, [
  'email' => 'required|string|max:255|unique:table_name,email,'.$request->id.',id,deleted_at,NULL'
]);
Inept answered 18/6, 2021 at 7:41 Comment(0)
N
1

This worked for me on Laravel 8.

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;

class UserRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            'name' => 'required|string',
            'email' => [
                'required',
                'email',
                Rule::unique('users', 'email')->ignore($this->user)
            ]
        ];
    }
}
Nyx answered 25/8, 2021 at 3:31 Comment(0)
P
1

This is other solution, pay attention over route parameter, is the "id" of user. Compare with solution mentioned by Arian Acosta.

Route:

Route::patch('users/{id}', [UserController::class, 'update']);

Controller:

public function update(UserRequest $request, $id) 
{
    // ...
}

Form Request:

class UserRequest extends FormRequest
{
    public function rules()`
    {
        return [
            'name' => 'required|string',
            'email' => 'required|email|unique:users,email,'.$this->id.',id',
        //...
        ];
    }
    //...
}
Polanco answered 14/9, 2021 at 4:56 Comment(0)
V
1
    'phone' => 'string|required|max:11|min:11|unique:users,phone,'.Auth::user()->phone.',phone'
Vraisemblance answered 14/3, 2022 at 3:56 Comment(0)
L
1

Laravel 10

 'email' => ['required', 'email:rfc,dns', Rule::unique('users')->ignore($this->route()->user->id,'id')],
Leadwort answered 23/11, 2023 at 21:45 Comment(1)
Hi. Please provide an explanation with your code block to offer context for why your approach is chosen, significant, necessary, etc. This will help future users gain a better understanding of your answer.Vegetate
P
0

i normaly make a rules array on controller construct, like this:

public function __construct()
{
    $this->rules = [
    'name' => 'required',
    'isCPNJ' => 'required',
    'CPF_CNPJ' => 'required',
    'password' => 'sometimes',
    'role_id' => 'sometimes',
    ];
 }

And then, when i need to validate somenthing specific, like the id and email on update, i create a specificRules variable and concatenate the id that i wish to ignore in the end of the rule,like this:

//Add the original rules to specificRules, just to make things more readable
$specificRules = $this->rules;
//Add the new rules
$specificRules['email'] = 'required|email|unique:users,email,' . $request['id'];
$specificRules['id'] = 'required|exists:users';
//Validate and save in $postData
$postData = $this->validate($request, $specificRules);

If someone has a more cleaner and simple way, please let me know :D

Papa answered 15/8, 2020 at 18:14 Comment(0)
M
0
  $validator = validator()->make($request->all(), [
            'product_name'  => 'required|min:10|unique:products,name,'.$id,
            'product_slug'  => 'required|min:10|unique:products,slug,'.$id,
            'product_desc'  => 'required',
            'short_desc'    => 'required',
            'color'         => 'required',
            'product_sku'   => 'required|unique:products,sku,'.$id,
            'offer_price'   => 'required',
            'actual_price'  => 'required',
            'product_size*' => 'required',
            'product_image*'=> 'required|mimes:jpeg,png,jpg',
            'product_brand' => 'required',
            'product_meta'  => 'required',
        ]);

    if($validator->fails()) {
        $messages = $validator->messages();
        return redirect()->back()->withErrors($messages);
    }

this $id Forcing a unique rule to ignore a given id this is working for me

Mitchell answered 11/2, 2022 at 12:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.