Laravel 路由

1、基本路由

最基本的 Laravel 路由只接收一個 URI 和一個閉包,並以此提供一個非常簡單且優雅的定義路由方法:

Route::get('home', function () {
    return 'Hello World';
});

默認路由文件

所有 Laravel 路由都定義在位於 routes 目錄下的路由文件中,這些文件通過框架自動加載。routes/web.php 文件定義了web界面的路由,這些路由被分配了web中間件組,從而可以提供session和csrf防護等功能。routes/api.php 中的路由是無狀態的,被分配了 api 中間件組。
對大多數應用而言,都是從 routes/web.php 文件開始定義路由。

有效的路由方法

我們可以註冊路由來響應任何 HTTP 請求:

Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);

有時候還需要註冊路由響應多個 HTTP 請求——這可以通過 match 方法來實現。或者,可以使用 any 方法註冊一個路由來響應所有 HTTP 請求:

Route::match(['get', 'post'], '/', function () {
    //
});

Route::any('home', function () {
    //
});

CSRF防護

在 web 路由文件中所有請求方式爲PUT、POST或DELETE的HTML表單都會包含一個CSRF令牌字段,否則,請求會被拒絕。關於CSRF的更多細節,可以參考CSRF文檔:

<form method="POST" action="/profile">
    {{ csrf_field() }}
    ...
</form>

2、路由參數

必選參數

有時我們需要在路由中捕獲 URI 片段。比如,要從 URL 中捕獲用戶ID,需要通過如下方式定義路由參數:

Route::get('user/{id}', function ($id) {
    return 'User '.$id;
});

可以按需要在路由中定義多個路由參數:

Route::get('posts/{post}/comments/{comment}', function ($postId, $commentId) {
    //
});

路由參數總是通過花括號進行包裹,這些參數在路由被執行時會被傳遞到路由的閉包。路由參數不能包含 - 字符,需要的話可以使用 _ 替代。

可選參數

有時候可能需要指定可選的路由參數,這可以通過在參數名後加一個 ? 標記來實現,這種情況下需要給相應的變量指定默認值:

Route::get('user/{name?}', function ($name = null) {
    return $name;
});

Route::get('user/{name?}', function ($name = 'John') {
    return $name;
});

正則約束

可以使用路由實例上的 where 方法來約束路由參數的格式。where 方法接收參數名和一個正則表達式來定義該參數如何被約束:

Route::get('user/{name}', function ($name) {
    //
})->where('name', '[A-Za-z]+');

Route::get('user/{id}', function ($id) {
    //
})->where('id', '[0-9]+');

Route::get('user/{id}/{name}', function ($id, $name) {
    //
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);

全局約束

如果想要路由參數在全局範圍內被給定正則表達式約束,可以使用 pattern 方法。在RouteServiceProvider 類的 boot 方法中定義約束模式:

/**
 * 定義路由模型綁定,模式過濾器等
 *
 * @param  \Illuminate\Routing\Router  $router
 * @return void
 * @translator  http://laravelacademy.org
 */
public function boot()
{
    Route::pattern('id', '[0-9]+');
    parent::boot();
}

一旦模式被定義,將會自動應用到所有包含該參數名的路由中:

Route::get('user/{id}', function ($id) {
    // 只有當 {id} 是數字時纔會被調用
});

3、命名路由

命名路由爲生成 URL 或重定向提供了便利。實現也很簡單,在路由定義之後使用 name 方法鏈的方式來實現:

Route::get('user/profile', function () {
    //
})->name('profile');

還可以爲控制器動作指定路由名稱:

Route::get('user/profile', 'UserController@showProfile')->name('profile');

爲命名路由生成URL

爲給定路由分配名稱之後,就可以通過輔助函數 route 爲該命名路由生成 URL:

$url = route('profile');
return redirect()->route('profile');

如果命名路由定義了參數,可以將該參數作爲第二個參數傳遞給 route 函數。給定的路由參數將會自動插入到 URL 中:

Route::get('user/{id}/profile', function ($id) {
    //
})->name('profile');

$url = route('profile', ['id' => 1]);

4、路由羣組

路由羣組允許我們在多個路由中共享路由屬性,比如中間件和命名空間等,這樣的話我們就不必爲每一個路由單獨定義屬性。共享屬性以數組的形式作爲第一個參數被傳遞給 Route::group 方法。

中間件

要給路由羣組中定義的所有路由分配中間件,可以在羣組屬性數組中使用 middleware。中間件將會按照數組中定義的順序依次執行:

Route::group(['middleware' => 'auth'], function () {
    Route::get('/', function () {
        // 使用 Auth 中間件
    });

    Route::get('user/profile', function () {
        // 使用 Auth 中間件
    });
});

命名空間

另一個通用的例子是路由羣組分配同一個 PHP 命名空間給其下的多個控制器,可以在分組屬性數組中使用 namespace 來指定羣組中所有控制器的公共命名空間:

Route::group(['namespace' => 'Admin'], function(){
    // 控制器在 "App\Http\Controllers\Admin" 命名空間下
});

默認情況下,RouteServiceProvider 引入你的路由文件並指定其下所有控制器類所在的默認命名空間App\Http\Controllers,因此,我們在定義的時候只需要指定命名空間 App\Http\Controllers 之後的部分即可。

子域名路由

路由羣組還可以被用於子域名路由通配符,子域名可以像 URI 一樣被分配給路由參數,從而允許捕獲子域名的部分用於路由或者控制器,子域名可以通過羣組屬性數組中的 domain 來指定:

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

路由前綴

羣組屬性 prefix 可以用來爲羣組中每個路由添加一個給定 URI 前綴,例如,你可以爲所有路由 URI 添加 admin 前綴 :

Route::group(['prefix' => 'admin'], function () {
    Route::get('users', function () {
        // 匹配 "/admin/users" URL
    });
});

5、路由模型綁定

注入模型ID到路由或控制器動作時,通常需要查詢數據庫才能獲取相應的模型數據。Laravel 路由模型綁定讓注入模型實例到路由變得簡單,例如,你可以將匹配給定 ID 的整個 User 類實例注入到路由中,而不是直接注入用戶ID。

隱式綁定

Laravel 會自動解析定義在路由或控制器動作(變量名匹配路由片段)中的 Eloquent 模型類型聲明,例如:

Route::get('api/users/{user}', function (App\User $user) {
    return $user->email;
});

在這個例子中,由於類型聲明瞭 Eloquent 模型 App\User,對應的變量名 $user 會匹配路由片段中的{user},這樣,Laravel 會自動注入與請求 URI 中傳入的 ID 對應的用戶模型實例。

如果數據庫中找不到對應的模型實例,會自動生成 HTTP 404 響應。

自定義鍵名

如果你想要在隱式模型綁定中使用數據表的其它字段,可以重寫 Eloquent 模型類的 getRouteKeyName 方法:

/**
 * Get the route key for the model.
 *
 * @return string
 */
public function getRouteKeyName()
{
    return 'slug';
}

顯示綁定

要註冊顯式綁定,需要使用路由的 model 方法來爲給定參數指定綁定類。應該在 RouteServiceProvider 類的 boot 方法中定義模型綁定:

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

接下來,定義一個包含 {user} 參數的路由:

$router->get('profile/{user}', function(App\User $user) {
     //
});

由於我們已經綁定 {user} 參數到 App\User 模型,User 實例會被注入到該路由。因此,如果請求 URL 是 profile/1,就會注入一個用戶 ID 爲 1 的 User 實例。

如果匹配的模型實例在數據庫不存在,會自動生成並返回 HTTP 404 響應。

自定義解析邏輯

如果你想要使用自定義的解析邏輯,需要使用 Route::bind 方法,傳遞到 bind 方法的閉包會獲取到 URI 請求參數中的值,並且返回你想要在該路由中注入的類實例:

public function boot()
{
    parent::boot();

    Route::bind('user', function($value) {
        return App\User::where('name', $value)->first();
    });
}

6、表單方法僞造

HTML 表單不支持 PUT、PATCH 或者 DELETE 請求方法,因此,當定義 PUT、PATCH 或 DELETE 路由時,需要添加一個隱藏的 _method 字段到表單中,其值被用作該表單的 HTTP 請求方法:

<form action="/foo/bar" method="POST">
    <input type="hidden" name="_method" value="PUT">
    <input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>

還可以使用輔助函數 method_field 來實現這一目的:

{{ method_field('PUT') }}

7、訪問當前路由

你可以使用 Route 門面上的 current、currentRouteName 和 currentRouteAction 方法來訪問處理當前輸入請求的路由信息:

$route = Route::current();
$name = Route::currentRouteName();
$action = Route::currentRouteAction();
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章