In Laravel, FormRequest is used for Form Verification and problem summary. laravelformrequest
In 'laravel', each Request is encapsulated as a 'request' object. The 'form request' object contains the additional authentication logic (and access permission control) the custom 'request' class. This article analyzes the handling process of FormRequest exceptions and proposes the idea of failing to customize FormRequest verification.
All examples are based on Laravel 5.1.39 (LTS)
Today's weather is good. Let's talk about form verification.
Form Verification in Controller
Some people write the Form Verification logic in the Controller. For example, the verification of the comments submitted to the user:
<? Php //... use Validator; class CommentController {public function postStoreComment (Request $ request) {$ validator = Validator: make ($ request-> all (), ['comment' => 'required', // For example only, write a simple rule. If your website is so written, you are welcome to post a website in the comment]); if ($ validator-> fails () {return redirect ()-> back ()-> withErrors ($ validator)-> withInput ();}}
In this case, the Form Verification and business logic are crowded together, so there will be too much code in our Controller, and Duplicate verification rules are basically copied and pasted.
We can use Form Request to encapsulate Form Verification code, so as to streamline the code logic in the Controller and focus on the business. The independent form verification logic can even be reused in other requests, such as modifying comments.
What is Form Request?
In Laravel, each Request is encapsulated as a Request object. The Form Request object is a custom Request class that contains the additional authentication logic (and access permission control.
How to use Form Request for Form Verification
Laravel provides the Artisan command for generating Form Request:
<Code> $ php artisan make: request StoreCommentRequest </code>
So app/Http/Requests/StoreCommentRequest. php is generated. Let's analyze the content:
<? Phpnamespace App \ Http \ Requests; use App \ Http \ Requests \ Request; // you can see that this base class is in our project, this means we can modify the class StoreCommentRequest extends Request {/*** Determine if the user is authorized to make this request. ** @ return bool */public function authorize () // This method can be used to control access permissions, such as prohibiting comments from paying users... {Return false; // note! The default value here is false. Remember to change it to true}/*** Get the validation rules that apply to the request. ** @ return array */public function rules () // This method returns an array of verification rules, that is, the validation rules of Validator {return [//];}
In addition to making the authorize method return true, it is easy to let the rules method return our verification rules:
<?php// ... public function rules() { return [ ]; }// ...
Then modify our Controller:
<? Php //... // before: public function postStoreComment (Request $ request) public function postStoreComment (\ App \ Http \ Requests \ StoreCommentRequest $ request ){//...} //...
Laravel automatically calls StoreCommentRequest for form verification.
Exception Handling
If form verification fails, Laravel redirects to the previous page and writes the error to the Session. If it is an AJAX request, a JSON data with an HTTP status of 422 is returned, similar to the following:
<Code> {comment: ["The comment field is required."]} </code>
I will not elaborate on how to modify the prompt information here. If you want to see the relevant tutorial, you can leave a message.
We mainly talk about how to customize error handling.
Generally, errors in Laravel are all Exceptions. We can perform unified processing in app \ Exceptions \ handler. php. Form Request also throws an Illuminate \ Http \ Exception \ HttpResponseException Exception, but this Exception is specially handled in the routing logic.
First, let's see how Form Request is executed:
Illuminate \ Validation \ ValidationServiceProvider:
<? Phpnamespace 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 (); // you can view me and view my $ this-> registerPresenceVerifier (); $ this-> registerValidationFactory ();}/*** Register the "ValidatesWhenResolved" container hook. ** @ return void */protected function registerValidationResolverHook () // pair, here I can see a listener FOR THE IMPLEMENTATION OF 'validateswhenresolved' $ this-> app-> afterResolving (function (ValidatesWhenResolved $ resolved) {$ resolved-> validate (); // then calls its 'validate' Method for verification });}//...
By mistake, Form Request implements the 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; use Illuminate \ Contracts \ Validation \ Validator; use Illuminate \ Http \ Exception \ HttpResponseException; use Illuminate \ Validation \ ValidatesWhenResolvedTrait; use Illuminate \ Contracts \ Validation \ ValidatesWhenResolved; // you use Illuminate \ Contracts \ Validation \ Factory as ValidationFactory; // Our 'app \ Http \ Requests \ request' is inherited from this 'formrequest' class FormRequest extends Request implements ValidatesWhenResolved // you {use ValidatesWhenResolvedTrait; // We will check it later //...
The validate method in the FormRequest base class is implemented by the Illuminate \ Validation \ ValidatesWhenResolvedTrait:
Illuminate \ Validation \ ValidatesWhenResolvedTrait:
<? Phpnamespace Illuminate \ Validation; use Illuminate \ Contracts \ Validation \ ValidationException; use Illuminate \ Contracts \ Validation \ UnauthorizedException;/*** Provides default implementation of specified contract. */trait ValidatesWhenResolvedTrait {/*** Validate the class instance. ** @ return void */public function validate () // The 'validate' method {$ instance = $ this-> getValidatorInstanc is implemented here. E (); // here the 'validator' instance if (! $ This-> passesAuthorization () {$ this-> failedAuthorization (); // this is an error occurred while calling Access Authorization} elseif (! $ Instance-> passes () {$ this-> failedValidation ($ instance); // The Verification Failed process is called here. Let's take a look at it here }}//...
In validate, if the verification fails, $ this-> failedValidation () will be called to continue:
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 (// The legendary exception $ this-> formatErrors ($ validator) is thrown here )));}
Finally, an exception occurred! However, this exception is handled 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) {$ 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) {// here return $ e-> getResponse (); // Response is directly returned to the client }}//...
Now, the entire idea is clear, but let's take a look at how the Response in the HttpResponseException generated here is generated:
Illuminate \ Foundation \ Http \ FormRequest:
<? Php //... // Row 3: if ($ this-> ajax () | $ this-> wantsJson () {// return new JsonResponse ($ errors, 422);} return $ this-> redirector-> to ($ this-> getRedirectUrl ()) // process Normal Form submission-> withInput ($ this-> handle T ($ this-> dontFlash)-> withErrors ($ errors, $ this-> errorBag ); //...
I believe you have understood it.
Here we provide two ideas for how to implement custom error handling: rewrite failedValidation of app \ Http \ Requests \ Request:
Throw a new exception, inherit the HttpResponseException exception, and re-implement the getResponse method. This exception class can be easily managed under app/Exceptions/, and the error return is still handed over to Laravel;
Throw a custom exception and handle it in app \ Exceptions \ handler.
The specific implementation will not be written here (refer to the error handling section in the Laravel document and the Chinese Document portal). If you have other methods or ideas, you can share them with me in the comments.
Supplement
If your Controller uses the Trait validate method of Illuminate \ Foundation \ Validation \ ValidatesRequests for verification, the verification failure will also throw the Illuminate \ Http \ Exception \ HttpResponseException Exception, you can refer to the above solution for processing.