Laravel训练计划:周/日/训练动作关联与workout_id绑定问题
解决训练计划多对多关联绑定workout_id的问题
核心问题梳理
你的代码存在几个关键问题,导致无法正确将workout_id绑定到多对多关联中:
- 周关联逻辑错误:直接用
Week::find($j)查找周记录不合理,$j是训练计划的周数序号,并非Week表的主键;且循环中重复执行sync会覆盖之前的关联。 - 请求参数获取方式错误:
$request->week_.$j.'_day_1'的写法无法正确读取请求参数,需使用Laravel标准的input方法。 - 多对多中间表字段传递错误:sync方法的参数格式不正确,未正确携带
workout_id到关联中间表。
修正后的完整代码
public function store(Request $request) { try { $this->validate($request, [ "title" => "required|unique:workouts", "description" => "required", "goal_id" => "required", "level_id" => "required", "duration" => "required", "status" => "required" ]); $image = null; if($request->hasFile('image')) { $image = Cloudinary::upload($request->file('image')->getRealPath())->getSecurePath(); } // 创建训练计划主记录 $workout = Workout::create([ "title" => $request->title, "description" => $request->description, "goal_id" => $request->goal_id, "level_id" => $request->level_id, "duration" => $request->duration, "image" => $image, "price" => $request->price, "status" => $request->status ]); // 关联身体部位和器材 $workout->workout_bodypart()->sync($request->bodyparts); $workout->workout_equipment()->sync($request->equipments); // 处理每周的关联与天数配置 for($weekNum = 1; $weekNum <= $request->duration; $weekNum++) { // 创建或获取当前训练计划对应的周记录(假设Week表用number字段存储周序号) $week = Week::firstOrCreate([ 'number' => $weekNum ]); // 关联训练计划与周 $workout->workout_week()->syncWithoutDetaching([$week->id]); // 遍历7天,处理每天的训练动作关联 for($dayNum = 1; $dayNum <= 7; $dayNum++) { // 获取当天的训练动作ID数组 $exerciseIds = $request->input("week_{$weekNum}_day_{$dayNum}", []); // 休息日无动作,直接跳过 if(empty($exerciseIds)) continue; // 创建或获取天记录(假设Day表用number字段存储天序号) $day = Day::firstOrCreate([ 'number' => $dayNum ]); // 关联周与天,同时绑定workout_id到中间表 $week->week_day()->syncWithoutDetaching([ $day->id => ['workout_id' => $workout->id] ]); // 关联天与训练动作,绑定workout_id到中间表 $day->day_exercise()->syncWithoutDetaching( collect($exerciseIds)->mapWithKeys(function($exerciseId) use ($workout) { return [$exerciseId => ['workout_id' => $workout->id]]; })->toArray() ); } } return redirect()->route('workouts.index')->with('success', "训练计划添加成功!"); } catch(Exception $e) { return redirect()->back()->with('error', $e->getMessage()); } }
关键修正说明
- 周/天记录的创建逻辑:用
firstOrCreate确保每个周/天序号对应的记录存在,避免直接用主键查找的错误。 - 关联方式优化:使用
syncWithoutDetaching避免覆盖已有的关联,适配多对多场景的增量关联需求。 - 请求参数正确读取:通过
$request->input("week_{$weekNum}_day_{$dayNum}")正确获取对应周数天数的训练动作ID。 - 中间表字段传递:在sync时通过键值对形式,将
workout_id附加到中间表,确保所有关联都绑定到当前训练计划。 - 休息日处理:当天无训练动作时直接跳过,符合你3天休息日的需求。
内容的提问来源于stack exchange,提问作者Sharada Sharma
相关产品推荐
相关产品推荐

