Format data before validating

This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the data category.

Last Updated: 2024-11-21

I had the following code to validate email field uniqueness before creating a user:

<?php

function create() {
  Validator::make($request->all(), [
    'email' => 'required|string|email|max:255|unique:users',
  ])->validate();

  $user = User::create([
      'email' => trim(strtolower($request['email'])),
      'password' => bcrypt($request['password']),
      'phone_number' => $request['phoneNumber']
  ]);
}

Yet, despite my validations saying the email was unique, some users could not be created due to DB constraints saying the email provided was non-unique. How is this possible that the validation passes but the DB constraint fails?

The issue was that I validated the non-formatted emails. Notice how I format the emails after validation (but before saving to the DB) with trim(strtolower($request['email']))

The fix is to format prior to validating:

<?php

  $request['email'] = trim(strtolower($request['email']));
  $this->validator($request->all())->validate();

  $user = User::create([
      'email' => $request['email'],
      'password' => bcrypt($request['password']),
      'phone_number' => $request['phoneNumber']
  ]);