Laravel : Validating unique fields in form updates

Laravel can be a bit gnarly with the form validation when you’re updating things like a user profile, you need not to check for a unique field against the current user.

Let’s take the following example code:

 

public function store(Request $request)
    {
        $validate = $request->validate([
            'password' => 'required|min:6|max:20',
            'email' => 'required|email|unique:users',
            'name' => 'required'
        ]);
    
    // Do the rest of the store
}

Creating a new user this would work fine, all the fields are required and the email will be unique on the users table.

However, if you try and use this in your update method like so:

public function update($id, Request $request)
    {
        $validate = $request->validate([
            'password' => 'required|min:6|max:20',
            'email' => 'required|email|unique:users',
            'name' => 'required'
        ]);
    
    // Do the rest of the update
}

You’ll start to encounter problems!

If the user hasn’t updated their email address the validator will fail because the email address was not unique (it already exists in the database as the user we are trying to update), the way around this is to specify the field and ID that should be ignored in that unique check.

public function update($id, Request $request)
    {
        $validate = $request->validate([
            'password' => 'required|min:6|max:20',
            'email' => 'required|email|unique:users,email.' . $id,
            'name' => 'required'
        ]);
    
    // Do the rest of the update
}

What about passwords?

The above will still fail if like us you have a password change field that if left empty doesn’t change the password, so we used something like this:

public function update($id, Request $request)
    {
        $validate = $request->validate([
            'password' => 'nullable|min:6|max:20',
            'email' => 'required|email|unique:users,email.' . $id,
            'name' => 'required'
        ]);
    
     $input = $request->all();

     if (empty($input['password'])) {
        // No password change
        unset($input['password']);
     } else {
        $input['password'] = Hash::make($input['password']);
     }
}

The password could be null, but if it is there it should be between 6 and 20 characters, if it is there then hash it otherwise remove it from the input array!

Leave a Reply

Your email address will not be published. Required fields are marked *