[译]Laravel 5.0 之 ValidatesWhenResolved

本文译自 Matt Stauffer系列文章.


在创建 FormRequest 的时候, Taylor(译注: Laravel 框架的作者) 还编写了一个接口 (ValidatesWhenResolved) 和一个 trait (ValidatesWhenResolvedTrait), 都是用于对控制器方法进行校验的. 这种校验会在IOC 容器对该方法的依赖项解析成功时调用.

老实说, 我目前还没有写出一个在 FormRequests 类之外的应用场景来使用这两个东西的实例. 但我还是想写一篇文档来介绍它们, 希望有比我更聪明的人来找出它们在实际项目中可能的应用场景.

所以, 如果你读过我的上一篇文章, 你已经了解了 FormRequest 对象, 通过 IOC 的依赖注入机制注入到方法, 可以取消相关方法的执行. 假如表单提交的数据不能通过校验, 与该表单对应的 POST route 会被负责校验它的 FormRequest 类取消执行.

这带来的一个结果就是: “触发 IOC 容器的 FormRequest 调用校验方法” 这个操作可以被分离为一个单独的接口, 名为 ValidatesWhenResolved. 借助这一点, 我们也可以创建类似 FormRequest 的类, 在执行控制器方法 (理论上非控制器也可以) 之前对请求进行拦截, 并决定它能否通过校验.

说明: 如果一个请求校验失败的话, 路由或方法其实没有真正取消. FormRequest 只是抛出了一个 HTTP 异常, 该异常随后以 JSON 格式返回, 或者被重定向到处理异常的页面. 理论上来说, 你不实现这个接口, 而只是简单地在控制器的构造函数中进行校验并抛出异常也是一样的. 但是借助这个接口, 我们可以保持代码清洁, 并且可以在一个命名的方法中来执行校验.

接口

在本文写作的时候, 该接口的签名是这样的:

namespace Illuminate\Contracts\Validation;

use Illuminate\Contracts\Container\Container;

interface ValidatesWhenResolved {

    /**
     * 对指定的类实例进行校验
     *
     * @return void
     */
    public function validate();

}

通过该签名可知, 实现这个接口只需要实现一个方法 validate(). 事实上, 对于实现这个方法的类, 我们只需要知道一点, 就是当 IOC 容器解析到它的时候, 会调用 validate() 这个方法. 接下来我们就来创建一个并非 FormRequest 扩展类但是却实现了这个接口的类:

在控制器中不使用 FormRequest 进行校验

// app/Http/Controllers/ValidatedController.php

namespace App\Http\Controllers;

use App\Random\RandomAccess;
use Illuminate\Routing\Controller;
use Response;

class ValidatedController extends Controller
{
    public function random(RandomAccess $ram)
    {
        return Response::make('You made it!');
    }
}

上面是一个简单的控制器. 有了路由之后, 我们来创建一个不继承 FormRequest 的验证类:

// app/Random/RandomAccess.php
namespace App\Random;

use Exception;
use Illuminate\Contracts\Validation\ValidatesWhenResolved;
use Illuminate\Http\Request;

class RandomAccess implements ValidatesWhenResolved
{
    public function __construct(Request $request)
    {
        $this->request = $request;
    }

    public function validate()
    {
        // Test for an even vs. odd remote port
        if (($this->request->server->get('REMOTE_PORT') / 2) % 2 > 0)
        {
            throw new Exception("WE DON'T LIKE ODD REMOTE PORTS");
        }
    }
}

现在控制器方法就被拦截并且随机抛出异常 (取决于请求访问的端口是奇数还是偶数, 这恐怕是有史以来最没实用价值的一个例子了, 哈哈).

如你所见, 这里没有用到什么神奇的东西, validate() 方法是否返回 true 或者 false 并不重要. 你当然可以通过 ValidatesWhenResolvedTrait 这个 trait 来实现 FormRequest 中的 failedValidation() 的部分流程, 而在上面的例子中, 只需要抛出异常就可以了.

在控制器之外使用 FormRequest 风格的验证

在控制器之外也可以使用这些手段, 比如在 FormRequest 风格的验证中使用 ValidatesWhenResolvedTrait. 但我暂时没有找到合适的用例, 所以我先简单地略过这部分. 你可以自己尝试… 但是我想不出有什么理由值得这样去做, 呵呵.

真实案例

你肯定不会像上面的例子里那样去随机抛出异常. 本文探讨的这些新特性最终看起来有点像以前的 route filters. 但我还是怀疑它们在实际中能有多少应用场景. 不管怎么说, 要是你想给你的控制器注入什么东西的话, 或者可以让它实现 ValidatesWhenResolved 接口或者使用 ValidatesWhenResolvedTrait, 这样它就能通过注入进行自动校验, 不用额外去调用一个校验方法了.

结束语

你可以认为这篇文章的目的就是为了钓鱼, 看看能否找到对这个新特性的实际应用场景. 假如你有什么想法, 可以通过 Twitter 与 @stauffermatt 进行讨论.

               

[译]Laravel 5.0 之 ValidatesWhenResolved》上有1条评论

  1. Pingback引用通告: Laravel 5.0 之 Middleware (Filter-Style) - PHP - 裁纸刀下

评论已关闭。