[译]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 条评论
登录 后参与评论

相关文章

来自专栏代码世界

Python中的logger和handler到底是个什么鬼

最近的任务经常涉及到日志的记录,特意去又学了一遍logging的记录方法。跟java一样,python的日志记录也是比较繁琐的一件事,在写一条记录之前,要写好多...

3259
来自专栏安恒网络空间安全讲武堂

Amazing phpinfo()

前记 Xdebug 前记 定义 开启Xdebug 适用目标 实验效果 注意事项 session.upload_progress 定义 开启session.upl...

3526
来自专栏Java职业技术分享

分布式 | Dubbo 架构设计详解

Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合)。从服务模型的角度...

2270
来自专栏java达人

Kafka漫游记

我是一条消息,从我被生产者发布到topic的时候,我就清楚自己的使命:被消费者获取消费。但我一直很纳闷,把我直接推送给消费者不就行了,为什么一定要先推送到类似队...

2537
来自专栏Golang语言社区

【Go 语言社区】用Go实现的简易TCP通信框架--转

接触到GO之后,GO的网络支持非常令人喜欢。GO实现了在语法层面上可以保持同步语义,但是却又没有牺牲太多性能,底层一样使用了IO路径复用,比如在LINUX下用了...

39610
来自专栏web编程技术分享

一分钟学会在JavaWeb项目中配置数据源

3069
来自专栏一名合格java开发的自我修养

计算机操作系统之存储管理

内存的回收与分配,地址变换(程序中的逻辑地址与内存中的物理地址之间的转换),内存扩充(借助虚拟技术或覆盖技术从逻辑上扩充内存容量),内存保护(保证进入内存的各道...

651
来自专栏黑泽君的专栏

消除windows下的PyCharm中满屏的波浪线

1、PyCharm使用了较为 严格的PEP8 的检查规则,如果代码命名不规范,甚至多出的空格都会被 波浪线 标识出来,导致整个编辑器里 铺满了波浪线,右边的滚动...

4031
来自专栏小李刀刀的专栏

[译]Laravel 5.0 之 ValidatesWhenResolved

本文译自 Matt Stauffer 的系列文章. ---- 在创建 FormRequest 的时候, Taylor(译注: Laravel 框架的作者) 还编...

3625
来自专栏智能大石头

NewLife.Net——构建可靠的网络服务

老规矩,先上源码:https://github.com/nnhy/NewLife.Net.Tests

1140

扫码关注云+社区

领取腾讯云代金券