专栏首页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 发布, 海量新特性!!

    译注: 期待 Laravel 5.0 已经很久很久了, 之前跳票说要到今年一月份发布. 从一月份就一直在刷新官网和博客, 始终没有更新的消息, 前几天终于看到官...

    小李刀刀
  • [译]Laravel 5.0 之目录结构与命名空间

    本文译自 Matt Stauffer 的系列文章. ---- Laravel 的主版本号之所以从 4 升到 5. 一个很重要的原因是目录结构的改变. 这个改变实...

    小李刀刀
  • Laravel 开发 RESTful API 的一些心得

    最近用 Laravel 写了一段时间的 API,总结一下自己的心得吧。 Start API开发我们可以看到,有些网站用token验证身份,有些用OAuth2.0...

    前端教程
  • laravel与thinkphp之间的区别与优缺点

    在Laravel框架里,使用return view()来渲染模版;而ThinkPHP里则使用了$this->display()的方式渲染模版。

    码农编程进阶笔记
  • Laravel和Thinkphp有什么区别,哪个框架好用

    Laravel和Thinkphp这两个php框架对于php程序员都不陌生,新手可能对Thinkphp比较熟,也是国内比较出名的开源框架,更高级的Laravel一...

    Lanson
  • element-ui之Form表单验证--自定义方法验证【详细】

    element ui 验证–自定义方法验证-两种验证写法,方法很简单,主要是自定义方法的时候,方法的位置有些新手还掌握不清,这里详细列举一下。

    用户2323866
  • laravel-admin form表单中,同时验证两个或多个唯一值

    最近在使用laravel-admin,记录一下用laravel-admin时遇到的问题

    用户4973967
  • 在 Laravel 控制器中进行表单请求字段验证

    在 Web 应用中,用户提交的数据往往是不可预测的,因此一个非常常见的需求是对用户提交的表单请求进行验证,以确保用户输入的是我们所期望的数据格式。很多 Web ...

    学院君
  • laravel初次学习总结及一些细节

    刚开始一周多一点的时间先把laravel的开发文档看了一遍,,感觉刚开始接触时的感觉laravel的目录与thinkphp又不一样,它们的渲染模板的方式也不一样...

    lin_zone
  • php写app用的框架整理

    TP框架是一共快速兼容简单的轻量级国产PHP开发框架,使用面向对象的结构和MVC模式进行开发。它可以支持Windows、Linux等服务器,并且支持MySql、...

    砸漏
  • Laravel VerifyCsrfToken 报错解决

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011415782/article/de...

    泥豆芽儿 MT
  • 通过 Laravel 表单请求类实现字段验证和错误提示

    在上一篇教程中,我们已经演示了如何在控制器方法中对表单请求字段进行验证,并且提到如果请求字段很多很复杂,都写到控制器方法里面会导致控制器臃肿,从单一职责原则来说...

    学院君
  • [译]Laravel 5.0 之事件调度程序 (定时任务)

    本文译自 Matt Stauffer 的系列文章. ---- 关于 Laravel 5.0 的事件调度程序(可以理解为定时任务),Eric Barnes 有一篇...

    小李刀刀
  • [译]Laravel 5.0 之命令及处理程序

    本文译自 Matt Stauffer 的系列文章. ---- 本文中涉及的新功能都是关于 Commands 的,这些特性在 Laravel 旧版本中已经有了,但...

    小李刀刀
  • 通过 Laravel 创建一个 Vue 单页面应用(六)

    我们将完成基本 CURD 的最后一部分:创建新用户。您已经拥有了我们之前讨论过的主题中所需要的所有工具,因此可以尝试创建用户并将本文与您的工作进行比较。

    hedeqiang
  • 浅谈laravel框架与thinkPHP框架的区别

    2、在Laravel框架里,由于其考虑到了跨站请求伪造, 所以如果使用form表单以post方式进行传值时,如果不再form表单中加入{{csrf_field(...

    砸漏
  • 3分钟短文:用Laravel发一封“漂洋过海”的电子邮件

    电子邮件同时带来了垃圾信息的侵扰,随着国内社交类APP的普及,电子邮箱渐渐地趋于专业化。

    程序员小助手
  • [译]Laravel 5.0 之运行环境及环境变量

    本文译自 Matt Stauffer 的系列文章. ---- 如果你关注我的博客有段时间了,那你应该曾经见过我在 Laravel 环境检测问题上的各种尝试,特别...

    小李刀刀
  • 3分钟短文:Laravel Form,让你不再写 HTML 的好“库”

    作为后端工程师的你,是不是面对一堆JS,CSS感觉无比抓狂。如果能摆脱大量的冗余的HTML代码块,

    程序员小助手

扫码关注云+社区

领取腾讯云代金券