Laravel 路由的隱式繫結和顯式繫結

August5th發表於2017-11-17

路由的隱式繫結和顯示繫結

在學習 Laravel 的過程中,見識過控制器中,函式傳遞型別提示為某個 Eloquent 模型的變數之後,函式中就可以直接獲取該模型的相關資料引數的神奇操作。就是利用了路由的隱式繫結和顯示繫結,我就先不看底層如何實現的,先具體學習一下這一功能。

隱式繫結

官方的描述:
Laravel 會自動解析定義在路由或控制器行為中與型別提示的變數名匹配的路由段名稱的 Eloquent 模型

我們下面的例子中也就是: 型別提示的變數名 = 路由段名稱 = Eloquent 模型 = user

Route::get('users/{user}', UsersController@show);

該路由,則是匹配了 User Eloquent 模型,Laravel 會自動注入與請求 URI 中傳入的 ID(即為 {user} 引數的值) 匹配的使用者模型例項。當然,對應的 UsersController 控制器要引入對應的模型檔案。

use App\User;

同時,控制器的 show 方法,要傳入該模型例項。

public function show(User $user)
{
    dd($user->toArray());
}

當然你也可以不引入對應的模型檔案,直接在 show 方法的引數中用完全限定名稱引入相關模型檔案

public function show(\App\User $user)
{
    dd($user->toAyyay());
}

參考 PHP 手冊 - 語言參考的類與物件、名稱空間章節


自定義鍵名

如果你不想用 ID 這個資料庫欄位來檢索模型例項,你也可以在對應 Eloquent 模型上,對 getRouteKeyName 方法進行重寫。
我嘗試使用 users 表中的 name 欄位來獲取模型例項,即如下
app\User.php (這是你的模型檔案的路徑,根據你來定也可以是 app/Models/User.php

public function getRouteKeyName()
{
    return 'name';
}

這個時候,瀏覽器訪問 xxx.app/users/lara 就可以獲取 'users' 表中,name 欄位值為 'lara' 的模型例項。
file

這個地方我在資料庫中插入了另一個同樣的 name 為 lara 的值,但是獲取的例項只有第一個。
還有一個地方需要注意的是,此時的路由也必須是 {user},不能是其他,比如 {name}

顯式繫結

Q&A

Q:那如果我不想用 {user} 作為路由段名稱,想用其他的名稱,比如 {name} 怎麼辦呢?
A:用顯式繫結,將你想要繫結的名稱指定給路由,同時,重寫模型檔案的 getRouteKeyName 方法

app/Providers/RouteServiceProvider.php

public function boot()
{
    parent::boot();
    Route::model('name', \App\User::class);
}

你也可以繫結給其他路由了

Route::get('profile/{name}', function(\App\User $user){
    dd($user->toArray());
});

自定義邏輯

那麼回到之前的問題,「這個地方我在資料庫中插入了另一個同樣的 name 為 lara 的值,但是獲取的例項只有第一個。」
我們想找到 id 為 2, 且 name 為 lara 的模型例項的時候,我們需要自定義繫結的邏輯

app/Providers/RouteServiceProvider.php

public function boot()
{
    parent::boot();
    Route::bind('name', function ($value) {
        return \App\User::where('name', $value)->find(2);
    });
}

其他

當我們使用路由資源的時候

Route::resource('user', 'UsersController');

許多路由已經進行了隱式繫結,你可以在環境中檢視你的路由

$ php artisan route:list

file

最後

以上整理均為自己的理解,如有錯誤,還望指正。

相關文章