Attainly/backend/tests/Fakes/FakeScheduleRepository.php

267 lines
8.5 KiB
PHP

<?php
namespace Tests\Fakes;
use App\Schedule\AssignmentForDate;
use App\Schedule\CreateScheduleDto;
use App\Schedule\RescheduleScheduleDto;
use App\Schedule\Schedule;
use App\Schedule\ScheduleAssignment;
use App\Schedule\ScheduleRepository;
use App\User\User;
use DateTimeImmutable;
use DomainException;
class FakeScheduleRepository implements ScheduleRepository
{
/**
* @var array<int, Schedule>
*/
private array $schedules = [];
private int $nextAssignmentId = 1;
public function create(CreateScheduleDto $dto): Schedule
{
$id = count($this->schedules) + 1;
$assignments = [];
foreach ($dto->assignments as $assignmentDto) {
$assignments[] = new ScheduleAssignment(
id: $this->nextAssignmentId++,
name: $assignmentDto->name,
kind: $assignmentDto->kind,
path: $assignmentDto->path,
scheduledDate: $assignmentDto->scheduledDate,
position: $assignmentDto->position,
completedAt: null,
);
}
$schedule = new Schedule(
id: $id,
user: $dto->user,
setName: $dto->setName,
elementKind: $dto->elementKind,
startDate: $dto->startDate,
targetDate: $dto->targetDate,
assignments: $assignments,
);
$this->schedules[$id] = $schedule;
return $this->copy($schedule);
}
public function reschedule(RescheduleScheduleDto $dto): Schedule
{
$schedule = $this->schedules[$dto->scheduleId] ?? null;
if ($schedule === null || $schedule->getUser()->getId()
!== $dto->user->getId()
) {
throw new DomainException(
"Schedule with id {$dto->scheduleId} not found",
);
}
$datesByAssignmentId = [];
foreach ($dto->assignments as $assignmentDto) {
$datesByAssignmentId[$assignmentDto->id] =
$assignmentDto->scheduledDate;
}
$assignments = [];
foreach ($schedule->getAssignments() as $assignment) {
$assignments[] = new ScheduleAssignment(
id: $assignment->getId(),
name: $assignment->getName(),
kind: $assignment->getKind(),
path: $assignment->getPath(),
scheduledDate: $datesByAssignmentId[$assignment->getId()]
?? $assignment->getScheduledDate(),
position: $assignment->getPosition(),
completedAt: $assignment->getCompletedAt(),
);
}
$rescheduled = new Schedule(
id: $schedule->getId(),
user: $schedule->getUser(),
setName: $schedule->getSetName(),
elementKind: $schedule->getElementKind(),
startDate: $dto->startDate,
targetDate: $dto->targetDate,
assignments: $assignments,
);
$this->schedules[$dto->scheduleId] = $rescheduled;
return $this->copy($rescheduled);
}
public function findForUser(int $id, User $user): ?Schedule
{
$schedule = $this->schedules[$id] ?? null;
if ($schedule === null || $schedule->getUser()->getId()
!== $user->getId()
) {
return null;
}
return $this->copy($schedule);
}
public function findAllForUser(User $user): array
{
$schedules = array_filter(
$this->schedules,
function (Schedule $schedule) use ($user): bool {
return $schedule->getUser()->getId() === $user->getId();
},
);
krsort($schedules);
return array_map(function (Schedule $schedule): Schedule {
return $this->copy($schedule);
}, array_values($schedules));
}
public function findIncompleteAssignmentsForUserDueOnOrBefore(
User $user,
DateTimeImmutable $date,
): array {
$assignments = [];
foreach ($this->findAllForUser($user) as $schedule) {
foreach ($schedule->getAssignments() as $assignment) {
if ($assignment->getScheduledDate() > $date
|| $assignment->getCompletedAt() !== null
) {
continue;
}
$assignments[] = new AssignmentForDate(
scheduleId: $schedule->getId(),
setName: $schedule->getSetName(),
assignment: $assignment,
);
}
}
usort(
$assignments,
function (
AssignmentForDate $first,
AssignmentForDate $second,
): int {
$firstAssignment = $first->getAssignment();
$secondAssignment = $second->getAssignment();
$dateComparison = $firstAssignment->getScheduledDate()
<=> $secondAssignment->getScheduledDate();
if ($dateComparison !== 0) {
return $dateComparison;
}
$scheduleComparison = $second->getScheduleId()
<=> $first->getScheduleId();
if ($scheduleComparison !== 0) {
return $scheduleComparison;
}
$positionComparison = $firstAssignment->getPosition()
<=> $secondAssignment->getPosition();
if ($positionComparison !== 0) {
return $positionComparison;
}
return $firstAssignment->getId()
<=> $secondAssignment->getId();
},
);
return $assignments;
}
public function findAssignmentForUser(
int $id,
User $user,
): ?ScheduleAssignment {
foreach ($this->findAllForUser($user) as $schedule) {
foreach ($schedule->getAssignments() as $assignment) {
if ($assignment->getId() === $id) {
return $this->copyAssignment($assignment);
}
}
}
return null;
}
public function updateAssignment(
ScheduleAssignment $assignment,
): ScheduleAssignment {
foreach ($this->schedules as $id => $schedule) {
$assignments = [];
$found = false;
foreach ($schedule->getAssignments() as $storedAssignment) {
if ($storedAssignment->getId() === $assignment->getId()) {
$assignments[] = $this->copyAssignment($assignment);
$found = true;
} else {
$assignments[] = $this->copyAssignment(
$storedAssignment,
);
}
}
if ($found) {
$this->schedules[$id] = new Schedule(
id: $schedule->getId(),
user: $schedule->getUser(),
setName: $schedule->getSetName(),
elementKind: $schedule->getElementKind(),
startDate: $schedule->getStartDate(),
targetDate: $schedule->getTargetDate(),
assignments: $assignments,
);
return $this->copyAssignment($assignment);
}
}
throw new DomainException(
"Assignment with id {$assignment->getId()} not found",
);
}
private function copy(Schedule $schedule): Schedule
{
$assignments = array_map(function (
ScheduleAssignment $assignment,
): ScheduleAssignment {
return $this->copyAssignment($assignment);
}, $schedule->getAssignments());
return new Schedule(
id: $schedule->getId(),
user: $schedule->getUser(),
setName: $schedule->getSetName(),
elementKind: $schedule->getElementKind(),
startDate: $schedule->getStartDate(),
targetDate: $schedule->getTargetDate(),
assignments: $assignments,
);
}
private function copyAssignment(
ScheduleAssignment $assignment,
): ScheduleAssignment {
return new ScheduleAssignment(
id: $assignment->getId(),
name: $assignment->getName(),
kind: $assignment->getKind(),
path: $assignment->getPath(),
scheduledDate: $assignment->getScheduledDate(),
position: $assignment->getPosition(),
completedAt: $assignment->getCompletedAt(),
);
}
}