Search code examples
laravelvalidationlaravel-validation

Including Parameters in Message For Custom Validation Rule


I have created a custom validation rule:

<?php

namespace App\Rules;

use Carbon\Carbon;
use Illuminate\Contracts\Validation\Rule;

class NotOlderThan
{
    public function validate($attribute, $value, $parameters, $validator)
    {
        $maxAge = $parameters[0];
        $date = Carbon::parse($value);

        return !Carbon::now()->subYears($maxAge)->gte($date);
    }
}

I have added it in my ServiceProvider:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Validator;

class RulesServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        Validator::extend('phone', 'App\\Rules\\Phone');
        Validator::extend('not_older_than', 'App\\Rules\\NotOlderThan');
    }
}

I have modified resources/lan/en/validation.php to include the following:

/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/

'phone' => 'The :attribute must be a valid :locale number without the country code prefix.',
'not_older_than' => 'Age cannot be older than :maxAge',

Now I am able to use these custom validation rules like this:

$this->validate([
    'phone' => 'required|phone',
    'dateOfBirth' => 'not_older_than:30',
    'issuedAt' => 'not_older_than:10'
]);

Now the problem I have is I want to be able to include the parameters in the validation message returned to the client but I'm not sure where to set that. eg. 'not_older_than' => 'Age cannot be older than :maxAge' should return Age cannot be older than 30 years. in the above example.


Solution

  • So taking a 2nd look at the docs I saw the following which I must have missed the first time:

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Validator::extend(...);
    
        Validator::replacer('foo', function ($message, $attribute, $rule, $parameters) {
            return str_replace(...);
        });
    }
    

    However this did not work for me, for some reason whenever I added this code custom validator stopped working, no errors it just didn't work. So I look around and found a solution here tat recommended I try it this way instead:

    <?php
    
    namespace App\Rules;
    
    use Carbon\Carbon;
    use Illuminate\Contracts\Validation\Rule;
    
    class NotOlderThan
    {
        public function validate($attribute, $value, $parameters, $validator)
        {
            $validator->addReplacer('not_older_than',  function ($message, $attribute, $rule, $parameters) {
                return str_replace(':age', $parameters[0], $message);
            });
    
            $maxAge = $parameters[0];
            $date = Carbon::parse($value);
    
            return Carbon::now()->subYears($maxAge)->lte($date);
        }
    }
    

    Here I call the validator instance in my validate method of my custom rule class and use replacer on it. This worked for me.