125 lines
3.8 KiB
PHP
125 lines
3.8 KiB
PHP
<?php
|
|
|
|
namespace App\Service;
|
|
|
|
use App\Entity\Task;
|
|
use App\Entity\TaskSchema;
|
|
use App\Enum\TaskSchemaType;
|
|
use App\Repository\TaskRepository;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
|
|
class TaskSynchronizer
|
|
{
|
|
public function __construct(
|
|
private EntityManagerInterface $em,
|
|
private TaskRepository $taskRepository,
|
|
private DeadlineCalculator $deadlineCalculator,
|
|
) {}
|
|
|
|
public function syncForSchema(TaskSchema $schema): void
|
|
{
|
|
$today = new \DateTimeImmutable('today');
|
|
$end = $this->calculateSyncEnd($schema, $today);
|
|
|
|
$deadlines = $this->deadlineCalculator->getDeadlinesForRange($schema, $today, $end);
|
|
$shouldExist = [];
|
|
foreach ($deadlines as $deadline) {
|
|
$shouldExist[$deadline->format('Y-m-d')] = true;
|
|
}
|
|
|
|
$existingByDate = $this->loadExistingByDate($schema, $today);
|
|
|
|
$this->removeObsoleteTasks($existingByDate, $shouldExist);
|
|
$this->handleNullDateTasks($schema);
|
|
$this->resetFutureOverrides($existingByDate);
|
|
$this->createMissingTasks($schema, $deadlines, $existingByDate);
|
|
|
|
$this->em->flush();
|
|
}
|
|
|
|
private function calculateSyncEnd(TaskSchema $schema, \DateTimeImmutable $today): \DateTimeImmutable
|
|
{
|
|
$minEnd = $today->modify('+6 days');
|
|
$end = $schema->getEndDate()
|
|
? new \DateTimeImmutable($schema->getEndDate()->format('Y-m-d'))
|
|
: $minEnd;
|
|
|
|
return $end < $minEnd ? $minEnd : $end;
|
|
}
|
|
|
|
/**
|
|
* @return array<string, Task>
|
|
*/
|
|
private function loadExistingByDate(TaskSchema $schema, \DateTimeImmutable $today): array
|
|
{
|
|
$futureTasks = $this->taskRepository->findBySchemaFromDate($schema, $today);
|
|
$existingByDate = [];
|
|
foreach ($futureTasks as $task) {
|
|
$existingByDate[$task->getDate()->format('Y-m-d')] = $task;
|
|
}
|
|
|
|
return $existingByDate;
|
|
}
|
|
|
|
/**
|
|
* @param array<string, Task> $existingByDate
|
|
* @param array<string, true> $shouldExist
|
|
*/
|
|
private function removeObsoleteTasks(array &$existingByDate, array $shouldExist): void
|
|
{
|
|
foreach ($existingByDate as $dateKey => $task) {
|
|
if (!isset($shouldExist[$dateKey])) {
|
|
$this->em->remove($task);
|
|
unset($existingByDate[$dateKey]);
|
|
}
|
|
}
|
|
}
|
|
|
|
private function handleNullDateTasks(TaskSchema $schema): void
|
|
{
|
|
$nullDateTasks = $this->taskRepository->findBy(['schema' => $schema, 'date' => null]);
|
|
|
|
if ($schema->getTaskType() === TaskSchemaType::Single && $schema->getDeadline() === null) {
|
|
foreach ($nullDateTasks as $task) {
|
|
$task->setName(null);
|
|
$task->setCategory(null);
|
|
$task->setCategoryOverridden(false);
|
|
}
|
|
} else {
|
|
foreach ($nullDateTasks as $task) {
|
|
$this->em->remove($task);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array<string, Task> $existingByDate
|
|
*/
|
|
private function resetFutureOverrides(array $existingByDate): void
|
|
{
|
|
foreach ($existingByDate as $task) {
|
|
$task->setName(null);
|
|
$task->setCategory(null);
|
|
$task->setCategoryOverridden(false);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param \DateTimeInterface[] $deadlines
|
|
* @param array<string, Task> $existingByDate
|
|
*/
|
|
private function createMissingTasks(TaskSchema $schema, array $deadlines, array $existingByDate): void
|
|
{
|
|
foreach ($deadlines as $deadline) {
|
|
$dateKey = $deadline->format('Y-m-d');
|
|
if (!isset($existingByDate[$dateKey])) {
|
|
$task = new Task();
|
|
$task->setSchema($schema);
|
|
$task->setDate(new \DateTime($dateKey));
|
|
|
|
$this->em->persist($task);
|
|
}
|
|
}
|
|
}
|
|
}
|