Laravel显式模型绑定下路由指定withTrashed的实现方案
优雅解决Laravel显式模型绑定支持软删除的几种方案
针对你遇到的显式模型绑定不识别withTrashed路由选项的问题,这里有几个不用重复实现$route->allowsTrashedBindings()的优雅处理方式:
方案一:在显式绑定中直接判断路由动作
在RouteServiceProvider的显式绑定逻辑里,直接通过当前路由的动作名称来决定是否包含软删除模型。示例代码如下:
// RouteServiceProvider.php public function boot() { parent::boot(); $this->bind('organization', function ($value) { $query = Organization::query(); // 检查当前路由动作是否在允许的列表中 if (in_array(request()->route()->getActionMethod(), ['show', 'update'])) { $query->withTrashed(); } return $query->findOrFail($value); }); // Region、Location的绑定逻辑可以复用同样的判断逻辑 }
如果三个模型的判断逻辑一致,可以封装成私有方法避免重复代码:
// RouteServiceProvider.php private function getModelQuery($modelClass) { $query = $modelClass::query(); if (in_array(request()->route()->getActionMethod(), ['show', 'update'])) { $query->withTrashed(); } return $query; } // 绑定调用示例 $this->bind('organization', function ($value) { return $this->getModelQuery(Organization::class)->findOrFail($value); });
方案二:利用路由参数的自定义约束
给路由参数添加额外标识,在显式绑定里识别该标识来决定是否启用软删除查询:
- 修改路由定义:
// api.php Route::apiResource('organizations', OrganizationController::class) ->withTrashed(['show', 'update']) ->parameters([ 'organizations' => 'organization:withTrashed' ]);
- 在
RouteServiceProvider中处理绑定:
public function boot() { parent::boot(); $this->bind('organization', function ($value, $route) { $paramDefinition = $route->signatureParameters()[$route->parameterNames()[0]]->getName(); // 检查参数是否带有withTrashed标识 if (str_contains($paramDefinition, 'withTrashed')) { return Organization::withTrashed()->findOrFail($value); } return Organization::findOrFail($value); }); }
这种方式无需硬编码动作名称,能更灵活地控制哪些路由参数支持软删除。
方案三:自定义中间件控制模型查询作用域
创建中间件挂载到指定路由,动态给模型添加withTrashed全局作用域:
- 创建中间件:
// app/Http/Middleware/AllowTrashedBindings.php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use App\Models\Organization; use App\Models\Region; use App\Models\Location; class AllowTrashedBindings { public function handle(Request $request, Closure $next) { // 给目标模型添加软删除查询作用域 foreach ([Organization::class, Region::class, Location::class] as $model) { $model::addGlobalScope('withTrashed', function ($query) { $query->withTrashed(); }); } return $next($request); } }
- 在
Kernel.php注册中间件:
// app/Http/Kernel.php protected $routeMiddleware = [ // ... 'allow.trashed' => \App\Http\Middleware\AllowTrashedBindings::class, ];
- 修改路由定义,给指定动作挂载中间件:
// api.php Route::apiResource('organizations', OrganizationController::class) ->withTrashed(['show', 'update']) ->middleware(['allow.trashed'])->only(['show', 'update']);
这种方式将软删除控制逻辑与路由绑定分离,符合单一职责原则,也方便后续扩展其他模型。
内容的提问来源于stack exchange,提问作者Moshe Katz
相关产品推荐
相关产品推荐

