深入理解 Laravel 管道

这是一篇译文,原文 Understanding Laravel Pipelines

基本上,你可以使用 laravel 管道(pipelines)基于链式操作将对象传入多个类中执行任何类型的任务,并在所有「任务」执行完成后一次性返回最终结果。

你可以从 Laravel pipelines 获取更多相关知识。

有关管理工作原理的最常见的示例是在框架本身的组件中的使用。我这里说的就是「中间件」。

中间件提供一种方便的机制来过滤发送到应用中的 HTTP 请求...

下面是一个基本的中间件示例:

<?php

namespace App\Http\Middleware;

use Closure;

class TestMiddleware
{
    /**
     * 处理请求
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        // 在这里加入你的代码

        return $next($request);
    }
}

这些「中间件」实际上就是管道通过接受传入的请求,来处理执行所需的任务。在这里你可以来检测当前接受的请求是一个 HTTP 请求、JSON 请求或任何用户认证等工作。

如果你快速浏览过 Illuminate\Foundation\Http\Kernel 类,你会看到中间件是如何在 Pipeline 对象中被执行的。

/**
  * 将请求传入到指定的 中间件/路由。

  * @param  \Illuminate\Http\Request  $request
  * @return \Illuminate\Http\Response
  */
protected function sendRequestThroughRouter($request)
{
    $this->app->instance('request', $request);
    Facade::clearResolvedInstance('request');
    $this->bootstrap();
    return (new Pipeline($this->app))
                    ->send($request)
                    ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
    ->then($this->dispatchToRouter());
}

你可以从这段代码中看到:pipeline 实例将请求发送到一组中间件中,并将其分发到路由器。

如果这段代码对你来说有些手足无措的话请不用担心。我将以一些实例来阐明它的相关概念。

在类中运行多个任务(Working on a class that requires to run multiple tasks)

考虑一下这样的场景。我们需要创建一个允许用户创建话题和留言功能的论坛系统。但客户端在它们创建或编辑时要求你自动删除标签。

下面是你需要做的事情:

  1. 替换文本中的 link 标签。
  2. 使用「*」替换掉敏感词。
  3. 移除文本中的 script 标签。

也许最终你会构建相关的类来处理这些「任务」。

$pipes = [
    RemoveBadWords::class
    ReplaceLinkTags::clas
    RemoveScriptTags::class
];

我们要做的就是将我们的「内容」依次传入每个任务,然后将上一个任务处理结果传入到下一个任务。我们可以使用管道来处理这个任务。

public function create(Request $request)
{
    $pipes = [
        RemoveBadWords::class,
        ReplaceLinkTags::class,
        RemoveScriptTags::class
    ];

    $post = app(Pipeline::class)
    ->send($request)
    ->through($pipes)
    ->then(function ($content) {
        return Post::create(['content' => $content]);
    });

    // 返回响应
}

每个「任务」类都需要定义一个「handle」方法来处理功能。也许通过实现接口编程是一个不错的主意:

<?php

namespace App;

use Closure;

interface Pipe
{
    public function handle($content, Closure $next);
}
  • 命名好难啊 ¯_(ツ)_/¯*
<?php

namespace App;

use Closure;

class RemoveBadWords implements Pipe
{
    public function handle($content, Closure $next)
    {
        // 在这里处理任务,返回待更新的 **$content** 给到下一个管道任务。
        return  $next($content);
    }
}

用于处理任务的方法接收两个参数,第一个是一个可传递的对象,第二个是闭包,在运行最后一个管道后对象将被重定向到这个闭包。

你也可以自定义方法名来替代「handle」方法名。然后您需要指定管道要使用的方法名,就像这样:

app(Pipeline::class)
 ->send($content)
 ->through($pipes)
 ->via('customMethodName') // <---- 就是这个 :)
 ->then(function ($content) {
     return Post::create(['content' => $content]);
 });

最后发生了什么?(What happens at the end ?)

这里应该发生的是提交的内容将会被每个 \$pipes 修改,最终的返回的内容将被保存。

$post = app(Pipeline::class)
    ->send($request->all())
    ->through($pipes)
    ->then(function ($content) {
        return Post::create(['content' => $content]);
    });

结束语(Final words)

记住, 有很多方法可以处理这种类型的问题。如何选择取决于你。但是值得高兴的是在你的知识库中在需要的时候已经建立了管道这个新的武器的知识。

我希望这个实例能够让你对「Laravel Pipelines」有更深如的了解,并知道如何使用它们。

你也可以去查看 laravel api 文档,如果你希望了解更多它是如何工作的 https://laravel.com/api/5.4/Illuminate/Pipeline/Pipeline.html

在哪用?(Where to use it ?)

这需要靠你去发现... 如果你有任何好的将以请联系我。😉

发表评论

电子邮件地址不会被公开。 必填项已用*标注