How to add custom validation rules in Laravel (with examples)

Updated: January 18, 2024 By: Guest Contributor Post a comment

Introduction

Laravel, the popular PHP framework, provides a wide range of features to make development more convenient and robust, one of which is its powerful validation component. Out-of-the-box, Laravel supports numerous validation rules that cater to common use-cases; however, there might be instances where you need something specific that isn’t provided by default. This is where custom validation rules come into play.

In this tutorial, we will walk through the process of creating custom validation rules in Laravel. We’ll start from the basics and gradually move to more complex examples, to ensure that you can adapt these methods to your own projects.

Prerequisites

  • A basic understanding of PHP and Laravel
  • Laravel installed on your development machine
  • A functioning Laravel project to test the validation rules

Basic Custom Validation

To add a simple custom validation rule in Laravel, you can just pass a Closure to the Validator::extend.

$validator = Validator::make($data, [...]);

Validator::extend('custom_rule', function ($attribute, $value, $parameters, $validator) {
  return $value == 'some_value'; // Custom condition
});

if ($validator->fails()) {
  return redirect('some_route')->withErrors($validator);
}

In this example, the custom_rule checks if the given attribute equals ‘some_value’. This is, of course, very basic and not that useful; we’ll get to more practical examples shortly.

Using Rule Objects

A more advanced way to apply custom validation rules is by using rule objects. Laravel makes it easy to create new rule objects by executing an Artisan command:

php artisan make:rule ValidCustomText

Once you’ve run the command, a new Rule object is generated in the app/Rules directory. Let’s suppose we want to validate a string so it’s not only alphanumeric but also has alternating alphabets and numbers.

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class ValidCustomText implements Rule
{
  public function passes($attribute, $value)
  {
    return preg_match('/^(?:[a-z]+\d+|[\d]+[a-z]+)+$/i', $value) > 0;
  }

  public function message()
  {
    return 'The :attribute must have alternating letters and numbers.';
  }
}

You can then utilize your new Rule object when defining your validation logic.

use App\Rules\ValidCustomText;

$request->validate([
  'custom_text' => [new ValidCustomText()],
]);

This code snippet sets up validation for a request input named custom_text using our custom ValidCustomText rule.

Complex Conditional Validation

Sometimes you might need validation rules that cope with more complex conditions. Let’s create a custom rule which validates an input based on the value of another input in the request.

Validator::extend('if_value_then_required', function ($attribute, $value, $parameters, $validator) {
  $other = Arr::get($validator->getData(), $parameters[0], null);
  return $other != $parameters[1] || !empty($value);
});

In this rule, named if_value_then_required, if another field (specified in $parameters[0]) is equal to a certain value ($parameters[1]), then the field under validation must not be empty.

$validator = Validator::make($request->all(), [
  'some_field' => 'required',
  'conditional_field' => 'if_value_then_required:some_field,some_value',
]);

if ($validator->fails()) {
  return redirect('some_route')->withErrors($validator);
}

Here, 'conditional_field' is required only if 'some_field' equals 'some_value'.

Custom Validation Messages

Defining custom messages for your custom rules should not be overlooked as it provides clearer feedback to users. When creating a Rule object, the message method allows you to specify the feedback message to be returned if validation fails.

Alternatively, when using closures, you can define custom messages by adding them to your validation logic:

$messages = [
  'custom_rule' => 'The :attribute must meet custom rule requirements.',
];

$validator = Validator::make($request->all(), [...], $messages);

Here, :attribute is a placeholder for the name of the input field being validated. It’s automatically replaced by the actual name by Laravel when orchestrating the error message.

Error Handling and Displays

After defining your custom rule, it’s important that you also consider how you will handle and display validation errors. Laravel provides several methods for retrieving and showing error messages.

You can pass errors back to views and use the $errors variable to show them:

@if ($errors->any())
  • {{ $error }}

@endif

In a JSON API, you could return the errors in your response:

if ($validator->fails()) {
  return response()->json(['errors' => $validator->messages()], 422);
}

Laravel also provides the ability to custom format the error messages in responses by specifying your custom formatter in a service provider.

Conclusion

Sometimes Laravel’s built-in rules are not enough, and you have to create custom validation to match your unique business logic. As you’ve seen in these examples, Laravel provides several ways to apply custom validation rules that are intuitive and extendable.

Remember that validation is a critical part of any application, and investing time to refine it brings you one step closer to a great user experience and a secure app.