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

Published 3 years ago by Raymond

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?

Best Answer (As Selected By Raymond)
callam

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;
    }
}
codenihal

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

Raymond

@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'),
   ...
    ];
 }
enginebit

@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'),
   ...
    ];
 }
Raymond

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 :-)

laurence

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,
   ... 
    ];
 }
zeeshan

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}}

sosmaier

Hi, I set this....

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

lieutdan13

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.

kyslik
kyslik
2 years ago (18,765 XP)

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}
bestmomo
bestmomo
2 years ago (373,920 XP)

There is a simpler syntax for :

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

It's :

$this->route('desired_parameter')
usman
usman
2 years ago (130,085 XP)

@bestmomo have you tried:

$this->desired_parameter;

:)

bestmomo
bestmomo
2 years ago (373,920 XP)

@usman coudn't get shorter ^^

usman
usman
2 years ago (130,085 XP)

@bestmomo haha :)

lj
lj
2 years ago (6,800 XP)

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?

saul.lopez

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) !!}
  ...
  ...
  ...

Please sign in or create an account to participate in this conversation.