In ' Laravel ', each request is encapsulated as a ' request ' object, and the ' Form request ' object is a custom ' request ' class that contains additional validation logic (and access control). In this paper, the processing process of formrequest anomaly is analyzed and the idea of formrequest verification failure is proposed.
All samples are based on Laravel 5.1.39 (LTS)
It's a nice day today, let's talk about form validation.
Make form verification in controller
Some students write form validation logic in controller, such as the validation of user submissions:
<?php
//...
Use Validator;
Class Commentcontroller
{public
function poststorecomment (Request $request)
{
$validator = Validator::make ($request->all (), [
' comment ' => ' required ',//is just an example, write a simple rule, your site if so write welcome in the comments posted URL
]);
if ($validator->fails ()) {return
redirect ()
->back ()
->witherrors ($validator)
-> Withinput ();
}
In this case, form validation and business logic are crammed together, we have too much code in our controller, and duplicate validation rules are basically copy and paste.
We can use form request to encapsulate form validation code, thus streamlining the code logic in controller to focus on the business. The independent form validation logic can even be reused in other requests, such as modifying comments.
What is form Request
In Laravel, each request is encapsulated as a requests object, and the Form request object is a custom request class that contains additional validation logic (and access control).
How to use form request to do form validation
Laravel provides the artisan command to generate form request:
<code>$ PHP Artisan make:request storecommentrequest</code>
So it generates the app/http/requests/storecommentrequest.php, let's analyze the content:
<?php
namespace app\http\requests;
Use App\http\requests\request; As you can see, this base class is in our project, which means we can modify it
class Storecommentrequest extends Request
{
/**
* determine if the The user is authorized to make this request.
*
* @return bool
/Public Function authorize ()//This method can be used to control access rights, such as prohibiting unpaid user comments ...
{return
false;//Note! This defaults to False, and is remembered to be true
}
/** * Get the validation rules which apply to the
request.
*
* @return Array
/Public Function rules ()//This method returns an array of validation rules, that is, the validator validation rule
{return
[
//
];
}
}
So it's easy to let the rules method return our validation rules in addition to having the authorize method return true:
<?php
//...
Public function rules ()
{return
[
];
}
// ...
And then revise our controller:
<?php
//...
Before: Public function poststorecomment (Request $request) public
function Poststorecomment (\app\http\requests\ Storecommentrequest $request)
{
//...
}
// ...
This laravel automatically invokes the Storecommentrequest for form validation.
Exception handling
If the form validation fails, Laravel redirects to the previous page and writes the error to the session and, if it is an AJAX request, returns a section of JSON data with an HTTP status of 422, similar to this:
<code>{comment: ["The comment field is required."]} </code>
Here is not to elaborate on how to modify the information, if someone want to see the relevant tutorials, you can leave a message.
We mainly talk about how to customize error handling.
In general, errors in Laravel are exceptions (Exception), and we can all handle them uniformly in app\exceptions\handler.php. The Form request does throw a illuminate\http\exception\httpresponseexception exception, but the exception is handled specifically in the routing logic.
First, let's look at how the form request was executed:
Illuminate\validation\validationserviceprovider:
<?php
namespace Illuminate\validation;
Use Illuminate\support\serviceprovider;
Use illuminate\contracts\validation\validateswhenresolved;
Class Validationserviceprovider extends serviceprovider
{
/**
* Register the service provider.
*
* @return void
*
/Public Function register ()
{
$this->registervalidationresolverhook ( ); Look at me I see I
$this->registerpresenceverifier ();
$this->registervalidationfactory ();
}
/**
* Register the "validateswhenresolved" container hook.
*
* @return void
/
protected function Registervalidationresolverhook ()//Yes, that's me.
Here you can see the implementation of ' validateswhenresolved ' to do a listening
$this->app->afterresolving (function validateswhenresolved $ Resolved) {
$resolved->validate ();//Then called its ' validate ' method for validation
});
// ...
You guessed it, the Form request implemented this illuminate\contracts\validation\validateswhenresolved interface:
<?php
namespace Illuminate\foundation\http;
Use Illuminate\http\request;
Use Illuminate\http\response;
Use Illuminate\http\jsonresponse;
Use Illuminate\routing\redirector;
Use Illuminate\container\container;
Use Illuminate\contracts\validation\validator;
Use illuminate\http\exception\httpresponseexception;
Use illuminate\validation\validateswhenresolvedtrait;
Use illuminate\contracts\validation\validateswhenresolved; Is you use
illuminate\contracts\validation\factory as validationfactory;
We ' App\http\requests\request ' is inherited from this ' Formrequest ' class
Formrequest extends Request implements Validateswhenresolved//Is you
{use
validateswhenresolvedtrait;//This we'll have to see later
.
The Validate method in the Formrequest base class is implemented by this illuminate\validation\validateswhenresolvedtrait:
Illuminate\validation\validateswhenresolvedtrait:
<?php
namespace Illuminate\validation;
Use illuminate\contracts\validation\validationexception;
Use illuminate\contracts\validation\unauthorizedexception;
/**
* Provides default implementation of validateswhenresolved contract.
* *
trait validateswhenresolvedtrait
{
/**
* Validate the class instance.
*
* @return void
/Public Function validate ()///Here implements the ' validate ' method
{
$instance = $this-> Getvalidatorinstance (); This gets the ' Validator ' instance
if (! $this->passesauthorization ()) {
$this->failedauthorization ();// This is the failed process that invoked the access authorization
} elseif (! $instance->passes ()) {
$this->failedvalidation ($instance); Here we call the validation failed processing, we mainly look here
}
//...
In validate, if the validation fails, the $this->failedvalidation () is invoked and continues:
Illuminate\foundation\http\formrequest:
<?php
//...
/**
* Handle a failed validation attempt.
* *
@param \illuminate\contracts\validation\validator $validator
* @return mixed
/
protected function failedvalidation (Validator $validator)
{
throw new Httpresponseexception ($this->response (// This throws out the legendary anomaly
$this->formaterrors ($validator))
);
Finally see the anomaly! But this anomaly was dealt with in another place:
Illuminate\routing\route:
<?php
//...
/**
* Run the route action and return the response.
* *
@param \illuminate\http\request $request
* @return Mixed * * Public
function run (Request $request) c9/>{
$this->container = $this->container?: New Container;
try {
if (! is_string ($this->action[' uses ')) {return
$this->runcallable ($request);
}
if ($this->customdispatcherisbound ()) {return
$this->runwithcustomdispatcher ($request);
}
return $this->runcontroller ($request);
} catch (Httpresponseexception $e) {//This is where
return $e->getresponse ();//Here directly returns response to the client
}
}
// ...
So far, the whole idea is clear, but let's see how the response in the httpresponseexception exception generated here:
Illuminate\foundation\http\formrequest:
<?php
//...
132 Lines:
if ($this->ajax () | | $this->wantsjson ()) {//Processing of AJAX requests return to
new Jsonresponse ($errors, 422); c5/>}
return $this->redirector->to ($this->getredirecturl ())//processing of normal form submissions
->withinput ($this- >except ($this->dontflash))
->witherrors ($errors, $this->errorbag);
// ...
I'm sure you've read it.
How to implement custom error handling, here are two ideas that need to rewrite App\http\requests\request's failedvalidation:
Throws a new exception, inherits the Httpresponseexception exception, the realization GetResponse method, this exception class we may put under the app/exceptions/to be easy to manage, the error return still gives Laravel;
Throws a custom exception, which is handled in the App\exceptions\handler.
Concrete implementation Here is not written (refer to the Error handling section of the Laravel documentation, Chinese document portal), if you have other methods or ideas can be in the comments and communicate with me.
Add
If your controller is validated using the Validate method of illuminate\foundation\validation\validatesrequests this trait, the same Validation failures here also throw illuminate\http\exception\httpresponseexception exceptions, which can be referred to above solutions for processing.