Need to validate uniqueness without case sensitivity in Laravel? Here’s a custom rule that does just that — perfect for things like emails, titles, or usernames.
Create a custom validation rule like this:
namespace App\Rules;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
class UniqueCaseInsensitive implements ValidationRule
{
protected string $table;
protected string $column;
protected $ignore = null;
protected string $idColumn = 'id';
protected array $wheres = [];
public function __construct(string $table, string $column = 'email')
{
$this->table = $table;
$this->column = $column;
}
public function ignore($id, ?string $idColumn = null): self
{
if ($id instanceof Model) {
return $this->ignoreModel($id, $idColumn);
}
$this->ignore = $id;
$this->idColumn = $idColumn ?? 'id';
return $this;
}
public function ignoreModel(Model $model, ?string $idColumn = null): self
{
$this->idColumn = $idColumn ?? $model->getKeyName();
$this->ignore = $model->getAttribute($this->idColumn);
return $this;
}
public function where(Closure $callback): self
{
$this->wheres[] = $callback;
return $this;
}
public function validate(string $attribute, mixed $value, Closure $fail): void
{
$query = DB::table($this->table)
->whereRaw("LOWER({$this->column}) = ?", [strtolower($value)]);
foreach ($this->wheres as $callback) {
$query = $query->where($callback);
}
if (!is_null($this->ignore)) {
$query->where($this->idColumn, '!=', $this->ignore);
}
if ($query->exists()) {
$fail(__('validation.unique'));
}
}
}
Example Usage
In your form request or controller:
use App\Rules\UniqueCaseInsensitive;
$rules = [
'title' => [
'required',
new UniqueCaseInsensitive('departments', 'title')
->where(function ($query) use ($companyId) {
return $query->where('company_id', $companyId)
->whereNull('deleted_at');
})
->ignore($departmentId),
],
];
This rule respects soft deletes, ignores a specific row, and ensures lowercase uniqueness — all while staying clean and readable.