2

I am trying to override the doReplacements method in Illuminate\Validation\Validator. When I extend the native Validator and Request classes, I get this error:

ReflectionException in Route.php line 270:

Class App\Http\Requests\FooRequest does not exist

This is what I did:

  1. Extend native Illuminate\Validation\Validator:

    class MyCustomValidator extends Validator {
    
        protected function doReplacements($message, $attribute, $rule, $parameters) {
            //override this method
        }
    
    }
    
  2. Use MyCustomValidator in an abstract extension of native App\Http\Requests\Request:

    abstract class MyCustomRequest extends Request {
    
        //Override native method by injecting the extending validator
        protected function formatErrors( MyCustomValidator $validator )
        {
            return $validator->getMessageBag()->toArray();
        }
    }
    
  3. Extend MyCustomRequest with concrete class:

    class FooRequest extends MyCustomRequest
    {
    
        public function authorize()
        {
            return true;
        }
    
    
        public function rules()
        {
            return [
                // rules go here
            ];
        }
    }
    
  4. Use the FooRequest in a controller method:

    public function store(FooRequest $request) {
        //use the request and persist
    }
    


I am guessing I am lacking a required facade, provider, or container binding. I'm still learning these topics and don't understand them well enough to know a good next step.

References:

  • Custom validator in Laravel 5 - I followed the answer, but still got the same error. I want to know if this is is even remotely related to my problem before troubleshooting what I tried here.

  • Extending Custom Validation-Class - Problem looks similar, answer suggests using Validator::extend, which I know can be done in AppServiceProvider, but ideally my code should be in its own vendor package. Again, not sure if relevant.

Community
  • 1
  • 1
brietsparks
  • 4,776
  • 8
  • 35
  • 69

2 Answers2

2

I had the same problem and this is what I did.

First, create a class and name it CustomValidatorServiceProvider or anything you want. Inside CustomValidatorServiceProvider add the following lines.

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Event;
use Illuminate\Validation\ValidationServiceProvider as ServiceProvider;
use App\Services\Validator\Factory;

class CustomValidatorServiceProvider extends ServiceProvider
{

    /**
     * Register the validation factory.
     *
     * @return void
     */
    protected function registerValidationFactory()
    {
        $this->app->singleton('validator', function ($app) {
            $validator = new Factory($app['translator'], $app);

            // The validation presence verifier is responsible for determining the existence
            // of values in a given data collection, typically a relational database or
            // other persistent data stores. And it is used to check for uniqueness.
            if (isset($app['db']) && isset($app['validation.presence'])) {
                $validator->setPresenceVerifier($app['validation.presence']);
            }

            return $validator;
        });
    }

}

If you will notice I added my own Validator\Factory and imported it. Inside of Validator\Factory I have the following codes.

<?php

namespace App\Services\Validator;

use Illuminate\Validation\Factory as ParentFactory;

class Factory extends ParentFactory
{

    /**
     * Resolve a new Validator instance.
     *
     * @param  array  $data
     * @param  array  $rules
     * @param  array  $messages
     * @param  array  $customAttributes
     * @return \Illuminate\Validation\Validator
     */
    protected function resolve(array $data, array $rules, array $messages, array $customAttributes)
    {
        if (is_null($this->resolver)) {
            return new Validator($this->translator, $data, $rules, $messages, $customAttributes);
        }

        return call_user_func($this->resolver, $this->translator, $data, $rules, $messages, $customAttributes);
    }
}

Inside the same directory where Validator\Factory resides, I added also my custom Validator Class which will be the class that extends the Validator Class of framework. It contains the following codes.

<?php

namespace App\Services\Validator;

use Illuminate\Validation\Validator as ParentValidator;
use Illuminate\Support\Str;

class Validator extends ParentValidator
{

    /**
     * Replace all place-holders for the greater_than_equal rule.
     *
     * @param  string  $message
     * @param  string  $attribute
     * @param  string  $rule
     * @param  array   $parameters
     * @return string
     */
    protected function replaceGreaterThanEqual($message, $attribute, $rule, $parameters)
    {
        $replacers[0] = str_replace('_', ' ', Str::snake($parameters[0]));
        $replacers[1] = $attribute;
        return str_replace([':other', ':attribute'], $replacers, $message);
    }

    /**
     * Replace all place-holders for the after_or_equal rule.
     *
     * @param  string  $message
     * @param  string  $attribute
     * @param  string  $rule
     * @param  array   $parameters
     * @return string
     */
    protected function replaceAfterOrEqual($message, $attribute, $rule, $parameters)
    {
        return $this->replaceGreaterThanEqual($message, $attribute, $rule, $parameters);
    }
}

And lastly, we should add the Service Provider that we created in config/app.php under providers array.

App\Providers\CustomValidatorServiceProvider::class,

And you can already remove or comment out the ValidationServiceProvider

Illuminate\Validation\ValidationServiceProvider::class,
-1

What you can do is add validator rule into your Request class for example this way:

public function validator(\Illuminate\Contracts\Validation\Factory $factory)
{
    $this->addExtraRules($factory);

    return $factory->make(
        $this->all(), $this->container->call([$this, 'rules']),
        $this->messages(), $this->attributes()
    );
}

and now you need to implement addExtraRules method for example:

protected function addExtraRules(\Illuminate\Contracts\Validation\Factory $validator)
{
    $validator->extendImplicit('equals_2',
        function ($attribute, $value, $parameters, $validator) {
           return $value == 2;
        });
}

And about this errors: App\Http\Requests\FooRequest, make sure you have defined namespace in FooRequest class file this way:

namespace App\Http\Requests;
Marcin Nabiałek
  • 109,655
  • 42
  • 258
  • 291