Files
haushalt/backend/src/Service/TaskSynchronizer.php
Marek Lenczewski 7b58e68ecb update
2026-03-30 23:08:24 +02:00

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);
}
}
}
}