Validation is an important part of our application. Formerly we wrote about Laravel’s form requests and how to move your validation logic into them. Now we want to show some various validation issues and how to solve them with custom validation rules.
Creating custom validation rules
With the new make:rule command we can generate our custom rules. Along the constructor, we have two other methods by default.
The first is the passes() method, where we have to implement the logic what determines if the given value is correct or not. The other method is the message(), where we can customize our error message if the validation fails.
If we have a ready to use rule, all we have to do to add it to the value’s identifier what we want to validate. In this case, we have to use an array of validation rules, instead of a string, where we separate them with a | character.
// string version 'email' => 'string|email|max:255', // array version with the custom rule 'email' => [ 'string', 'email', 'max:255', new MyCustomRule, ],
As we see, it’s straightforward to add the custom rules we want. Of course, if we need we can pass anything to the constructor, we will see some example of that as well.
Let’s see some common validation issues and their solutions with custom validation rules. We will take a look only the passes() method, but we share the rules, and you can use them if you need!
#1 Checking the user’s password
It’s a good practice to check if the real user is using the app by checking its password. Since the password is hashed, we need to be a bit tricky and use Laravel’s Hash facade.
protected $user; public function __construct(User $user) { $this->user = $user; } public function passes($attribute, $value) { return Hash::check($value, $this->user->password); }
#2 Odd or even numbers
If for some reason, we need to check if a number odd or even we can do the following:
// Odd public function passes($attribute, $value) { return (int) $value % 2 === 1; } // Even public function passes($attribute, $value) { return (int) $value % 2 === 0; }
#3 Value can be incremented only
In some cases, we need to make sure that the given value is not lower than the current one. For example, if we are versioning some model (like 0.1.0, 0.1.1, etc.), we should ensure the versions are incrementing.
protected $model; public function __construct($model) { $this->model = $model; } public function passes($attribute, $value) { return version_compare($this->model->version, $value, '<'); }
#4 Value contains specific words
It can be convenient if we can check if a given text contains some particular words or text fragments. It can be useful for example spam detection. An elementary example of that:
protected $words = [ 'foo', 'bar', 'baz', ]; public function passes($attribute, $value) { return preg_match('(' . implode('|', $this->words) . ')', $value) === 1); }
#5 Day must be a weekday
If you are working with dates, mostly Laravel saves your life. Some built-in validation rules do the messy things, but sometimes we need to implement some extra features. For example, we want to restrict the dates only for weekdays and throw an error when the selected day is part of a weekend.
public function passes($attribute, $value) { return (new Carbon($value))->isWeekDay(); }
Summary
With custom validation rules, we can easily implement any kind of logic we need. It’s a nice way to keep clean the controllers or the form requests and generate customized error messages as well.
You can find the full code of the example validation rules in this repository.