Lumen控制器方法模型注入失败 参数应为Post类型实际传入字符串
尝试在Lumen中使用依赖注入能力,基于请求URL中的模型ID参数自动注入对应模型实例(该特性在Laravel中为资源控制器默认可用能力),路由定义如下:
$router->get('post/{post}', "PostController@show");
对应控制器方法实现:
/** * Display the specified resource. * * @param \App\Models\Post $post * @return \Illuminate\Http\Response */ public function show(Post $post) { if($post) { return $this->response("Post found.", Response::HTTP_OK, $post->toArray()); } return $this->response("Post not found.", Response::HTTP_NOT_FOUND); }
运行时抛出如下异常:
App\Http\Controllers\PostController::show(): Argument #1 ($post) must be of type App\Models\Post, string given
Lumen为了精简性能默认关闭了路由模型绑定功能。虽然它和Laravel共用同一套服务容器,但路由参数自动解析为对应模型实例的特性没有默认启用,因此路由定义里的{post}参数只会原样传入URL中的字符串ID,不会自动查询对应Post模型实例,最终触发参数类型不匹配的报错。
可根据实际需求选择以下两种方案:
方案1:显式绑定指定路由参数(性能最优,推荐)
不需要修改全局配置,仅为需要模型解析的路由参数单独声明绑定逻辑即可,额外性能开销最低。
- 直接在
bootstrap/app.php文件中,在路由注册代码之前添加参数绑定逻辑:
// 绑定 {post} 参数到 Post 模型 $router->bind('post', function ($id) { return \App\Models\Post::findOrFail($id); }); // 原有路由定义保持不变 $router->get('post/{post}', "PostController@show");
绑定后框架会自动将URL中传入的post ID查询为对应的Post实例传入控制器方法,findOrFail方法在模型不存在时会自动返回404响应,原有控制器里的if($post)判断可以直接删除。
- 如果需要绑定的参数较多,也可以将统一的绑定逻辑放到
app/Providers/RouteServiceProvider.php的boot方法中维护。
方案2:全局开启隐式路由模型绑定(与Laravel用法完全一致)
如果希望和Laravel保持一致的使用体验——只要控制器方法参数类型、变量名和路由参数匹配就自动解析模型,可以全局开启该功能:
- 第一步:打开
bootstrap/app.php,取消RouteServiceProvider注册行的注释:
// 原注释状态 // $app->register(App\Providers\RouteServiceProvider::class); // 取消注释后 $app->register(App\Providers\RouteServiceProvider::class);
- 第二步:打开
app/Providers/RouteServiceProvider.php,在boot方法中添加配置,启用参数替换中间件并全局生效:
public function boot() { parent::boot(); // 注册路由参数绑定中间件 $this->app->router->aliasMiddleware('bindings', \Illuminate\Routing\Middleware\SubstituteBindings::class); // 给所有Web路由应用绑定中间件 $this->app->router->pushMiddlewareToGroup('web', \Illuminate\Routing\Middleware\SubstituteBindings::class); }
配置完成后,现有路由和控制器代码不需要做任何修改即可正常运行,行为和Laravel的资源路由模型绑定完全一致。
如果需要自定义模型解析逻辑(比如不用主键ID查询,改用slug等其他字段匹配),无论使用哪种方案,都可以通过bind方法自定义解析闭包的逻辑,用法和Laravel完全一致。
内容的提问来源于stack exchange,提问作者Muhammad Ismail

