Laravel中如何向带参数关联的Eager load预加载传递参数
Laravel 动态中间表关联带参数预加载实现
问题场景
- 业务需要根据传入日期,从两个结构一致的中间表加载线路与驾驶员的多对多关联:
driver_route:存储当前周、未来日期的关联数据,通过weekday字段匹配星期标识driver_route_history:存储历史周的归档数据,通过date字段匹配绝对日期
- 已实现直接调用可用的
driversOnDay($date)方法,但需要支持Laravel预加载(Eager Load)调用,同时传入日期参数
原有方法代码如下:
public function driversOnDay($date) { $carbon_date = Carbon::parse($date); if ($carbon_date->isBefore(Carbon::today()->startOfWeek())) { return $this->belongsToMany(Driver::class, 'driver_route_history')->wherePivot('date', $carbon_date); } else { return $this->belongsToMany(Driver::class, 'driver_route')->wherePivot('weekday', strtolower($carbon_date->shortDayName)); } }
预期调用形式:
Route::with(['driversOnDay' => function($query) { ... });
实现方案
Laravel的关联定义方法不支持直接传入自定义参数,关联加载时框架会自动调用方法获取关系实例,手动传入的参数不会被注入,因此需要把固定关联定义和动态参数逻辑拆分实现:
- 首先在
Route模型中定义两个固定的多对多关联,对应两张中间表
// 对应当前/未来周数据关联 public function driversCurrent() { return $this->belongsToMany(Driver::class, 'driver_route'); } // 对应历史归档数据关联 public function driversHistory() { return $this->belongsToMany(Driver::class, 'driver_route_history'); }
- 封装本地查询作用域,把日期判断、关联选择、pivot条件约束的逻辑统一封装,后续调用直接传日期即可
use Carbon\Carbon; use Illuminate\Database\Eloquent\Builder; // Route模型中添加作用域 public function scopeWithDriversOnDay(Builder $query, string $date): Builder { $carbonDate = Carbon::parse($date); // 判断日期区间,选择对应关联 $targetRelation = $carbonDate->isBefore(Carbon::today()->startOfWeek()) ? 'driversHistory' : 'driversCurrent'; return $query->with([ $targetRelation => function($relationQuery) use ($carbonDate) { if ($carbonDate->isBefore(Carbon::today()->startOfWeek())) { $relationQuery->wherePivot('date', $carbonDate->toDateString()); } else { $relationQuery->wherePivot('weekday', strtolower($carbonDate->shortDayName)); } } ]); }
- 实际调用时直接传日期参数,支持和其他查询条件链式组合
// 最简单调用 $routes = Route::withDriversOnDay('2022-08-06')->get(); // 结合筛选条件、分页使用 $routes = Route::where('line_status', 1) ->orderBy('id') ->withDriversOnDay(request('query_date')) ->paginate(20);
注意:如果需要在获取模型后再懒加载对应关联,也可以用同样的判断逻辑,调用
load()方法传入对应关联和约束即可。
内容的提问来源于stack exchange,提问作者julianatkin
相关产品推荐
相关产品推荐

