Home > php教程 > php手册 > body text

Using FormRequest in Laravel for form verification methods and problem summary, laravelformrequest

WBOY
Release: 2016-07-06 14:24:43
Original
954 people have browsed it

A summary of form verification methods and problems using FormRequest in Laravel, laravelformrequest

In `Laravel`, each request will be encapsulated into a `Request` object, `Form Request `Objects are custom `Request` classes that contain additional validation logic (and access control). This article analyzes the FormRequest exception handling process and proposes a custom way to handle FormRequest verification failure.

All examples are based on Laravel 5.1.39 (LTS)

The weather is nice today, let’s talk about form validation.

Do form validation in Controller

Some students write form verification logic in the Controller, such as this verification of user-submitted comment content:

<&#63;php

// ... 

use Validator;

class CommentController
{

  public function postStoreComment(Request $request)
  {
    $validator = Validator::make($request->all(), [
      'comment' => 'required', // 只是实例,就写个简单的规则,你的网站要是这么写欢迎在评论里贴网址
    ]);

    if ($validator->fails()) {
      return redirect()
        ->back()
        ->withErrors($validator)
        ->withInput();
    }
  }

Copy after login

If written like this, form validation and business logic will be squeezed together, there will be too much code in our Controller, and repeated validation rules will basically be copied and pasted.

We can use Form Request to encapsulate the form validation code, thereby streamlining the code logic in the Controller and focusing it 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 will be encapsulated as a Request object. The Form Request object is a custom Request class that contains additional verification logic (and access control).

How to use Form Request for form verification

Laravel provides Artisan commands to generate Form Request:

$ php artisan make:request StoreCommentRequest

So app/Http/Requests/StoreCommentRequest.php was generated, let us analyze the content:

<&#63;php

namespace App\Http\Requests;

use App\Http\Requests\Request; // 可以看到,这个基类是在我们的项目中的,这意味着我们可以修改它

class StoreCommentRequest extends Request
{
  /**
   * Determine if the user is authorized to make this request.
   *
   * @return bool
   */
  public function authorize() // 这个方法可以用来控制访问权限,例如禁止未付费用户评论…
  {
    return false; // 注意!这里默认是false,记得改成true
  }

  /**
   * Get the validation rules that apply to the request.
   *
   * @return array
   */
  public function rules() // 这个方法返回验证规则数组,也就是Validator的验证规则
  {
    return [
      //
    ];
  }
}

Copy after login

Then it’s easy. In addition to letting the authorize method return true, we also have to let the rules method return our verification rules:

<&#63;php

// ...

  public function rules()
  {
    return [

    ];
  }

// ...

Copy after login

Then modify our Controller:

<&#63;php

// ...

  // 之前:public function postStoreComment(Request $request)
  public function postStoreComment(\App\Http\Requests\StoreCommentRequest $request)
  {
    // ...
  }

// ...

Copy after login

In this way, Laravel will automatically call StoreCommentRequest for form verification.

Exception handling

If the form validation fails, Laravel will redirect to the previous page and write the error to the Session. If it is an AJAX request, a piece of JSON data with HTTP status 422 will be returned, similar to this:

{comment: ["The comment field is required."]}

I won’t go into details here on how to modify the prompt information. If anyone wants to see related tutorials, you can leave a message.

We mainly talk about how to customize error handling.

Generally speaking, errors in Laravel are exceptions, and we can all handle them uniformly in appExceptionshandler.php. Form Request did throw an IlluminateHttpExceptionHttpResponseException exception, but this exception was specially handled in the routing logic.

First let’s take a look at how Form Request is executed:

IlluminateValidationValidationServiceProvider:

<&#63;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(); // 看我看我看我

    $this->registerPresenceVerifier();

    $this->registerValidationFactory();
  }

  /**
   * Register the "ValidatesWhenResolved" container hook.
   *
   * @return void
   */
  protected function registerValidationResolverHook() // 对,就是我
  {
    // 这里可以看到对`ValidatesWhenResolved`的实现做了一个监听
    $this->app->afterResolving(function (ValidatesWhenResolved $resolved) {
      $resolved->validate(); // 然后调用了它的`validate`方法进行验证
    });
  }

// ...

Copy after login

You guessed it, Form Request implements this IlluminateContractsValidationValidatesWhenResolved interface:

<&#63;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; // 是你
use Illuminate\Contracts\Validation\Factory as ValidationFactory;

// 我们`app\Http\Requests\Request`便是继承于这个`FormRequest`类
class FormRequest extends Request implements ValidatesWhenResolved // 就是你
{
  use ValidatesWhenResolvedTrait; // 这个我们待会儿也要看看

  // ...

Copy after login

The validate method in the FormRequest base class is implemented by this IlluminateValidationValidatesWhenResolvedTrait:

IlluminateValidationValidatesWhenResolvedTrait:

<&#63;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() // 这里实现了`validate`方法
  {
    $instance = $this->getValidatorInstance(); // 这里获取了`Validator`实例

    if (! $this->passesAuthorization()) {
      $this->failedAuthorization(); // 这是调用了访问授权的失败处理
    } elseif (! $instance->passes()) {
      $this->failedValidation($instance); // 这里调用了验证失败的处理,我们主要看这里
    }
  }

  // ...

Copy after login

In validate, if the verification fails, $this->failedValidation() will be called, continue:

IlluminateFoundationHttpFormRequest:

<&#63;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->formatErrors($validator)
    ));
  }

Copy after login

Finally saw something unusual! But this exception was handled in another place:

IlluminateRoutingRoute:

<&#63;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 &#63;: 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) { // 就是这里
      return $e->getResponse(); // 这里直接返回了Response给客户端
    }
  }

  // ...

Copy after login

At this point, the whole idea is clear, but let’s take a look at how the Response in the HttpResponseException generated here is generated:

IlluminateFoundationHttpFormRequest:

<&#63;php

// ...

  // 132行:
  if ($this->ajax() || $this->wantsJson()) { // 对AJAX请求的处理
    return new JsonResponse($errors, 422);
  }

  return $this->redirector->to($this->getRedirectUrl()) // 对普通表单提交的处理
                  ->withInput($this->except($this->dontFlash))
                  ->withErrors($errors, $this->errorBag);

// ...

Copy after login

I believe you understand everything.

How to implement custom error handling, here are two ideas, both of which need to rewrite the failedValidation of appHttpRequestsRequest:

Throw a new exception, inherit the HttpResponseException exception, and reimplement the getResponse method. We can put this exception class under app/Exceptions/ for easy management, and error returns are still handed over to Laravel;

Throws a custom exception and handles it in appExceptionshandler.

The specific implementation will not be written here (refer to the error handling section in the Laravel documentation, Chinese document portal). If you have other methods or ideas, you can communicate with me in the comments.

Supplement

If your Controller uses the validate method of the IlluminateFoundationValidationValidatesRequests Trait for verification, similarly, if the verification fails here, an IlluminateHttpExceptionHttpResponseException exception will be thrown. You can refer to the above solution for processing.

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Recommendations
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template