欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

译]Laravel 5.0 之 表单验证类 (Form Requests)

shiping1 的头像
  http://www.ofcss.com/2015/02/10/laravel-5-0-form-requests.html

让人头痛的表单验证

本文译自 Matt Stauffer 的 系列文章 .

只要你曾经在使用 Laravel 框架的过程中试图找到有关用户输入验证的最佳实践, 你就应该了解这是一个争论最多并且几乎没有达成共识的话题. 我们可以在控制器中进行验证, 可以在单独的一个服务层进行验证, 可以在模型中进行验证, 当然还可以在 Javascript 中进行验证 (这只是一个玩笑, 谁都知道不能只依赖于客户端的验证). 但是, 哪一种做法才是最佳的呢?

Laravel 5.0 新引入的表单请求 (Form Request) 特性提供了集规范性 (差不多就是 "最佳实践" 的意思) 和便捷性 (这是比之前任何一种选择都更强大也更便捷的方式) 于一体的, 在 Laravel 中执行数据检查和验证的新手段.

 

说明: 本文中使用新的 view() 辅助方法代替了旧版本中的 View::make() .

 

Form Requests 使表单验证不再让人头痛

Laravel 5.0 带来了 Form Requests, 这是一种特殊的类型, 用于在提交表单时进行数据的检查和验证. 每个 Form Request 类至少包含一个 rules() 方法, 这个方法返回一组验证规则. 除此之外还必须包含一个 authorize() 方法, 该方法返回一个布尔值, 代表是否允许用户执行本次请求.

Laravel 会在解析 POST 路由之前自动把用户输入的信息传递给相应的表单请求, 因此我们的所有验证逻辑都可以移到独立于控制器和模型之外的 FormRequest 对象中.

开始实践: 快速创建一个 Laravel 5.0 项目

如果你还没有创建好的 Laravel 5.0 项目, 用下面的命令创建一个:

$ composer create-project laravel/laravel myProject dev-develop --prefer-dist

1. 添加路由

// app/Http/routes.php
Route::get('/', 'FriendsController@getAddFriend');
Route::post('/', 'FriendsController@postAddFriend');

2. 创建控制器

//app/Http/Controllers/FriendsController:
namespace App\Http\Controllers;
use App\Http\Requests\FriendFormRequest;
use Illuminate\Routing\Controller;
use Response;
use View;
class FriendsController extends Controller
{
  public function getAddFriend()
  {
    return view('friends.add');
  }
  public function postAddFriend(FriendFormRequest $request)
  {
    return Response::make('Friend added!');
  }
}

3. 创建视图

<html><body>
  @foreach ($errors->all() as $error)
    <p class="error">{{ $error }}</p>
  @endforeach
  <form method="post">
    <label>First name</label><input name="first_name"><br>
    <label>Email address</label><input name="email_address"><br>
    <input type="submit">
  </form>
</body></html>

4. 创建 FormRequest

// app/http/requests/FriendFormRequest.php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Response;
class FriendFormRequest extends FormRequest
{
  public function rules()
  {
    return [
      'first_name' => 'required',
      'email_address' => 'required|email'
    ];
  }
  public function authorize()
  {
    // 只允许登陆用户
    // 返回 \Auth::check();
    // 允许所有用户登入
    return true;
  }
  // 可选: 重写基类方法
  public function forbiddenResponse()
  {
    // 这个是可选的, 当认证失败时返回自定义的 HTTP 响应. 
    // (框架默认的行为是带着错误信息返回到起始页面)
    // 可以返回 Response 实例, 视图, 重定向或其它信息
    return Response::make('Permission denied foo!', 403);
  }
  // 可选: 重写基类方法
  public function response()
  {
    // 如果需要自定义在验证失败时的行为, 可以重写这个方法
    // 了解有关基类中这个方法的默认行为,可以查看:
    // https://github.com/laravel/framework/blob/master/src/Illuminate/Foundation/Http/FormRequest.php
  }
}

接下来, 用 php artisan serve 或者你自己喜欢的方式启动服务器. 提交表单, 你可以看到我们并没有往控制器中添加任何一行验证逻辑, 但是验证规则已经生效了.

其它用例

如果对 "新增" 和 "编辑" 有不同的规则, 或者根据不同的输入进行不同的验证, 要怎么办呢? 这里有几个可以参考的例子, 虽然还不能确定这些就是 "最佳实践":

采用分开的 form requests

Laravel 并没有规定你不能对 "新增" 和 "编辑" 操作采用不同的 form request 类. 所以你可以创建一个包含所有规则的 FriendFormRequest 作为基类, 然后把它扩展为 addFriendFormRequest 和 editFriendFormRequest 两个子类, 每个子类都可以实现各自的默认行为.

采用条件判断逻辑

rules() 作为一个方法而不是属性, 带来的好处就是你可以在方法中添加判断逻辑:

...
class UserFormRequest extends FormRequest
{
  ...
  protected $rules = [	
    'email_address' => 'required',
    'password' => 'required|min:8',
  ];
  public function rules()
  {
    $rules = $this->rules;
    // 根据不同的情况, 添加不同的验证规则
    if ($someTestVariableShowingThisIsLoginInsteadOfSignup)
    {
      $rules['password'] = 'min:8';
    }
    return $rules;
  }
}

也可以在 authorize 方法中添加逻辑, 比如:

...
class FriendFormRequest extends FormRequest
{
  ...
  public function authorize()
  {
    if ( ! Auth::check() )
    {
      return false;
    }
    $thingBeingEdited = Thing::find(Input::get('thingId'));
    // 如果是编辑操作, 或者当前用户不是对象创建者
    if ( ! $thingBeingEdited || $thingBeingEdited->owner != Auth::id()) {
      return false;
    }
    return true;
  }
}

自定义校验

除了上面的方式, 如果需要对验证逻辑进行更深入的控制, 可以重写提供校验对象实例的方法. 下面是一个简单的实例, 后续会专门写一篇文章来解释:

...
class FriendFormRequest extends FormRequest
{
  public function validator(ValidationService $service)
  {
    $validator = $service->getValidator($this->input());
    // 可选: 通过新的 ->after() 方法来进行自定义
    $validator->after(function() use ($validator)) {
      // 在这里可以做更多更深入的校验
      $validator->errors()->add('field', 'new error);
    }
  }
}

ValidatesWhenResolved 接口

后续还会有一篇有关 ValidatesWhenResolved 接口的文章, 不过那篇文章重点讨论的是对方法/路由等的校验. IOC 何时提供什么东西, 这个在 Laravel 5.0 版已经分离出一个单独的接口. 官方文档:https://github.com/illuminate/contracts/blob/master/Validation/ValidatesWhenResolved.php

其它可自定义的参数:

$redirect : 校验失败时要重定向到的 URI. $redirectRoute : 校验失败时要重定向到的路由. $redirectAction : 校验失败时要重定向到的方法. $dontFlash : 重定向时不要传递的输入项的键 (默认值: ['password', 'password_confirmation']).

写在最后

通过文本可以看到, Form Requests 对于简化表单请求的数据校验是非常强大和方便的. 如果你阅读本文觉得还不够, 可以观看关于 Form Request 的 这个视频 .

本文写作时, Laravel 5.0 还未正式发布, 因此上述内容最终可能还会有修改, 或者作者遗漏了某些东西. 如果你有建议或者对文章内容的修正, 可以在 给译者发邮件 或者(在 Twitter 上直接联系原作者)[http://twitter.com/stauffermatt].

来自  http://www.tuicool.com/articles/3IVvYva
普通分类: