Why is validate() method accessible via request()?

Viewed 3232

Quoting the Laravel documentation:

By default, Laravel's base controller class uses a ValidatesRequests trait which provides a convenient method to validate incoming HTTP request with a variety of powerful validation rules

It's true, reading the code, App\Http\Controllers\Controller actually uses ValidatesRequests trait. And ValidatesRequests has a validate method.

What is really strange for me is that everywhere else in the documentation, the validate method is called on $request object. And it works this way. I can validate a form with this code:

public function store()
{
    $attributes = request()->validate([
        'name' => 'required|string|max:255',
    ]);
    // ...
}

But I don't see any presence of a validate method on the Request class. Just a strange comment line at the beginning of the file:

/**
 * @method array validate(array $rules, array $messages = [], array $customAttributes = [])
 */

So there are two things:

  • I don't know what to trust in Laravel documentation.
  • And I don't understand how the validation works on the $request object.

And my actual question is:

Is the initial quote I pasted from the documentation still true if I use the validate method through $request object? If so, how does it works?

2 Answers

Well, validate method is there, but it's not in FormRequest directly but in ValidatesWhenResolvedTrait trait so it's usable without any problem in FormRequest so documentation is fine.

Let's look at the beginning of this trait:

trait ValidatesWhenResolvedTrait
{
    /**
     * Validate the class instance.
     *
     * @return void
     */
    public function validate()
    {
        $this->prepareForValidation();

        $instance = $this->getValidatorInstance();

        if (! $this->passesAuthorization()) {
            $this->failedAuthorization();
        } elseif (! $instance->passes()) {
            $this->failedValidation($instance);
        }
    }

so when you are running in controller:

request()->validate

you are running the method from trait and ValidatesRequests has nothing in common with this.

Alternatively if you would like to use "Controller way" validation you could do:

$this->validate(request(), [
        'name' => 'required|string|max:255',
    ]);

and now you would be using validate method from ValidatesRequests requests.

As you see there are multiple ways of running validation in Laravel. I personally use only Form Request validation instead.

Related