Laravel 11双模型注入路由报错:如何通过slug解析模型?
Laravel 11 基于Slug的路由模型绑定问题解决
问题场景
在Laravel 11中配置了如下路由与控制器方法:
Route::prefix('g/{guide:slug}/p/{property:slug}') ->controller(GuestController::class) ->group(function () { Route::get('/', 'guidePropertyBySlug') ->where('guide', Guide::class) ->where('property', Property::class) ->name('guide-property-slug.show') ->withoutScopedBindings(); }); public function guidePropertyBySlug(Guide $guide, Property $property): Response|ResponseFactory { $guideProperty = GuideProperty::where('guide_id', $guide->id)->where('property_id', $property->id)->firstOrFail(); $guideProperty->load( 'guide.featuredMedia', 'guide.categories.featuredMedia', 'guide.categories.tileFeaturedMedia', 'property.address', 'property.hotel.address', 'property.description', 'property.featuredMedia'); return $this->setData($guideProperty)->send(); }
Guide和Property模型同时引入两个Trait:
- Uuidable:将模型的
getRouteKeyName设置为uuid - Sluggable:依赖
slug字段,但未修改路由键配置
运行时触发错误:
[2024-04-07 22:37:37] local.ERROR: preg_match(): Compilation failed: unrecognized character follows \ at offset 18 {"exception":"[object] (ErrorException(code: 0): preg_match(): Compilation failed: unrecognized character follows \\ at offset 18 at /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Matching/UriValidator.php:21) [stacktrace]
解决步骤
1. 移除错误的路由约束配置
直接删除路由中的->where('guide', Guide::class)和->where('property', Property::class)两行。where方法用于定义路由参数的正则匹配规则,传入模型类会导致Laravel生成无效的正则表达式,这是触发错误的直接原因。
2. 正确配置基于Slug的模型绑定
由于模型默认路由键被Uuidable设置为uuid,需要明确指定当前路由用slug字段解析模型,有两种可选方案:
方案一:路由内自定义绑定逻辑(推荐,不影响全局路由行为)
在路由中通过bind方法指定参数的解析规则:
Route::prefix('g/{guide:slug}/p/{property:slug}') ->controller(GuestController::class) ->group(function () { Route::get('/', 'guidePropertyBySlug') ->name('guide-property-slug.show') ->withoutScopedBindings() ->bind('guide', function ($slug) { return Guide::where('slug', $slug)->firstOrFail(); }) ->bind('property', function ($slug) { return Property::where('slug', $slug)->firstOrFail(); }); });
方案二:修改模型的路由绑定逻辑(全局生效)
在Guide和Property模型中重写resolveRouteBinding方法,根据传入的字段参数选择查询条件:
// Guide模型 public function resolveRouteBinding($value, $field = null) { return $field === 'slug' ? $this->where('slug', $value)->firstOrFail() : parent::resolveRouteBinding($value, $field); } // Property模型同理 public function resolveRouteBinding($value, $field = null) { return $field === 'slug' ? $this->where('slug', $value)->firstOrFail() : parent::resolveRouteBinding($value, $field); }
修改后,路由中{guide:slug}的写法会自动触发Laravel用slug字段查询模型,无需额外配置路由绑定。
3. 验证控制器方法
控制器的参数类型提示Guide $guide和Property $property已经正确,修正路由后,Laravel会自动将解析后的模型实例注入方法,无需修改控制器代码。
内容的提问来源于stack exchange,提问作者TheRealPapa
相关产品推荐
相关产品推荐

