Attainly/backend/app/Http/Controllers/ScheduleController.php

273 lines
8.3 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Exceptions\BadRequestException;
use App\Exceptions\NotFoundException;
use App\Schedule\AssignmentForDate;
use App\Schedule\Schedule;
use App\Schedule\ScheduleAssignment;
use App\Schedule\UseCases\CreateSchedule\CreateSchedule;
use App\Schedule\UseCases\CreateSchedule\CreateScheduleRequest;
use App\Schedule\UseCases\GetSchedule\GetSchedule;
use App\Schedule\UseCases\GetSchedule\GetScheduleRequest;
use App\Schedule\UseCases\ListSchedules\ListSchedules;
use App\Schedule\UseCases\ListAssignmentsForDate\ListAssignmentsForDate;
use App\Schedule\UseCases\ListAssignmentsForDate\ListAssignmentsForDateRequest;
use App\Schedule\UseCases\SetAssignmentCompletion\SetAssignmentCompletion;
use App\Schedule\UseCases\SetAssignmentCompletion\SetAssignmentCompletionRequest;
use App\Shared\Http\RequestInput;
use App\User\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ScheduleController extends Controller
{
public function __construct(
private CreateSchedule $createSchedule,
private ListSchedules $listSchedules,
private GetSchedule $getSchedule,
private ListAssignmentsForDate $listAssignmentsForDate,
private SetAssignmentCompletion $setAssignmentCompletion,
) {}
public function store(Request $request): JsonResponse
{
$input = new RequestInput($request);
$user = $this->user($request);
try {
$schedule = $this->createSchedule->execute(
new CreateScheduleRequest(
user: $user,
setId: $input->integer('setId'),
levelId: $input->integer('levelId'),
startDate: $input->string('startDate'),
targetDate: $input->string('targetDate'),
),
);
} catch (BadRequestException $exception) {
return new JsonResponse(
['error' => $exception->getMessage()],
400,
);
} catch (NotFoundException $exception) {
return new JsonResponse(
['error' => $exception->getMessage()],
404,
);
}
return new JsonResponse(
['schedule' => $this->detailPayload($schedule)],
201,
);
}
public function index(Request $request): JsonResponse
{
$schedules = array_map(
function (Schedule $schedule): array {
return $this->summaryPayload($schedule);
},
$this->listSchedules->execute($this->user($request)),
);
return new JsonResponse(['schedules' => $schedules]);
}
public function show(Request $request, int $scheduleId): JsonResponse
{
try {
$schedule = $this->getSchedule->execute(
new GetScheduleRequest(
scheduleId: $scheduleId,
user: $this->user($request),
),
);
} catch (NotFoundException $exception) {
return new JsonResponse(
['error' => $exception->getMessage()],
404,
);
}
return new JsonResponse([
'schedule' => $this->detailPayload($schedule),
]);
}
public function assignments(Request $request): JsonResponse
{
$input = new RequestInput($request);
$date = $input->string('date');
try {
$assignments = $this->listAssignmentsForDate->execute(
new ListAssignmentsForDateRequest(
user: $this->user($request),
date: $date,
),
);
} catch (BadRequestException $exception) {
return new JsonResponse(
['error' => $exception->getMessage()],
400,
);
}
return new JsonResponse([
'date' => $date,
'assignments' => array_map(
function (AssignmentForDate $assignment): array {
return $this->assignmentForDatePayload($assignment);
},
$assignments,
),
]);
}
public function updateAssignment(
Request $request,
int $assignmentId,
): JsonResponse {
$input = new RequestInput($request);
try {
$assignment = $this->setAssignmentCompletion->execute(
new SetAssignmentCompletionRequest(
assignmentId: $assignmentId,
user: $this->user($request),
completed: $input->boolean('completed'),
),
);
} catch (BadRequestException $exception) {
return new JsonResponse(
['error' => $exception->getMessage()],
400,
);
} catch (NotFoundException $exception) {
return new JsonResponse(
['error' => $exception->getMessage()],
404,
);
}
return new JsonResponse([
'assignment' => [
'id' => $assignment->getId(),
'completedAt' => $assignment->getCompletedAt()
?->format(DATE_ATOM),
],
]);
}
/**
* @return array<string, mixed>
*/
private function summaryPayload(Schedule $schedule): array
{
return [
'id' => $schedule->getId(),
'set' => [
'name' => $schedule->getSetName(),
],
'elementKind' => $schedule->getElementKind(),
'startDate' => $schedule->getStartDate()->format('Y-m-d'),
'targetDate' => $schedule->getTargetDate()->format('Y-m-d'),
'assignmentCount' => count($schedule->getAssignments()),
];
}
/**
* @return array<string, mixed>
*/
private function detailPayload(Schedule $schedule): array
{
$payload = $this->summaryPayload($schedule);
$payload['days'] = $this->dayPayloads($schedule);
return $payload;
}
/**
* @return list<array{date: string, assignments: list<mixed>}>
*/
private function dayPayloads(Schedule $schedule): array
{
$assignmentsByDate = [];
foreach ($schedule->getAssignments() as $assignment) {
$date = $assignment->getScheduledDate()->format('Y-m-d');
$assignmentsByDate[$date][] = $this->assignmentPayload(
$assignment,
);
}
$days = [];
$date = $schedule->getStartDate();
while ($date <= $schedule->getTargetDate()) {
$formattedDate = $date->format('Y-m-d');
$days[] = [
'date' => $formattedDate,
'assignments' => $assignmentsByDate[$formattedDate] ?? [],
];
$date = $date->modify('+1 day');
}
return $days;
}
/**
* @return array{id: int, completedAt: string|null, element: array{
* name: string,
* kind: string,
* path: list<string>
* }}
*/
private function assignmentPayload(
ScheduleAssignment $assignment,
): array {
return [
'id' => $assignment->getId(),
'completedAt' => $assignment->getCompletedAt()
?->format(DATE_ATOM),
'element' => [
'name' => $assignment->getName(),
'kind' => $assignment->getKind(),
'path' => $assignment->getPath(),
],
];
}
/**
* @return array<string, mixed>
*/
private function assignmentForDatePayload(
AssignmentForDate $assignmentForDate,
): array {
$assignment = $assignmentForDate->getAssignment();
return [
'id' => $assignment->getId(),
'schedule' => [
'id' => $assignmentForDate->getScheduleId(),
'set' => [
'name' => $assignmentForDate->getSetName(),
],
],
'element' => [
'name' => $assignment->getName(),
'kind' => $assignment->getKind(),
'path' => $assignment->getPath(),
],
];
}
private function user(Request $request): User
{
/** @var User $user */
$user = $request->attributes->get('user');
return $user;
}
}