Files
fitness/app/Http/Controllers/Api/WorkoutController.php
T
2026-08-10 19:18:25 +03:00

210 lines
6.7 KiB
PHP

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Resources\ExerciseResource;
use App\Http\Resources\WorkoutExerciseResource;
use App\Http\Resources\WorkoutResource;
use App\Models\Exercise;
use App\Models\Workout;
use App\Models\WorkoutExercise;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class WorkoutController extends Controller
{
public function index(): JsonResponse
{
$workouts = Auth::user()->workouts()->with('assignedByTrainer')->latest()->paginate(10);
return $this->paginated($workouts);
}
public function community(Request $request): JsonResponse
{
$q = trim((string) $request->query('q', ''));
$workouts = Workout::query()
->where('is_public', true)
->with(['user:id,name', 'items'])
->when($q !== '', fn ($qb) => $qb->where('title', 'like', "%{$q}%"))
->latest()
->paginate(12)
->withQueryString();
return $this->paginated($workouts);
}
public function store(Request $request): JsonResponse
{
$data = $request->validate([
'title' => 'required|string|max:255',
'notes' => 'nullable|string',
'estimated_minutes' => 'nullable|integer|min:1|max:600',
]);
$workout = Auth::user()->workouts()->create($data);
return response()->json(['workout' => new WorkoutResource($workout)], 201);
}
public function show(Workout $workout): JsonResponse
{
$this->authorizeView($workout);
$workout->load(['items.exercise', 'assignedByTrainer', 'user:id,name']);
return response()->json(['workout' => new WorkoutResource($workout)]);
}
public function searchExercises(Request $request, Workout $workout): JsonResponse
{
$this->authorizeWorkout($workout);
$q = trim((string) $request->query('q', ''));
$exercises = Exercise::query()
->with(['aliases' => fn ($rel) => $rel->where('user_id', Auth::id())])
->when($q !== '', fn ($qb) => $qb->where('name', 'like', "%{$q}%"))
->orderBy('name')
->limit(20)
->get(['id', 'name']);
return response()->json(ExerciseResource::collection($exercises));
}
public function togglePublic(Workout $workout): JsonResponse
{
if ($workout->user_id !== Auth::id()) {
abort(403);
}
$workout->is_public = !$workout->is_public;
$workout->save();
return response()->json(['workout' => new WorkoutResource($workout)]);
}
public function copy(Workout $workout): JsonResponse
{
if (!$workout->is_public && $workout->user_id !== Auth::id()) {
abort(403);
}
$workout->loadMissing('items');
$copy = Auth::user()->workouts()->create([
'title' => $workout->title.' (copy)',
'notes' => $workout->notes,
'estimated_minutes' => $workout->estimated_minutes,
]);
foreach ($workout->items as $item) {
$copy->items()->create([
'exercise_id' => $item->exercise_id,
'position' => $item->position,
'sets' => $item->sets,
'reps' => $item->reps,
'weight' => $item->weight,
'rest_seconds' => $item->rest_seconds,
'notes' => $item->notes,
]);
}
$copy->load(['items.exercise']);
return response()->json(['workout' => new WorkoutResource($copy)], 201);
}
public function addExercise(Request $request, Workout $workout): JsonResponse
{
$this->authorizeWorkout($workout);
$data = $request->validate([
'exercise_id' => 'required|exists:exercises,id',
'position' => 'nullable|integer|min:1',
'sets' => 'nullable|integer|min:1|max:20',
'reps' => 'nullable|integer|min:1|max:200',
'weight' => 'nullable|numeric|min:0|max:999.99',
'rest_seconds' => 'nullable|integer|min:0|max:600',
'notes' => 'nullable|string',
]);
$nextPos = ($workout->items()->max('position') ?? 0) + 1;
$data['position'] = $data['position'] ?? $nextPos;
$item = $workout->items()->create($data);
$item->load('exercise');
return response()->json(['item' => new WorkoutExerciseResource($item)], 201);
}
public function updateExercise(Request $request, Workout $workout, WorkoutExercise $item): JsonResponse
{
$this->authorizeWorkout($workout);
if ($item->workout_id !== $workout->id) {
abort(404);
}
$data = $request->validate([
'position' => 'nullable|integer|min:1',
'sets' => 'nullable|integer|min:1|max:20',
'reps' => 'nullable|integer|min:1|max:200',
'weight' => 'nullable|numeric|min:0|max:999.99',
'rest_seconds' => 'nullable|integer|min:0|max:600',
'notes' => 'nullable|string',
]);
$item->update($data);
$item->load('exercise');
return response()->json(['item' => new WorkoutExerciseResource($item)]);
}
public function removeExercise(Workout $workout, WorkoutExercise $item): JsonResponse
{
$this->authorizeWorkout($workout);
if ($item->workout_id !== $workout->id) {
abort(404);
}
$item->delete();
return response()->json(['message' => 'Exercise removed']);
}
public function destroy(Workout $workout): JsonResponse
{
if ($workout->user_id !== Auth::id()) {
abort(403);
}
$workout->delete();
return response()->json(['message' => 'Workout deleted']);
}
protected function authorizeWorkout(Workout $workout): void
{
if ($workout->user_id === Auth::id()) {
return;
}
if ($workout->assigned_by_trainer_id && $workout->assigned_by_trainer_id === Auth::id()) {
return;
}
abort(403);
}
protected function authorizeView(Workout $workout): void
{
if ($workout->is_public) {
return;
}
$this->authorizeWorkout($workout);
}
protected function paginated($paginator): JsonResponse
{
return response()->json([
'data' => WorkoutResource::collection($paginator->items()),
'meta' => [
'current_page' => $paginator->currentPage(),
'last_page' => $paginator->lastPage(),
'per_page' => $paginator->perPage(),
'total' => $paginator->total(),
],
]);
}
}