3分鐘短文:Laravel路子真野啊!路由暱稱字首中介軟體

程式設計師小助手發表於2020-10-20

引言

上一章內容我們介紹了使用laravel路由動詞定義方便的url,以及通過url引數繫結傳遞資料,本文我們繼續深入Route功能,學習一些提升生產力的方法,在現實場景中也非常實用。

img

“暱稱”

如果你的應用程式路由條目可以達到300到500條,光是管理這些路由地址不重複,或者是瀏覽某些部分的路由,

都將是一件非常考驗腦力的事兒。

有沒有想過,能不能給路由起個名字,方便記憶,不用想著路由定義的多複雜,我們們直接用別名訪問?laravel為我們考慮到了,

比如路由這樣寫:

Route::get('members/{id}', 'MembersController@show')->name('members.show');

這樣定義之後在HTML檔案內比如有 a 標籤,或者 form 表單的 action,填url地址的時候,就可以使用laravel的助手函式,這樣來寫:

<a href="<?php echo route('members.show', ['id' => 14]); ?>">

這樣使用起來,就好像記一個函式名一樣,然後通過陣列傳入繫結的位置引數,一般不容易寫錯,格式化也更好。比如我們之前講述的,使用laravel的 Route::resource() 方法生成 restful 風格的api,那麼如果對一個 Phone 模型相關的介面做別名,大概會是這樣子的:

photos.index
photos.create
photos.store
photos.show
photos.edit
photos.update
photos.destroy

其實助手函式 route 提供的引數傳入,可以靈活組裝url,比如按照位置傳入的資料,不指定鍵名,按順序傳入:

route('users.comments.show', [1, 2])
// http://myapp.com/users/1/comments/2

也可以明確鍵名,指定傳入的位置引數:

route('users.comments.show', ['userId' => 1, 'commentId' => 2])
// http://myapp.com/users/1/comments/2

為了驗證位置引數是否和陣列鍵名繫結關係,我們顛倒傳入的引數順序,看看輸出是否如預期:

route('users.comments.show', ['commentId' => 2, 'userId' => 1])
// http://myapp.com/users/1/comments/2

可見,route函式是按照鍵名繫結到位置引數的。如果傳入的陣列比可接受的資料要多,route函式會將其作為 get 方法的 querystring 進行傳遞:

route('users.comments.show', ['userId' => 1, 'commentId' => 2, 'opt' => 'a'])
// http://myapp.com/users/1/comments/2?opt=a

分組

分而治之,對於有相同類目的路由,應該歸類到一起,成為一個組。這就是路由組的由來。我們來看一下,不附加任何額外的功能的組是如何宣告的:

Route::group([], function () {
    Route::get('hello', function () {
        return 'Hello';
    });
    Route::get('world', function () {
        return 'World';
    });
});

有了分組,那麼可以手動指定,這個分組內所有註冊的路由,都要經過某個中介軟體,可以宣告如下:

Route::group(['middleware' => 'auth'], function () {
    Route::get('dashboard', function () {
        return view('dashboard');
    });
    Route::get('account', function () {
        return view('account');
    });
});

其中這個 ‘middleware’ => ‘auth’ 的 auth 中介軟體,是宣告在 app/Http/Kernel.php 檔案內,下面這一段是原始碼內自帶的中介軟體:

protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
    'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
    'can' => \Illuminate\Auth\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
    'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];

我們可以直接拿來用。當然了,上面的示例是在路由組內引入的中介軟體。對於極為特殊的中介軟體功能,不能在路由組內統一引用的,可以放到控制器的建構函式內呼叫。比如下面的程式碼:

class DashboardController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
        $this->middleware('admin-auth')->only('admin');
        $this->middleware('team-member')->except('admin');
    }
}

因為控制器類已經繼承了中介軟體的註冊流程,所以可以有效使用中介軟體的攔截、驗證功能。

加字首

在規劃路由時,能省則省,功能一致的放在一起,同時在路由數量多了之後,能夠有效地使用字首區分不同的功能模組,也是一個很好的實踐。

為一組路由加字首,就想註冊中介軟體一樣,在配置內手動指定,比如下面這樣:

Route::group(['prefix' => 'api'], function () {
    Route::get('/', function () {
        // 路徑 /api
    });
    Route::get('users', function () {
        // 路徑 /api/users
    });
});

字首是給url路徑中路由部分指定的,我們還可以為二級域名指定路由,相似地,宣告如下程式碼:

Route::group(['domain' => 'api.myapp.com'], function () {
    Route::get('/', function () {
    //
    });
});

那麼該路由組內所有路由,就僅對指定的二級域名起作用。當然了二級域名還要使用nginx的反向代理配合使用。

laravel的花樣是真多啊!

不僅如此,我們還可以為路由組宣告是指定的名稱空間下的控制器所使用的。這樣,可以通過把相似功能模組放在相同名稱空間下,從而達到路由分組的目的。比如:

Route::group(['namespace' => 'API'], function () {
     // 對應 App\Http\Controllers\API\EventController
    Route::get('api/', 'EventController@index');
});

寫在最後

laravel是給web藝術家準備的,你想到的,想不到的,基礎的,高階的功能都有了。沒有的,你也可以手動實現輪子夢。從上面註冊的路由方法,大家應該能有所感觸。

Happy coding :-)

我是@程式設計師小助手,專注程式設計知識,圈子動態的IT領域原創作者

本作品採用《CC 協議》,轉載必須註明作者和本文連結
write-less-do-more-make-you-out-of-door

相關文章