Why is validate() method accessible via request()?
Asked Answered
A

2

14

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?

Assured answered 16/11, 2017 at 16:13 Comment(0)
F
8

That "strange comment" was removed a couple days ago.

I believe Request gets its validate function from the Request::macro('validate', ...) call in FoundationServiceProvider.php. See this article for more on macros.

Farny answered 16/11, 2017 at 16:21 Comment(7)
Ok thanks! So do you think the ValidatesRequests is useless in this case, and the initial quote of Laravel is irrelevant now? (because the way the whole documentation is written after that initial quote does not take into account that there is a ValidatesRequests trait)Assured
@Assured No, it's not useless. They are for different situations. $this->validate() on the controller and request()->validate() are not the same thing.Farny
Oops sorry, I did not mean "useless" (anyway, I wrote it). I wanted to ask: "So do you think the ValidatesRequests is not in use in this case [...]?". Anyway, thanks!Assured
In that case, the answer would be "right, ValidatesRequests has no relationship to a request()->validate() call - it's not involved".Farny
Does the drive-by downvoter wish to explain what I've gotten wrong?Farny
not me (I upvoted), sorry about that, I actually think your answer is good!Assured
Damn this was frustrating me. Thanks. I'm just getting started with Laravel and already I'm starting to hate all the automagic going on here as soon as I try to dig a little deeper into it. PhpStorm was clueless about where this $request->validate() was coming from. These traits are out of control, starting to feel like glorified GOTO statements.Pica
T
2

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.

Tellus answered 16/11, 2017 at 16:31 Comment(2)
Thanks! I'm a bit lost. Are you sure this validate method is the one which is called in the example I provided when we call request()->validate(...)? I don't see any params in this one and it seems it's not for the same purpose... (but maybe I'm wrong, sometimes I'm lost with the "magic" side of Laravel).Assured
I've updated my answer a while ago. when you run request()->validate() then you run the method I showed you at the beginning of my answer and if you are running $this->validate(request() you are running method from ValidateRequests trait for controllersBonhomie

© 2022 - 2024 — McMap. All rights reserved.