Search code examples
laraveldatecustomvalidator

Object of class Closure could not be converted to string when adding custom validation in Laravel


Am working on some custom validation rules in Laravel whereby am adding some custom validation of 2 dates where return date must be 6 days after depart date,, I keep getting the folllowing error when I add the custom validation:

(1/1) ErrorException Object of class Closure could not be converted to string in ValidationRuleParser.php line 107

Please assist

Controller

public function validatePlanEntries(Request $request)
{
    $validation = $this->validate($request, [
        'departure_date' => 'required|date|after:now',

        //Must be 6 days after departure date
        'return_date' => ['required', 'date', function ($attribute, $value, $fail) {
            if (strtotime($value) < strtotime(request('departure_date')) + 518400) {
                $fail('Departure date invalid');
            }
        }],
    ]);
}

Solution

  • As you mentioned in the comment you are using a version of Laravel which does not support callback validation rules, unfortunately the only way you can do this is by extending the validator with your new rule.

    Add this in one of your service providers (e.g. AppServiceProvider)

    public function boot() {
         //Other boot things
    
        $validator = app()->make(\Illuminate\Validation\Factory::class);
        $validator->extend('return_date_after', function ($attribute, $value, $parameters, $validator) {
              $otherAttribute = array_get($parameters, 0);
              $days = array_get($parameters, 1, 6); //default 6 days
              $otherValue = array_get($validator->getData(), $otherAttribute);
              if (strtotime($value) < strtotime($otherValue) + $days*24*60*60) {
                return false;
              }
              return true;
        });
    
        $validator->replacer('return_date_after', function ($message, $attribute, $rule, $parameters) {
              return 'Your return date must be '.array_get($parameters,1,6).' days after your '.array_get($parameters, 0);
       });
    }
    

    Then you can use this custom rule as:

      $validation = $this->validate($request, [
            'departure_date' => 'required|date|after:now',
    
            //Must be 6 days after departure date
            'return_date' => ['required', 'date', 'return_date_after:departure_date,6' ]
        ]);
    

    Note the $message in your replacer comes from the resources/lang/<locale>/validation.php so you can add an entry in there such as "return_date_after" and manipualte it in your replacer instead of returning static text. For example:

    "return_date_after" => "Your :attribute must be :days days after your :other_attribute"
    

    And then your replacer can be :

     $validator->replacer('return_date_after', function ($message, $attribute, $rule, $parameters) {
          return str_replace([ ":days", ":other_attribute" ], 
              [ array_get($parameters, 1, 6), array_get($parameters,0) ], 
              $message);        
    });