Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace Functional\Tracking\Services;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Functional\Tracking\Enums\WorkoutSessionStatus;
|
||||
use Functional\Tracking\Exceptions\WorkoutSessionAlreadyClosedException;
|
||||
use Functional\Tracking\Models\SetLog;
|
||||
use Functional\Tracking\Models\WorkoutSession;
|
||||
use Functional\Users\Models\User;
|
||||
|
||||
/**
|
||||
* Cycle de vie d'une séance d'entraînement : démarrage, log de sets, complétion.
|
||||
* La complétion sauvegarde le statut "completed", ce qui déclenche WorkoutCompleted
|
||||
* (écouté par la couche streaks pour recalculer le streak de l'utilisateur).
|
||||
*/
|
||||
class WorkoutSessionService
|
||||
{
|
||||
public function start(User $user, array $data): WorkoutSession
|
||||
{
|
||||
return WorkoutSession::create([
|
||||
'user_id' => $user->id,
|
||||
'routine_id' => $data['routine_id'] ?? null,
|
||||
'title' => $data['title'] ?? null,
|
||||
'started_at' => now(),
|
||||
'status' => WorkoutSessionStatus::Active,
|
||||
]);
|
||||
}
|
||||
|
||||
public function logSet(WorkoutSession $session, array $data): SetLog
|
||||
{
|
||||
if ($session->status->isTerminal()) {
|
||||
throw new WorkoutSessionAlreadyClosedException($session->id);
|
||||
}
|
||||
|
||||
return $session->setLogs()->create([
|
||||
'exercise_id' => $data['exercise_id'],
|
||||
'set_number' => $data['set_number'],
|
||||
'reps' => $data['reps'] ?? null,
|
||||
'weight' => $data['weight'] ?? null,
|
||||
'rpe' => $data['rpe'] ?? null,
|
||||
'duration_seconds' => $data['duration_seconds'] ?? null,
|
||||
'distance_meters' => $data['distance_meters'] ?? null,
|
||||
'is_warmup' => $data['is_warmup'] ?? false,
|
||||
'is_completed' => true,
|
||||
'logged_at' => now(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function complete(WorkoutSession $session, array $data): WorkoutSession
|
||||
{
|
||||
if ($session->status->isTerminal()) {
|
||||
throw new WorkoutSessionAlreadyClosedException($session->id);
|
||||
}
|
||||
|
||||
$session->ended_at = isset($data['ended_at']) ? Carbon::parse($data['ended_at']) : now();
|
||||
$session->total_volume = $this->calculateTotalVolume($session);
|
||||
$session->status = WorkoutSessionStatus::Completed;
|
||||
$session->save(); // déclenche WorkoutCompleted (recalcul du streak, couche streaks)
|
||||
|
||||
return $session->fresh('setLogs');
|
||||
}
|
||||
|
||||
/** Volume total = somme(reps * poids) des séries effectives (hors échauffement). */
|
||||
private function calculateTotalVolume(WorkoutSession $session): float
|
||||
{
|
||||
return (float) $session->setLogs()
|
||||
->where('is_warmup', false)
|
||||
->get()
|
||||
->sum(fn (SetLog $setLog) => (float) ($setLog->reps ?? 0) * (float) ($setLog->weight ?? 0));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user