带有路由模型绑定的更清洁的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;
});

结论

您可以在 文档 中阅读有关路由模型绑定的更多信息。

希望这个小而简洁的功能可以在您的项目中为您节省几行代码,并使您的控制器更加简洁。