2 BONUS TIPS AT THE END !!!
The Validation Logic: For eg: i want to apply custom validation of : allow only users who have age above 20 .
So lets first create a service provider to define our custom validation logic by writing
php artisan make:provider ValidationServiceProvider
Note: Its not necessary to create separate service provider but just for the sake of separation of concern... (You can still put logic in the AppServiceProvider in the boot method ) ...
Then we will register the provider in the config/app.php file just like this :
'providers' => ServiceProvider::defaultProviders()->merge([
/*
* Package Service Providers...
*/
/*
* Application Service Providers...
*/
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
App\Providers\ValidationServiceProvider::class
])->toArray(),
ok so now our registration is complete of the validation now go to the validation service provider
Now here first we define our Validator class and use the method called extends now this extends method will accept 3 parameters
So let's first name our custom validation rule called olderThan and in the second parameter here we will have our closure function which will have our main custom validation logic .
And in the 3rd parameter we will define our rule message that we want to show .
Now it will look like this :
public function boot(): void
{
\Validator::extend('olderThan', function($attribute, $value, $parameters)
{
//validation logic
});
}
Now in the function also it will accept 3 parameters .
you can pass the parameters like this:
$request->validate([
'age' => 'olderThan:20' <--- parameter
]);
To Pass multiple Paramters:
$request->validate([
'age' => 'olderThan:20,18,29' <--- parameter
]);
and then you can access the parameters like comment given below in the code:
Now lets write our custom logic now :
\Validator::extend('olderThan', function($attribute, $value, $parameters)
{
// $parameters[0], $parameters[1], $parameters[2] <-- to access multiple parameters values
$minAge = (!empty($parameters)) ? (int)$parameters[0] : 18;
return \Carbon\Carbon::now()->diff(new \Carbon\Carbon($value))->y >= $minAge;
},'Age cannot be greater than 18');
Now we have written our logic, which checks if the user is above specific age we have to allow them else don't allow them , but wait there is one problem here if you noticed ?
The age should be dynamic and so should be the message now if we write it like this :
\Validator::extend('olderThan', function($attribute, $value, $parameters)
{
$minAge = (!empty($parameters)) ? (int)$parameters[0] : 18;
return \Carbon\Carbon::now()->diff(new \Carbon\Carbon($value))->y >= $minAge;
},'Age cannot be greater than ' . $paramters[0]);
its gonna throw me an exception : "undefined variable $paramters".
To tackle this we have to add a Validator Replacer so that we can make our message dynamic
\Validator::replacer('olderThan', function($message, $attribute, $rule, $parameters){
return str_replace(':min_age', $parameters[0], 'Only Allow Age who are above :min_age');
});
This also will have a replacer method which will accept 2 paramters:
- first one will be the validator rule name which we just created
- second paramter will be our function which will have our dynamic message logic and this function will also accepts 4 paramters. Now let me show what each parameter is
$message => if you dd($message) you will get "validation.older_than" which denotes our lang/en/validation.php where we store our global validation messages and define it in the validation file like this : validation.older_than => "Age should be above 18",
$attribute => this will be our name attribute which is defined in our input element which is in our case is age
$rule => this will will print the rule which we have defined here which is OlderThan
We now have all our dynamic variables which we want to use .
We will use str_replace() method to replace a particular string to our dynamic variable like this:
return str_replace(':min_age', $parameters[0], 'Only Allow Age who are above :min_age'); });
This will replace this string :
'Only Allow Age who are above :min_age'
To this:
'Only Allow Age who are above 18'
Our final validation will look like this:
public function boot(): void
{
\Validator::extend('olderThan', function($attribute, $value, $parameters)
{
$minAge = (!empty($parameters)) ? (int)$parameters[0] : $parameters[0];
return \Carbon\Carbon::now()->diff(new \Carbon\Carbon($value))->y >= $minAge;
});
\Validator::replacer('olderThan', function($message, $attribute, $rule, $parameters){
return str_replace(':min_age', $parameters[0], 'Only Allow Age who are above :min_age');
});
}
Or you can also globally register the message in lang/en/validation.php
'custom' => [
'age' => [
'older_than' => 'Only allow :attribute above :min_age',
],
],
In ValidationServiceProvider.php
public function boot(): void
{
\Validator::extend('olderThan', function($attribute, $value, $parameters)
{
$minAge = (!empty($parameters)) ? (int)$parameters[0] : $parameters[0];
return \Carbon\Carbon::now()->diff(new \Carbon\Carbon($value))->y >= $minAge;
});
\Validator::replacer('olderThan', function($message, $attribute, $rule, $parameters){
return str_replace(':min_age', $parameters[0],$message);
});
}
2 Bonus Tips:
1st Tip:
You can also use class also instead of a closure like this :
Note: this will only work if the method name is validate.
in ValidationServiceProvider.php
\Validator::extend('olderThan',[OlderThanValidation::class]);
In App\Validators/OlderThanValidation.php
<?php
namespace App\Validators;
class OlderThanValidation
{
public function validate($attribute, $value, $parameters)
{
$minAge = (!empty($parameters)) ? (int)$parameters[0] : $parameters[0];
return \Carbon\Carbon::now()->diff(new \Carbon\Carbon($value))->y >= $minAge;
}
}
2nd Tip
You can also use custom validation directly in the controller by throwing a validation exception like this :
public function store(Request $request)
{
$request->validate([
'age' => 'required'
]);
if(\Carbon\Carbon::now()->diff(new \Carbon\Carbon($request->age))->y < 20){
return throw \Illuminate\Validation\ValidationException::withMessages(
[
'age' => __('validation.custom.age.older_than',
[ //pass dynamic attributes in the array
'min_age' => 20,
'attribute' => __('validation.attributes.age')
])
]
);
}
}
lang/en/validation.php
return [
'custom' => [
'age' => [
'older_than' => 'Only allow :attribute above :min_age',
],
],
/*
|--------------------------------------------------------------------------
| Custom Validation Attributes
|--------------------------------------------------------------------------
|
| The following language lines are used to swap our attribute placeholder
| with something more reader friendly such as "E-Mail Address" instead
| of "email". This simply helps us make our message more expressive.
|
*/
'attributes' => [
'age' => 'Age'
],
]
I hope you enjoyed my article STAY TUNED for the second part of in Depth Series of Validation