Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel request update unique field only if changed

I wan't to be able to validate a user email address based on certain circumstances.

For example

If a user is being created, the email address must be unique

If a user is being updated but the email address hasn't changed, ignore the unique email rule

If a user is being updated and their email address has changed, it has to be unique

I've had a little look around and I know that I can specify different rules based on the method like so

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

    switch($this->method())
    {
        case 'POST':
        {
            return [
                'user.email'      => 'required|email|unique:users,email',
            ];
        }
        case 'PUT':
        case 'PATCH':
        {
            return [
                'user.email'      => 'required|email,
            ];
        }
        default:break;
    }
}

Is there any way to make it so that in the put/patch case, the rule checks if the email address has been changed, and if it has then it has to be unique?

If not is there a cleaner way of achieving this goal? Maybe without the switch case? Perhaps more in depth validation rules I haven't stumbled across yet?

like image 733
S_R Avatar asked Jul 17 '18 10:07

S_R


3 Answers

If i understand you correctly, you want to add unique validation if email changed, if that is the case then you just need to add a condition in validation. If you check unique validation structure it look like this unique:table,column,except,idColumn, check documentation

So the validation will be look like this, when you will create new record $userId will be null but at time of patch it will have value. So this validation will work for both create and patch.

$userId = isset($user) ? $user->id : null;

$rules = [
        'email' => 'required|email|unique:users,email,'. $userId.',id',
    ];

 $this->validate($request, $rules);
like image 174
rkj Avatar answered Nov 11 '22 05:11

rkj


I had a similar issue and found a tidy way of addressing it in the docs.

My issue was that if a user was already created, the email address claimed it wasn't unique, even if it was already registered to the user.

https://laravel.com/docs/8.x/validation#rule-unique

A few headings down is something like this:

use Illuminate\Validation\Rule;

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

This does the following:

Validate the email address, make it required and unique, unless the user ID of that row matches this user.

like image 30
Djave Avatar answered Nov 11 '22 05:11

Djave


There is a built-in feature for this. You can add the actual user id to the unique constraint, if present. This will ensure that the unique constraint will still work, but it will not fail when the value did not change:

$exists = $user->exists;
$rules = return [
    'user.email' => 'required|email|unique:users,email' . ($exists ? ','.$user->id : ''),
];

Internally, this will execute a query like:

SELECT count(id) FROM users WHERE email = '[email protected]' AND id != 42

The latter part AND id != 42 will only be part of the query when you add the third parameter to the unique validation rule.

like image 1
Namoshek Avatar answered Nov 11 '22 03:11

Namoshek