带有路由模型绑定的更清洁的Laravel控制器
介绍
Laravel 作为构建网站的框架或构建 API 的容器(lumen)已经发展成为开发人员的首选框架。 Laravel 带有许多不断增长的功能——以 Laravel 的事件为例。 Laravel 中的事件曾经是一个简单的 pub-sub 库,但现在 Laravel 事件可以一直广播到客户端并允许我们创建实时应用程序。
但这不是重点,今天的名人是 Laravel 的路由模型绑定。
什么是路由模型绑定
Laravel 中的路由模型绑定提供了一种将模型实例注入到路由中的机制。 还是不太清楚意思,这里举个例子。 假设我们想从数据库中获取一个帖子,我们可以这样做:
... // the route parameter is the id of the post // for example http://example.com/posts/53 Route::get('posts/{id}', function ($id) { // we have to find the post using the $id $post = Post::find($id); // if there is no post, 404 if (!$post) return abort(404); // return the view and the post return view('post.show', compact('post')); }); ...
我们可以进一步将这种方法简化为
... // the route parameter is the id of the post // for example http://awesome.dev/posts/53 Route::get('posts/{id}', function ($id) { // find the post or 404 if not found $post = Post::findOrFail($id); // return the view and the post return view('post.show', compact('post')); }); ...
但是路由模型绑定通过将上面的两个实例简化为
... // by using $post, we can inject the Post object Route::get('posts/{post}', function ($post) { // we now have access to the $post object! no code necessary // return the view and the post return view('post.show', compact('post')); }); ...
这可以通过告诉 Laravel 将 Post
模型注入到任何附加了 {post}
参数的路由控制器中来实现。
Laravel 目前支持两种类型的路由模型绑定。 我们有:
- 隐式模型绑定
- 显式模型绑定
注: 上面列出的路由模型绑定示例是显式的。
隐式模型绑定
虽然我们已经看到了显式模型绑定,但下面是一个隐式模型绑定的示例:
Route::get('posts/{post}', function (App\Post $post) { // be awesome. enjoy having the $post object });
Laravel 足够聪明,知道由于 Post
模型被注入到控制器闭包中,它应该从路由中获取 id
参数并为用户获取详细信息。
访问帖子仍需使用 http://awesome.example.com/posts/24
。
更改模型的 Route Key
如果您希望隐式模型绑定在检索模型时使用 id
以外的数据库列,您可以覆盖 Eloquent 模型上的 getRouteKeyName
方法。
例如,如果我们想使用 slug
而不是 id
,我们可以执行以下操作:
class Post extends Model { public function getRouteKeyName() { return 'slug'; } }
然后我们可以使用 http://awesome.example.com/posts/my-post-slug
而不是 http://awesome.example.com/posts/24
访问我们的路线。
显式模型绑定
就像名字暗示的那样,你必须明确告诉 Laravel 你希望它绑定一个 url
参数到一个特定的模型。 有两种方法可以做到这一点,我们可以使用提供的 Route
外观将参数绑定到模型,或者在 app/Providers/RouteServiceProvider.php
中执行此绑定(我更喜欢这种方法)。
使用 Route
外观
使用 Route
外观将参数绑定到模型,我们可以这样做:
Route::bind('post', 'App\Post');
我们还可以赋予绑定更多的意义,例如,如果我们只想要一个帖子,如果是草稿怎么办? 为此,我们可以将 Route::bind
的第二个参数更改为以路由参数为值的闭包。
Route::bind('post', function ($value) { return App\Post::find($value)->where('status', '=', 'published')->first(); });
使用 RouteServiceProvider
使用 Route
外观和 RouteServiceProvider
类之间的唯一区别是 - 注册绑定是在 RouteServiceProvider
类的 boot
方法中完成的(位置是app/Providers
目录)并且在注入方法的 $router
对象上调用 bind
方法。 快速示例
public function boot(Router $router) { parent::boot($router); $router->bind('post', function ($value) { return App\Post::find($value)->where('status', '=', 'published')->first(); }); }
路由模型绑定的自定义异常
我构建了很多 API,因此路由模型绑定的自定义异常实际上对像我这样的人更有用。 Laravel 为我们提供了一种简单的方法来做到这一点。 还是在RouteServiceProvider
类的boot
方法中,调用$router
对象的model
方法。
model
方法接受三个参数,这些参数与 bind
方法的参数相似,只是增加了第三个参数,它是一个抛出新异常的闭包。
$router->model($routeParameter, $modelToBind, function () { throw new NotFoundHTTPException; });
结论
您可以在 文档 中阅读有关路由模型绑定的更多信息。
希望这个小而简洁的功能可以在您的项目中为您节省几行代码,并使您的控制器更加简洁。