Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

binalfew's avatar

Forcing a unique rule to ignore a given id

Hello,

In the documentation for validation is says:

"Sometimes, you may wish to ignore a given ID during the unique check. For example, consider an "update profile" screen that includes the user's name, e-mail address, and location. Of course, you will want to verify that the e-mail address is unique. However, if the user only changes the name field and not the e-mail field, you do not want a validation error to be thrown because the user is already the owner of the e-mail address. You only want to throw a validation error if the user provides an e-mail address that is already used by a different user. To tell the unique rule to ignore the user's ID, you may pass the ID as the third parameter:"

So, I did like this:

email'  =>  'required|unique:users,email,1'

But the validation fails when updating an existing user.

Any help is highly appreciated.

0 likes
22 replies
mstnorris's avatar

Check out this question. You can use

email'  =>  'required|email|unique:users,email,'.$user->id
8 likes
mstnorris's avatar

You'll have to show more code as to how you're passing the ID through in order for us to help you. Did you check out the linked question?

binalfew's avatar

@mstnorris Ok. I am not using Form request validation as I'm using laravel as an API where the front end is a javascript application. Here is my code:

I have a validator class like this:

use InvalidInputException;
use Illuminate\Validation\Factory as Validator;

class UserValidator
{
    protected $validator;

    public function __construct(Validator $validator)
    {
        $this->validator = $validator;
    }

    public function rules($id)
    {
        return [
            'name'  =>  'required',
            'email'  =>  'required|unique:users,id,'.$id,
            'password'  =>  'required'
        ];
    }

public function validate(array $input, $id = 0)
    {
        $validator = $this->validator->make($input, $this->rules($id));
        
        if($validator->fails()) throw new InvalidInputException();
    }
}

And I have a repository class for database operations:

class UserRepository extends Repository
{
   protected $validator;
   public function __construct(UserValidator $validator)
    {
        $this->validator = $validator;
    }  

   public function update(array $attributes, $id)
    {
        $this->validator->validate($attributes, $id);
        //----Rest of the code
    }
}
rodrigo.pedra's avatar

@binalfew Try changing this line:

class UserValidator
{
    protected $validator;

    public function __construct(Validator $validator)
    {
        $this->validator = $validator;
    }

    public function rules($id)
    {
        return [
            'name'  =>  'required',
            'email'  =>  'required|unique:users,email,'.$id, // <--- THIS LINE
            'password'  =>  'required'
        ];
    }

public function validate(array $input, $id = 0)
    {
        $validator = $this->validator->make($input, $this->rules($id));
        
        if($validator->fails()) throw new InvalidInputException();
    }
}
1 like
rodrigo.pedra's avatar

In the code you posted you had this line:

'email'  =>  'required|unique:users,id,'.$id, // note the id field

I suggested to change to this:

'email'  =>  'required|unique:users,email,'.$id, // note the email field

If you look into the docs [ http://laravel.com/docs/5.1/validation#rule-unique ], you'll see that the second argument is the table field which the value should be unique.

1 like
MESEE's avatar

what if the roles array is defined in the model ??

CyrusGreat's avatar

regarding this question, i don't understand the new way in Laravel 5.3 which is like this:

use Illuminate\Validation\Rule;

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

where should I write this code? in my FormRequest? what is $data? And how can I send the user id to FormRequest?

2 likes
swatantra's avatar

how can i replace id with userid in the query???

rahulhaque's avatar

@CyrusGreat You should write this in your controller. Here $data represents your $request. You can write the above code like this in the controller.

$this->validate($request, [
    'email' => [
        'required',
        Rule::unique('users')->ignore($user->id),
    ],
]);
cix's avatar

hi i am new in laravel . i have some questions . Is it possible to write more line for validate? for example : $this->validate($request, [ 'email' => [ 'required', Rule::unique('users')->ignore($user->id), ], another parameter => [ .... ], another parameter => [ .... ], ]);

and another question if i want to use RequestFile to check validation how pass the id for ignoring?

the third question : can i use this rule for one of the inputs and for the rest use Request file? how can i understand that the validate was true , for example if the validate true check the request file rules .

last question : which one is better Request file or validate this way in controllers ?

eduardoarandah's avatar

THIS IS AN EASY SOLUTION

Just add $this->route('id') as the third parameter

if your route was defined like this:

Route::put('{company}', 'CompanyController@update')
            ->name('update');

then your parameter name is "company"

So in your FormRequest:

    public function rules()
    {
        $rules = [
            'url' => [
                'required',
                'url',
                'unique:companies,url,'.$this->route('company') ?? 0
            ],    
        ];
        // dd($rules); << check yourself

        return $rules;
    }

This FormRequest works the same for insert or update.

this line will instruct to ignore "0" in case of insert

$this->route('company') ?? 0

4 likes
niravbhoi007's avatar

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

so I do it this way

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

2 likes
michaellatham's avatar

This snippet may be useful if you're using a FormReqest. This will ensure the name is unique, ignore the existing record and also ignore any soft deleted records.

 public function rules()
    {
        return [
            'name' => [
                'required',
                'email',
                Rule::unique('users', 'email')
                    ->where(static function ($query) {
                        return $query->whereNull('deleted_at');
                    })
                    ->ignore($this->user),
            ]
        ];
    }
hassam's avatar

How to manage unique rule in Laravel Nova

Nova version v4.25.1 (Silver Surfer)

For Laravel Nova use ->creationRules() and ->updateRules() methods.

// app\Nova\Expense.php

Text::make('Type')
    ->sortable()
    ->rules('required', 'string')
    ->creationRules('unique:expenses,type')
    ->updateRules('unique:expenses,type,{{resourceId}}'),

If you use Route Model Binding and Form Request.

To ignore unique rule you need Model ID you can apply unique rule on any column e.g type, name, amount, email, two_factor_code etc of the Model BUT you require Model ID for ignoring unique rule on update. So, we can get model-id using $this->segments() or $this->route('expense')->id and i prefer second approach.

for this you can create two form requests e.g ExpenseStoreRequest and ExpenseUpdateRequest BUT I'm using single ExpenseRequest and it will mange both POST and PUT/PATCH

$this->route('expense')->id return the ID "2" from URL query params e.g http://127.0.0.1:8000/api/v1/expense/2, you can even use $this->segment(4); it returns 2 which is Model id, but this approach is not good reason.

$this->segments();
array:4 [ // app/Http/Requests/ExpenseRequest.php:11
  0 => "api"
  1 => "v1"
  2 => "expense"
  3 => "2"
]

$this->segment(1); // api
$this->segment(2); // v1
$this->segment(3); // expense
$this->segment(4); // 2
// App\Http\ExpenseRequest
class ExpenseRequest extends FormRequest
{
    public function rules(): array
    {
        $rules = [
            'name' => ['required', 'string', 'max:100'],
            'type' => ['required', 'unique:expenses,type'],
            'amount' => ['required'],
        ];

        if ($this->isMethod('PUT') || $this->isMethod('PATCH')) {
            $rules['type'] = 'required|unique:expenses,type,' . $this->route('expense')->id;
        }

        return $rules;
    }
}

routes/api.php

Route::patch('v1/expense/{expense}', [ExpenseController::class, 'update'])
                    ->name('update')
                    ->middleware('can:viewAny,App\Models\Expense');

Please or to participate in this conversation.