query('q', '')); $bodypart = (string) $request->query('bodypart', ''); $muscle = (string) $request->query('muscle', ''); $equipment = (string) $request->query('equipment', ''); $perPage = (int) ($request->query('per_page', 12)); if ($perPage < 6 || $perPage > 60) { $perPage = 12; } $query = Exercise::query() ->with(['bodyParts:id,name,slug', 'targetMuscles:id,name,slug', 'secondaryMuscles:id,name,slug', 'equipments:id,name,slug'] + (Auth::check() ? ['aliases' => function ($rel) { $rel->where('user_id', Auth::id()); }] : [])) ->when($q !== '', function ($qBuilder) use ($q) { $qBuilder->where(function ($sub) use ($q) { $sub->where('name', 'like', "%{$q}%") ->orWhere('instructions', 'like', "%{$q}%"); }); }) ->when($bodypart !== '', function ($qBuilder) use ($bodypart) { $qBuilder->whereHas('bodyParts', function ($rel) use ($bodypart) { $rel->where('slug', $bodypart); }); }) ->when($muscle !== '', function ($qBuilder) use ($muscle) { $qBuilder->where(function ($sub) use ($muscle) { $sub->whereHas('targetMuscles', function ($rel) use ($muscle) { $rel->where('slug', $muscle); }) ->orWhereHas('secondaryMuscles', function ($rel) use ($muscle) { $rel->where('slug', $muscle); }); }); }) ->when($equipment !== '', function ($qBuilder) use ($equipment) { $qBuilder->whereHas('equipments', function ($rel) use ($equipment) { $rel->where('slug', $equipment); }); }) ->orderBy('name'); $exercises = $query->paginate($perPage)->withQueryString(); return response()->json([ 'data' => ExerciseResource::collection($exercises->items()), 'meta' => [ 'current_page' => $exercises->currentPage(), 'last_page' => $exercises->lastPage(), 'per_page' => $exercises->perPage(), 'total' => $exercises->total(), ], 'filters' => [ 'body_parts' => BodyPart::orderBy('name')->get(['id', 'name', 'slug']), 'muscles' => Muscle::orderBy('name')->get(['id', 'name', 'slug']), 'equipments' => Equipment::orderBy('name')->get(['id', 'name', 'slug']), ], ]); } public function show(Exercise $exercise): JsonResponse { $exercise->load(['bodyParts:id,name,slug', 'targetMuscles:id,name,slug', 'secondaryMuscles:id,name,slug', 'equipments:id,name,slug'] + (Auth::check() ? ['aliases' => function ($rel) { $rel->where('user_id', Auth::id()); }] : [])); $targetIds = $exercise->targetMuscles->pluck('id')->all(); $bodyPartIds = $exercise->bodyParts->pluck('id')->all(); $equipmentIds = $exercise->equipments->pluck('id')->all(); $similarExercises = Exercise::query() ->with(['bodyParts:id,name,slug', 'targetMuscles:id,name,slug', 'equipments:id,name,slug'] + (Auth::check() ? ['aliases' => function ($rel) { $rel->where('user_id', Auth::id()); }] : [])) ->where('id', '!=', $exercise->id) ->where(function ($q) use ($targetIds, $bodyPartIds, $equipmentIds) { if (!empty($targetIds)) { $q->orWhereHas('targetMuscles', fn ($rel) => $rel->whereIn('id', $targetIds)); } if (!empty($bodyPartIds)) { $q->orWhereHas('bodyParts', fn ($rel) => $rel->whereIn('id', $bodyPartIds)); } if (!empty($equipmentIds)) { $q->orWhereHas('equipments', fn ($rel) => $rel->whereIn('id', $equipmentIds)); } }) ->orderBy('name') ->limit(9) ->get(); $personalBest = null; if (Auth::check()) { $personalBest = WorkoutSessionItem::query() ->whereHas('workoutExercise', fn ($q) => $q->where('exercise_id', $exercise->id)) ->whereHas('session', fn ($q) => $q->where('user_id', Auth::id())) ->where('done', true) ->whereNotNull('actual_weight') ->orderByDesc('actual_weight') ->orderByDesc('actual_reps') ->first(); } return response()->json([ 'exercise' => new ExerciseResource($exercise), 'similar_exercises' => ExerciseResource::collection($similarExercises), 'personal_best' => $personalBest ? [ 'actual_weight' => $personalBest->actual_weight !== null ? (float) $personalBest->actual_weight : null, 'actual_reps' => $personalBest->actual_reps, ] : null, ]); } }