Laravel 路由参数绑定与路由模型绑定

老牛浏览 446评论 0发表于

在 Laravel 中一个典型的路由定义是这样的:

routes/web.php

php
// 闭包方式定义路由
Route::get('foo', function () {
    return 'Hello World';
})

当然也可以将其指定到具体控制器:

php
Route::get('home', 'PagesController@home');

routes/web.php 文件用于定义 web 界面的路由。里面的路由都会被分配给 web 中间件组,它提供了会话状态和 CSRF 保护等功能。定义在 routes/api.php 中的路由都是无状态的,并且被分配了 api 中间件组。

1. 路由参数绑定

当然,有时需要在路由中捕获一些 URL 片段。例如,从 URL 中捕获用户的 ID,可以通过定义路由参数来执行此操作:

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

也可以根据需要在路由中定义多个参数:

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

路由的参数通常都会被放在 {} 内,并且参数名只能为字母,同时路由参数不能包含 - 符号,如果需要可以用下划线 _ 代替。路由参数会按顺序依次被注入到路由回调或者控制器中,而不受回调或者控制器的参数名称的影响。

有时,可能需要指定一个路由参数,但希望这个参数是可选的。那么可以在参数后面加上 ? 标记来实现,但前提是要确保路由的相应变量有默认值

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

2. 路由模型绑定

当向路由或控制器行为注入模型 ID 时,就需要查询这个 ID 对应的模型。Laravel 为路由模型绑定提供了一个自动将模型实例注入到路由中的方法。例如,你可以注入与给定 ID 匹配的整个 User 模型实例,而不是仅注入用户的 ID。

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

实现路由模型的自动绑定,需要满足以下条件:

  • 控制器或闭包中的变量「类型提示」或「类型约束」为 Eloquent 模型

  • 控制器或闭包中的变量名与路由中的变量名匹配

满足以上两个条件即可实现路由模型的自动注入。该功能是由中间件的 \Illuminate\Routing\Middleware\SubstituteBindings 类来完成的。该中间件同时存在于 web 和 api 中间件组中。

除了自动绑定,还可以进行显式绑定。要注册显式绑定,使用路由器的 model() 方法来为给定参数指定要绑定的类。在 RouteServiceProvider 类中的 boot() 方法内定义显式模型绑定:

app/Providers/RouteServiceProvider.php

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

    Route::model('user', App\Models\User::class);
}

接着,定义一个包含 {user} 参数的路由:

routes/web.php

php
Route::get('profile/{user}', function (User $user) {
    //
})

因为我们已经将所有 {user} 参数绑定到 App\Models\User 模型,所有 User 实例将被注入到该路由。例如,profile/1 的请求会注入数据库中 ID 为 1 的 User 实例。

如果在数据库中不存在对应 ID 的数据,就会自动抛出一个 404 异常。

3. 总结

  • 路由参数会按顺序依次被注入到路由回调或者控制器中,而不受回调或者控制器的参数名称的影响。

  • 要实现路由模型自动绑定,满足以下要求:

    • 控制器或闭包中的变量「类型提示」或「类型约束」为 Eloquent 模型

    • 控制器或闭包中的变量名与路由中的变量名匹配

点赞
收藏
暂无评论,快来发表评论吧~
私信
老牛@ilaoniu
老牛,俗称哞哞。单纯的九零后理工小青年。喜欢折腾,爱玩,爱音乐,爱游戏,爱电影,爱旅游...
最后活跃于