輕鬆理解laravel的Pipeline("管道"模式)

本文來自pilishen.com----原文連接; 歡迎來和pilishen一塊兒學習php&Laravel;學習羣:109256050php

該篇屬於《Laravel底層核心技術實戰揭祕》這一課程《laravel底層核心概念解析》這一章的擴展閱讀。考慮到學員們的基礎差別,爲了不視頻當中過於詳細而連篇累牘,故將一些laravel底層實現相關的PHP知識點以文章形式呈現,供你們預習和隨時查閱。laravel

基本上,使用laravel pipelines你能夠將一個實例對象(object)在多個類之間傳遞,就像流水順着管道依次流淌通常,最終呢,層層傳遞,你就獲得了從頭到尾一系列執行操做的「最終」結果。數據庫

固然,laravel裏pipeline(管道、通道)相關的,最直接的例子就是Middleware了。藉助這種通道方式,Middleware能夠很方便地層層「過濾」(filter)進入你程序中的request。json

下面是一個基本的Middleware例子:bootstrap

<?php
namespace App\Http\Middleware;
use Closure;
class TestMiddleware
{
    
    public function handle($request, Closure $next)
    {
        // 這裏添加本身的邏輯
        return $next($request);
    }
}
複製代碼

middleware就像是咱們的request請求流經的「管道」,這期間能夠執行必要的操做,好比判斷當前請求是一個http請求呢,仍是一個json請求呢,或者也能夠檢查一下用戶的權限,或許這個時候你就會想到咱們laratrust(或Entrust)插件一系列經典的Middleware。bash

《Laravel底層核心技術實戰揭祕》課程裏,涉及到service provider的加載註冊原理和源碼解讀的時候,咱們一塊兒看過Illuminate\Foundation\Http\Kernel這個class,期間呢詳細分析了sendRequestThroughRouter這個方法:app

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());
}
複製代碼

注意return後面的那段,看字面意思都很好理解:ide

一個new Pipeline發送了(send)request請求,經過了(through)咱們的Middleware,而後(then)提交給了路由。函數

例子:實現一個須要依次處理多個任務的類(class)邏輯

假設呢你在寫一個論壇功能,用戶呢能夠建立話題、評論話題,可是呢,你的客戶要求你實現一個能自動替換刪除某些內容、符號的功能,數據處理了之後呢才能寫入數據庫,好比說具體的需求列表是這樣的:post

  1. 刪除那些沒有href的空的連接
  2. 將一些敏感詞彙替換成星號*
  3. 刪掉用戶提交可能危險的script tag

極可能最後呢,你須要實現下面的這個處理過程:

$pipes = [
    RemoveBadWords::class
    ReplaceLinkTags::class
    RemoveScriptTags::class
];
複製代碼

咱們須要的是,將須要處理的內容依次傳遞到這三個class中,上一個class的執行結果要傳給下一個class來繼續處理,那麼相似的需求,咱們就可使用pipeline來實現:

<?php

public function create(Request $request)
{
    $pipes = [
        RemoveBadWords::class,
        ReplaceLinkTags::clas,
        RemoveScriptTags::class
    ];
    $post = app(Pipeline::class)
        ->send($request->content)
        ->through($pipes)
        ->then(function ($content) {
            return Post::create(['content' => 'content']);
        });
    // return any type of response
}
複製代碼

每個數據處理的class,都應該有一個handle方法來執行具體的邏輯,因此這個時候讓它們都擴展或實現某個特定的interface比較好:

<?php
namespace App;

use Closure;

interface Pipe
{
    public function handle($content, Closure $next);
}
複製代碼

而後呢假設咱們過濾敏感詞的class就能夠這樣寫:

<?php
namespace App;

use Closure;

class RemoveBadWords implements Pipe
{
    public function handle($content, Closure $next)
    {
        //具體的替換邏輯,更新掉$content
        return  $next($content);
    }
}
複製代碼

這裏handle方法接收兩個參數,第一個是你要在管道中傳遞的對象(passable object),第二個呢是一個Closure,也便是匿名函數,它指代你管道中的下一步,當前這一步的邏輯執行完了,就能夠把結果傳給下一步。

你也能夠不用handle這個方法名,但這個時候你須要經過via方法來指定自定義方法的名字:

app(Pipeline::class)
 ->send($content)
 ->through($pipes)
 ->via(‘customMethodName’) // <---- 在這兒指定
 ->then(function ($content) {
     return Post::create(['content' => $content]);
 });
複製代碼

原文出處://medium.com/@jeffochoa/understanding-laravel-pipelines-a7191f75c351

相關文章
相關標籤/搜索