Laravel: Validation unique on update

2019-01-22 20:02发布

问题:

I know this question has been asked many times before but no one explains how to get the id when you're validating in the model.

'email' => 'unique:users,email_address,10'

My validation rule is in the model so how do I pass the ID of the record to the validation rule.

Here is my models/User

protected $rules_update = [
    'email_address' => 'required|email|unique:users,email_address,'.$id,
    'first_name' => "required",
    'last_name' => "required",
    'password' => "required|min:6|same:password_confirm",
    'password_confirm' => "required:min:6|same:password",
    'password_current' => "required:min:6"
];

models/BaseModel

    protected $rules = array();

public $errors;

/*
    * @data: array, Data to be validated
    * @rules: string, rule name in model 
*/

public function validate($data, $rules = "rules") {

    $validation  = Validator::make($data, $this->$rules);

    if($validation->passes()) {
        return true;
    }

    $this->errors = $validation->messages();

    return false;
}

回答1:

One simple solution.

In your Model

protected $rules = [
    'email_address' => 'sometimes|required|email|unique:users',
    ..
];

In your Controller, action:update

...
$rules = User::$rules;
$rules['email_address'] = $rules['email_address'] . ',id,' . $id;
$validationCertificate  = Validator::make($input, $rules); 


回答2:

There is an elegant way to do this. If you are using Resource Controllers, your link to edit your record will look like this:

/users/{user}/edit OR /users/1/edit

And in your UserRequest, the rule should be like this :

public function rules()
{
    return [
        'name' => [
            'required',
            'unique:users,name,' . $this->user
        ],
    ];
}

Or if your link to edit your record look like this:

/users/edit/1

You can try this also:

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


回答3:

If i understand what you want:

'email' => 'required|email|unique:users,email_address,'. $id .''

In model update method, for exemple, should receive the $id with parameter.

Sorry my bad english.



回答4:

Just a side note, most answers to this question talk about email_address while in Laravel's inbuilt auth system, the email field name is just email. Here is an example how you can validate a unique field, i.e. an email on the update:

In a Form Request, you do like this:

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

Or if you are validating your data in a controller directly:

public function update(Request $request, User $user)
{
  $request->validate([
      'email' => 'required|email|unique:users,email,'.$user->id,
  ]);
}

P.S: I have added some other rules, i.e. required and email, in order to make this example clear for newbies.



回答5:

public function rules()
{

    switch($this->method())
    {
        case 'GET':
        case 'DELETE':
        {
            return [];
        }
        case 'POST':
        {
            return [
                'name' => 'required|unique:permissions|max:255',
                'display_name' => 'required',
            ];
        }
        case 'PUT':
        case 'PATCH':
        {
            return [                    
                'name' => 'unique:permissions,name,'.$this->get('id').'|max:255',
                'display_name' => 'required',
            ];
        }
        default:break;
    }    
}


回答6:

$rules = [
    "email" => "email|unique:users, email, {{$id}}, user_id"
];

In Illuminate\Validation\Rules\Unique;

Unique validation will parse string validation to Rule object

Unique validation has pattern: unique:%s,%s,%s,%s,%s'

Corresponding with: table name, column, ignore, id column, format wheres

/**
 * Convert the rule to a validation string.
 *
 * @return string
 */
public function __toString()
{
    return rtrim(sprintf('unique:%s,%s,%s,%s,%s',
        $this->table,
        $this->column,
        $this->ignore ?: 'NULL',
        $this->idColumn,
        $this->formatWheres()
    ), ',');
}


回答7:

From Laravel 5.7, this works great

use Illuminate\Validation\Rule;

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

Forcing A Unique Rule To Ignore A Given ID:



回答8:

Found the easiest way, working fine while I am using Laravel 5.2

public function rules()

{

switch ($this->method()) {
    case 'PUT':
        $rules = [
            'name'                  => 'required|min:3',
            'gender'                => 'required',
            'email'                 => 'required|email|unique:users,id,:id',
            'password'              => 'required|min:5',
            'password_confirmation' => 'required|min:5|same:password',
        ];
        break;

    default:
        $rules = [
            'name'                  => 'required|min:3',
            'gender'                => 'required',
            'email'                 => 'required|email|unique:users',
            'password'              => 'required|min:5',
            'password_confirmation' => 'required|min:5|same:password',
        ];
        break;
}

return $rules;
}


回答9:

an even simpler solution tested with version 5.2

in your model

// validator rules
public static $rules = array(
    ...
    'email_address' => 'email|required|unique:users,id'
);


回答10:

This is what I ended up doing. I'm sure there is a more efficient way of doing this but this is what i came up with.

Model/User.php

protected $rules = [
    'email_address' => 'sometimes|required|email|unique:users,email_address, {{$id}}',
];

Model/BaseModel.php

public function validate($data, $id = null) {


      $rules = $this->$rules_string;

     //let's loop through and explode the validation rules
     foreach($rules as $keys => $value) {

        $validations = explode('|', $value);

        foreach($validations as $key=>$value) {

            // Seearch for {{$id}} and replace it with $id
            $validations[$key] = str_replace('{{$id}}', $id, $value);

        }
        //Let's create the pipe seperator 
        $implode = implode("|", $validations);
        $rules[$keys] = $implode;

     }
     ....

  }

I pass the $user_id to the validation in the controller

Controller/UserController.php

public function update($id) { 

   .....

    $user = User::find($user_id);

    if($user->validate($formRequest, $user_id)) {
      //validation succcess 
    } 

    ....


}


回答11:

My solution:

$rules = $user->isDirty('email') ? \User::$rules : array_except(\User::$rules, 'email');

Then in validation:

$validator = \Validator::make(\Input::all(), $rules, \User::$messages);

The logic is if the email address in the form is different, we need to validated it, if the email hasn't changed, we don't need to validate, so remove that rule from validation.



回答12:

$validator = Validator::make( array( 'E-mail'=>$request['email'], ), array( 'E-mail' => 'required|email|unique:users,email,'.$request['id'], ));



回答13:

'email' => 'required|email|unique:users,email_address,'. $id .'ID'

Where ID is the primary id of the table



回答14:

While updating any Existing Data Write validator as following:

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

This will skip/ignore existing user's id's unique value matching for the specific column.