Search code examples
phpvalidationlaravel-5laravel-validation

Better control on error message on Custom Laravel 5 validation


I am defining a Custom validator in my AppServiceProvider@boot as following

/* Custom unique value in set of fields validation */
Validator::extend('unique_in', function ($attribute, $value, $parameters, $validator) {
    $validator_data = $validator->getData();
    foreach ($parameters as $field) {
        if ($value === array_get($validator_data, $field)) {
            return false;
        }
    }
    return true;
}, 'The :attribute cannot be same as any other field in this form.');

/* replace the :fields message string */
Validator::replacer('unique_in', function ($message, $attribute, $rule, $parameters) {
    // I was doing this (this works)
    //    $message = str_replace(':field', implode(',',$parameters), $message);
    //    return $message;

    //I want to do this (to get proper names for the fields)
    $other = $this->getAttribute(array_shift($parameters));

    return str_replace([':other', ':values'], [$other, implode(', ', $parameters)], $message);
});

Problem is instance of validator is not available to access getAttribute. getAttribute resolves the readable name for parameters

Is there to access validator instance in replacer?

Note that the closure in Validator::extend has $validator which is an instance of validator.


Solution

  • I got it working using getCustomMessage and setCustomMessage, but without using Validator::replacer using Validator::extend alone.

    Validator::extend('unique_in', function ($attribute, $value, $parameters, $validator) {
            $validator_data = $validator->getData();
            $parameters = array_diff($parameters, [$attribute]);
            $same = null;
            $other = null;
            foreach ($parameters as $field) {
                if ($value === array_get($validator_data, $field)) {
                    $same[] = $field;
                }
            }
    //No same values found , validation success
            if (is_null($same)) {
                return true;
            }
    
    // Get all Custom Attributes those are defined for this validator and replace with field in $same array and create a new $other array
            $custom_attributes = $validator->getCustomAttributes();
            foreach ($same as $attribute) {
                $other[$attribute] = isset($custom_attributes[$attribute]) ? $custom_attributes[$attribute] : $attribute;
            }
    
    //Task of Validator:replacer is done right here.
            $message = 'The :attribute cannot have same value ":value" as in :fields';
            $message = str_replace([':value',':fields'], [$value ,implode(', ', $other)], $message);
            $validator->setCustomMessages(array_merge($validator->getCustomMessages(), ['unique_in' => $message]));
    
            return false;
        });
    

    Thanks,

    K