专栏首页PHP 开发[译]Laravel 5.0 之 表单验证类 (Form Requests)

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

本文译自 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 上直接联系原作者.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • [译]Laravel 5.0 之 Eloquent 属性转换

    本文译自 Matt Stauffer 的系列文章. ---- 之前完全忘了要把这个 Laravel 5 的系列博客写完,不过最近看到了一篇关于属性转换的简介 L...

    小李刀刀
  • [译]HTML验证的价值探讨

    [译]HTML验证的价值探讨 作者:Nicholas C. Zakas 原文:http://www.nczonline.net/blog/2010/08/17/...

    小李刀刀
  • dateDiff在Objective-C中的实现

    在学习iOS App开发中遇到需要计算时间差并格式化输出的需求,没有现成的方法,需要结合NSCalendar和NSDateComponents来实现。所以干脆把...

    小李刀刀
  • JavaScript函数式编程,真香之组合(二)

    组合是一种为软件的行为,进行清晰建模的一种简单、优雅而富于表现力的方式。通过组合小的、确定性的函数,来创建更大的软件组件和功能的过程,会生成更容易组织、理解、调...

    桃翁
  • 教你做一个异步的fis3插件

    本文作者:IMWeb 黄龙 原文出处:IMWeb社区 未经同意,禁止转载 不清楚fis3是什么的可以先看这个链接 http://fis.baidu.c...

    IMWeb前端团队
  • 教你做一个异步的fis3插件

    从fis的官方文档上看,fis 除了deploy 插件是支持异步的其它都不支持。但是有好多node包 都是异步,怎么才能让fis支持异步插件呢?

    IMWeb前端团队
  • go 生成随机字符串和获得定长字符串

    solate
  • Python之lambda函数

    匿名函数lambda:是指一类无需定义标识符(函数名)的函数或子程序。 lambda 函数可以接收任意多个参数 (包括可选参数) 并且返回单个表达式的值。

    py3study
  • JavaScript排序函数sort

    十月梦想
  • Git/SourceTree·查看单个文件提交记录

    陈满iOS

扫码关注云+社区

领取腾讯云代金券