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

Raymond's avatar

Laravel 5 Validation Request, how to handle validation on update?

First of all I love the way that validation is going through, can now easily use

 public function authorize(Authenticator $auth)
 {
    return $auth->user()->hasRole('administrator');
 }

That's not the problem, I bump always into another problem... that is when you update an record, how to do things with the rules? If I need to update an email, I need the following string: 'email' => 'unique:users,email_address,10'. In this case it should look like:

public function rules()
 {
    return [
   'email' => 'required|unique:users,id,?????',
   'tags' => 'required'
    ];
 }

Who can help me with this issue?

0 likes
75 replies
codenihal's avatar

Maybe You can create a new Form Request. Like `UpdateUserRequest.

4 likes
Raymond's avatar

@nsnihalsahu.code thanks, but that part i am already, read it again :-). Problem is how to set the ID in the rule.

i could do one of following things:

public function rules(Request $request)
 {
    return [
   'email' => 'required|unique:users,id,'.$request->segment(2),
   // Or i could do...
   'email' => 'required|unique:users,id,'.$request->get('id'),
   ...
    ];
 }
11 likes
enginebit's avatar

@Raymond You are inside the FormRequest class right? Then you should be able to do the following

public function rules()
 {
    return [
   'email' => 'required|unique:users,id,'.$this->segment(2),
   // Or i could do...
   'email' => 'required|unique:users,id,'.$this->get('id'),
   ...
    ];
 }
20 likes
Raymond's avatar

That is finally the thing that i gonna remember :-) thanks @enginebit, after 2-3 years of coding i always stumbled upon this particular thing. And btw, i use the get('id') that gives me more flexibility on my routes :-)

1 like
afrayedknot's avatar

How would you do this with a Route Model binding? This is what I have so far - is there any better way?

public function rules()
 {
    return [
   'email' => 'required|unique:users,id,'.$this->route->parameters()['user']->id,
   ... 
    ];
 }
3 likes
zeeshan's avatar

Firstly thanks to @enginebit . His solution lead me to success ;) However I was getting exception and I had to re arrange the segments to get it working.

If anybody is still stuck here is the solution I tried on Laravel 5:

Following is a Request Class to have unique validation on country name and code:

namespace App\Http\Requests;

use App\Http\Requests\Request;

class CountryRequest extends Request {

/**
 * 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 [
        'name' => 'required|min:3|unique:countries,name,' .$this->getSegmentFromEnd().',id',
        'code' => 'required|min:2|unique:countries,code,' .$this->getSegmentFromEnd().',id'
    ];
}

private function getSegmentFromEnd($position_from_end = 1) {
    $segments =$this->segments();
    return $segments[sizeof($segments) - $position_from_end];
}

}

Instead of getting id from segment(2) I am getting it from the segments relative to the end so if someday I have to group the routes my validation wont break.

Right now I am sending PATCH to /countries/{{id}} where 1 is the id. Some day I may have url like admin/countries/{{id}}

2 likes
sosmaier's avatar

Hi, I set this....

'email'=>'required|email|unique:users,email,'. Request::get('id'),

1 like
lieutdan13's avatar

If you use route model binding, you can do something like this:

// routes.php
Route::bind('user', function($id) {
    $user = App\User::find($id)->first();
});
Route::patch('user/{user}', 'UserController@update');

// UpdateUserRequest.php
public function rules() {
    $user = $this->route('user');
    return [
        'username' => 'required|unique:users,username,' . $user->id,
    ];
}

// UserController.php
public function update(UpdateUserRequest $request, User $user) {
    $user->fill($request->all());
    $user->save();
    return redirect()->route('user.edit', [$user->id]);
}

This is untested, but I did copy some of this code from one of my existing Controllers/Request classes and changed the names to be user related. Hope this helps.

10 likes
kyslik's avatar

Don't use segments that is bad practise, the best way is

dd($this->route()->getParameter('desired_parameter'));// you can find desired parameter in php artisan route:list and whatever is between {} is the thing you want to put there

For me it is name of model in plural form because I use resource routing

Route::resource('users', 'Dashboard\UserController');
.... $php artisan route:list ...
 PUT      | dashboard/users/{users}
3 likes
bestmomo's avatar

There is a simpler syntax for :

$this->route()->getParameter('desired_parameter')

It's :

$this->route('desired_parameter')
11 likes
lj's avatar

None of the variations above worked for me, but thanks to the last few answers I was able to get it working for my project (in which I use route model binding).

RouteServiceProvider.php

        $router->model('articles', 'App\Article');

ArticleRequest.php

public function rules()
{
    return [
        'url'     => 'unique:articles,url,'.$this->articles->id
    ];
}

Hope this helps someone out there.

EDIT Because I was also using the request for creating new objects I had to change it to:

public function rules()
{
    if (count($this->articles))
    {
        return [
            'url'     => 'unique:articles,url,'.$this->articles->id
        ];
    }
    else
    {
        return [
            'url'     => 'unique:articles'
        ];
    }
}

Would love to hear if there is an easier way to do this. Probably by creating an empty instance of Article if it doesn't exist?

1 like
saul.lopez's avatar

To handle both create/store and edit/update operations in the same FormRequest, I did the following:

...
public function rules()
{
  if ($this->method() == 'PUT')
  {
    // Update operation, exclude the record with id from the validation:
    $email_rule = 'required|email|unique:users,email,' . $this->get('id');
  }
  else
  {
    // Create operation. There is no id yet.
    $email_rule = 'required|email|unique:users,email';
  }
  return [
    'email' => $email_rule,
    'name' => 'required',
    'password' => 'required|confirmed'

  ];
}

Also, for $this->get('id') to work you have to include the id field in the form, perhaps something like:

{!! Form::model($user, array('method' => 'put', 'route' => ['users.update', $user->id])) !!}
  ...
  {!! Form::hidden('id', $user->id) !!}
  ...
  ...
  ...
4 likes
devartpro's avatar

If you want to conditionally set a rule using the above methods, you can do the following:

  • add a hidden input field with an ID to form in your edit/update view.
  • use the following in your Request class:
use Input;
...
        return [
            '' => '',           
            'password'              => 'confirmed|'.(Input::has('user_id')) ? '' : 'required',
            'password_confirmation' => (Input::has('user_id')) ? '' : 'required'
        ];
1 like
elporfirio's avatar

What happen when you want "multiple unique" fields? And I don't send the "id" to PUT method.

I use this...

    public function rules()
    {
        $this->route();
        return [
            //'name' => 'required|unique:roles,
            //'slug' => 'required|unique:roles,
            'name' => 'required|unique:roles,name,' . $this->name . ',name',
            'slug' => 'required|unique:roles,slug,' . $this->slug . ',slug'
            //'description' => 'required'
        ];
    }

But when I send (via form) a duplicated name or slug (i mean a name/slug owned by other element), throws me integrity error:

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'adalid' for key 'roles_slug_unique'

How to catch that like the others errors for this:

@foreach ($errors->all() as $error)
                        <li>{{ $error }}</li>
                    @endforeach
callam's avatar
callam
Best Answer
Level 2

You can use $this->method() to get the method name. Using a switch block, you can return the corresponding rules for a particular request method.

public function rules()
{
    $user = User::find($this->users);

    switch($this->method())
    {
        case 'GET':
        case 'DELETE':
        {
            return [];
        }
        case 'POST':
        {
            return [
                'user.name.first' => 'required',
                'user.name.last'  => 'required',
                'user.email'      => 'required|email|unique:users,email',
                'user.password'   => 'required|confirmed',
            ];
        }
        case 'PUT':
        case 'PATCH':
        {
            return [
                'user.name.first' => 'required',
                'user.name.last'  => 'required',
                'user.email'      => 'required|email|unique:users,email,'.$user->id,
                'user.password'   => 'required|confirmed',
            ];
        }
        default:break;
    }
}
64 likes
godbout's avatar

@zeeshan if you're using Route Model Binding you can drop the segments and use something like below instead:

$rules = [
            'code' => 'required|min:3|unique:programs,code,' . $this->route('programs')['id'],
        ];

then you can change your routes to whatever, add prefix and all, the correct data will always be retrieved.

2 likes
Ade's avatar

I came across this thread on Google while searching for a solution - I just wanted to add my version.

@callam has a nice solution with the switch and checking the method we're currently using, but I didn't like the rules replication. It only takes one change in one, and forgetting to update the other and you'll quickly get issues.

The route I found to overcome this was quite simple:

public function rules()
   {
        $module = app\Module::Find($this->route('Module_Management'));

        return ['module_name' => 'required|max:60|unique:modules,module_name,' . @($module->id == null ? null : $module->id),
            'module_code' => 'required|max:10|unique:modules,module_code,' . @($module->id == null ? null : $module->id),
            'department_id' => 'required|exists:departments,id',
            'user_id' => 'required|exists:users,id',];
}

The route is a resource, so it has a variable named for the update method - in this case it's "Module_Management". This is a number, and a regular expression makes sure of this before hand by using a

Route::pattern('Module_Management', '[0-9]');

This ensures that we have the id in numerical form we can pass to the find() method and get a record. If we don't get one back, it'll return null.

Then in the rules block we can simply check if the variable is null or not. If it is, just append null. If not, append the ID of the record to ignore. The only thing you need to remember is that PHP won't like it when you try to access $module->id if it's null (Trying to get property of non-object). For this reason, we suppress the error with the @ at the beginning of the ternary, which shouldn't be an issue as we're handling the error it's concerned about.

Hope that helps someone. It means you can have a single rule block for both create and update in this instance and not have to worry about replication of the ruleset and dealing with duplicate entries in the database.

callam's avatar

@Ade

If you would like to avoid repetition, you could try something like this:

public function rules()
{
    $user = User::find($this->users);

    $rules = [];

    switch($this->method())
    {
        case 'GET':
        case 'DELETE':
        {
            //
        }
        case 'POST':
        {
            $rules = [
                'user.name.first' => 'required',
                'user.name.last'  => 'required',
                'user.email'      => 'required|email|unique:users,email',
                'user.password'   => 'required|confirmed',
            ];
        }
        case 'PUT':
        case 'PATCH':
        {
            $rules['user.email'] = 'required|email|unique:users,email,'.$user->id;
        }
        default:break;
    }

    return $rules;
}
2 likes
bashy's avatar

For anyone who comes across this and just wants to edit a row

How long has this been in the framework? So easy now... :id excludes the current row ID (editing)

public function rules()
{
    return [
        'email' => 'required|email|unique:users,id,:id',
        // others
    ];
}
8 likes
pmall's avatar

@bashy How does this work ? Does :id matches the value of the id key in the values array ?

bashy's avatar

@pmall Found multiple examples on blog posts and answers on SO. Tested it myself and it seems okay.

henrique-ferrolho's avatar

@pmall @bashy what version are you using? I tried it myself and it did not work :/ But I am using Route Model Binding.. maybe that is the issue

Here is my SongRequest.php from the Laravel 5 from Scratch series:

    public function rules()
    {
        return [
            'title' => 'required',
            'slug' => 'required|unique:songs,slug,' . $this->route('songs')->id
        ];
    }
bashy's avatar

@ferrolho I tried it on the latest (v5.1.7). Probably though, I was just using normal.

jaystabins's avatar

I am having an issue where your code above "works" @bashy

The only problem I am having is a unique rule will ignore a given slug but I only want to ignore that slug for an update to that specific row.


public function rules(IncomingRequest $request)
{
        $rules = [
            'title'         => 'required',
            'body'          => 'required',
            'published_at'  => 'required|date',
            'slug'          => 'required|unique:articles'
        ];
    if($request->isMethod('PUT'))
    {
        $rules['slug'] = 'required|unique:articles,slug:' . $request->slug;
    }
    //dd($rules);
    return $rules;

}

In other words, validation will ignore the given slug (basically what I want when updating) but when I update and give it an existing slug in the database on another row it allows the insert.

jaystabins's avatar

Wow, okay, should have read the docs a little better. The below code works flawlessly.


public function rules(IncomingRequest $request)
{
        $rules = [
            'title'         => 'required',
            'body'          => 'required',
            'published_at'  => 'required|date',
            'slug'          => 'required|unique:articles'
        ];
    if($request->isMethod('PUT'))
    {
        $rules['slug'] = 'required|unique:articles,slug,' . $request->id;
    }
    return $rules;

}

3 likes
Next

Please or to participate in this conversation.