update
This commit is contained in:
@@ -20,7 +20,7 @@ class TaskGenerator
|
||||
|
||||
public function generateForRange(\DateTimeInterface $from, \DateTimeInterface $to): void
|
||||
{
|
||||
$schemas = $this->schemaRepository->findActiveTasksInRange($from, $to);
|
||||
$schemas = $this->schemaRepository->findActiveSchemasInRange($from, $to);
|
||||
$existingKeys = $this->taskRepository->getExistingKeys($from, $to);
|
||||
|
||||
$hasNew = false;
|
||||
@@ -60,10 +60,10 @@ class TaskGenerator
|
||||
foreach ($schemas as $schema) {
|
||||
$existing = $this->taskRepository->findOneBy(['schema' => $schema]);
|
||||
if (!$existing) {
|
||||
$occ = new Task();
|
||||
$occ->setSchema($schema);
|
||||
$occ->setDate(null);
|
||||
$this->em->persist($occ);
|
||||
$task = new Task();
|
||||
$task->setSchema($schema);
|
||||
$task->setDate(null);
|
||||
$this->em->persist($task);
|
||||
$hasNew = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,18 +2,25 @@
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\DTO\Request\ToggleRequest;
|
||||
use App\DTO\Request\UpdateTaskRequest;
|
||||
use App\DTO\Response\TaskResponse;
|
||||
use App\Entity\Task;
|
||||
use App\DTO\Response\ToggleResponse;
|
||||
use App\Entity\TaskSchema;
|
||||
use App\Enum\TaskSchemaStatus;
|
||||
use App\Enum\TaskStatus;
|
||||
use App\Entity\Task;
|
||||
use App\Repository\CategoryRepository;
|
||||
use App\Repository\TaskRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
class TaskManager
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $em,
|
||||
private CategoryRepository $categoryRepository,
|
||||
private TaskRepository $taskRepository,
|
||||
private TaskSerializer $taskSerializer,
|
||||
) {}
|
||||
|
||||
@@ -39,6 +46,29 @@ class TaskManager
|
||||
return $this->taskSerializer->serializeTask($task, new \DateTimeImmutable('today'));
|
||||
}
|
||||
|
||||
public function toggleTaskStatus(TaskSchema $schema, ToggleRequest $request): ToggleResponse
|
||||
{
|
||||
if ($schema->getStatus() === TaskSchemaStatus::Inactive) {
|
||||
throw new HttpException(422, 'Inaktive Aufgaben können nicht umgeschaltet werden.');
|
||||
}
|
||||
|
||||
$task = $request->date !== null
|
||||
? $this->taskRepository->findBySchemaAndDate($schema, new \DateTime($request->date))
|
||||
: $this->taskRepository->findOneBy(['schema' => $schema, 'date' => null]);
|
||||
|
||||
if (!$task) {
|
||||
throw new HttpException(404, 'Task nicht gefunden.');
|
||||
}
|
||||
|
||||
$newStatus = $task->getStatus() === TaskStatus::Active
|
||||
? TaskStatus::Completed
|
||||
: TaskStatus::Active;
|
||||
$task->setStatus($newStatus);
|
||||
$this->em->flush();
|
||||
|
||||
return new ToggleResponse(completed: $newStatus === TaskStatus::Completed);
|
||||
}
|
||||
|
||||
public function deleteTask(Task $task): void
|
||||
{
|
||||
$this->em->remove($task);
|
||||
|
||||
@@ -3,53 +3,27 @@
|
||||
namespace App\Service;
|
||||
|
||||
use App\DTO\Request\CreateSchemaRequest;
|
||||
use App\DTO\Request\ToggleRequest;
|
||||
use App\DTO\Request\UpdateSchemaRequest;
|
||||
use App\DTO\Response\ToggleResponse;
|
||||
use App\Entity\TaskSchema;
|
||||
use App\Enum\TaskSchemaStatus;
|
||||
use App\Enum\TaskSchemaType;
|
||||
use App\Enum\TaskStatus;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use App\Repository\CategoryRepository;
|
||||
use App\Repository\TaskRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
class TaskSchemaManager
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $em,
|
||||
private CategoryRepository $categoryRepository,
|
||||
private TaskRepository $taskRepository,
|
||||
private TaskSynchronizer $taskSynchronizer,
|
||||
) {}
|
||||
|
||||
public function createSchema(CreateSchemaRequest $request): TaskSchema
|
||||
{
|
||||
$schema = new TaskSchema();
|
||||
|
||||
$schema->setName($request->name ?? '');
|
||||
|
||||
if ($request->status !== null) {
|
||||
$status = TaskSchemaStatus::tryFrom($request->status);
|
||||
if ($status !== null) {
|
||||
$schema->setStatus($status);
|
||||
}
|
||||
}
|
||||
|
||||
if ($request->taskType !== null) {
|
||||
$taskType = TaskSchemaType::tryFrom($request->taskType);
|
||||
if ($taskType !== null) {
|
||||
$schema->setTaskType($taskType);
|
||||
}
|
||||
}
|
||||
|
||||
$schema->setDeadline($request->deadline !== null ? new \DateTime($request->deadline) : null);
|
||||
$schema->setStartDate($request->startDate !== null ? new \DateTime($request->startDate) : null);
|
||||
$schema->setEndDate($request->endDate !== null ? new \DateTime($request->endDate) : null);
|
||||
$schema->setWeekdays($request->weekdays);
|
||||
$schema->setMonthDays($request->monthDays);
|
||||
$schema->setYearDays($request->yearDays);
|
||||
|
||||
$this->applyFields($schema, $request);
|
||||
$this->resolveCategory($schema, $request);
|
||||
$this->applyDefaults($schema);
|
||||
|
||||
@@ -65,6 +39,19 @@ class TaskSchemaManager
|
||||
$schema->setName($request->name);
|
||||
}
|
||||
|
||||
$this->applyFields($schema, $request);
|
||||
$this->resolveCategory($schema, $request);
|
||||
$this->applyDefaults($schema);
|
||||
|
||||
$this->em->flush();
|
||||
|
||||
$this->taskSynchronizer->syncForSchema($schema);
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
private function applyFields(TaskSchema $schema, CreateSchemaRequest|UpdateSchemaRequest $request): void
|
||||
{
|
||||
if ($request->status !== null) {
|
||||
$status = TaskSchemaStatus::tryFrom($request->status);
|
||||
if ($status !== null) {
|
||||
@@ -85,40 +72,6 @@ class TaskSchemaManager
|
||||
$schema->setWeekdays($request->weekdays);
|
||||
$schema->setMonthDays($request->monthDays);
|
||||
$schema->setYearDays($request->yearDays);
|
||||
|
||||
$this->resolveCategory($schema, $request);
|
||||
$this->applyDefaults($schema);
|
||||
|
||||
$this->em->flush();
|
||||
|
||||
// Sync: delete what no longer fits, create what's missing
|
||||
$this->taskSynchronizer->syncForSchema($schema);
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
public function toggleTaskStatus(TaskSchema $schema, ToggleRequest $request): ToggleResponse
|
||||
{
|
||||
if ($schema->getStatus() === TaskSchemaStatus::Inactive) {
|
||||
throw new HttpException(422, 'Inaktive Aufgaben können nicht umgeschaltet werden.');
|
||||
}
|
||||
|
||||
// Find the task
|
||||
$task = $request->date !== null
|
||||
? $this->taskRepository->findByTaskAndDate($schema, new \DateTime($request->date))
|
||||
: $this->taskRepository->findOneBy(['schema' => $schema, 'date' => null]);
|
||||
|
||||
if (!$task) {
|
||||
throw new HttpException(404, 'Task nicht gefunden.');
|
||||
}
|
||||
|
||||
$newStatus = $task->getStatus() === TaskStatus::Active
|
||||
? TaskStatus::Completed
|
||||
: TaskStatus::Active;
|
||||
$task->setStatus($newStatus);
|
||||
$this->em->flush();
|
||||
|
||||
return new ToggleResponse(completed: $newStatus === TaskStatus::Completed);
|
||||
}
|
||||
|
||||
private function resolveCategory(TaskSchema $schema, UpdateSchemaRequest|CreateSchemaRequest $request): void
|
||||
|
||||
@@ -19,74 +19,106 @@ class TaskSynchronizer
|
||||
public function syncForSchema(TaskSchema $schema): void
|
||||
{
|
||||
$today = new \DateTimeImmutable('today');
|
||||
$end = $this->calculateSyncEnd($schema, $today);
|
||||
|
||||
// Range: bis endDate oder mindestens +6 Tage
|
||||
$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;
|
||||
if ($end < $minEnd) {
|
||||
$end = $minEnd;
|
||||
}
|
||||
|
||||
// Soll-Termine berechnen
|
||||
$deadlines = $this->deadlineCalculator->getDeadlinesForRange($schema, $today, $end);
|
||||
$shouldExist = [];
|
||||
foreach ($deadlines as $dl) {
|
||||
$shouldExist[$dl->format('Y-m-d')] = true;
|
||||
}
|
||||
return $end < $minEnd ? $minEnd : $end;
|
||||
}
|
||||
|
||||
// Alle zukünftigen Tasks laden (mit Datum)
|
||||
$futureTasks = $this->taskRepository->findByTaskFromDate($schema, $today);
|
||||
/**
|
||||
* @return array<string, Task>
|
||||
*/
|
||||
private function loadExistingByDate(TaskSchema $schema, \DateTimeImmutable $today): array
|
||||
{
|
||||
$futureTasks = $this->taskRepository->findBySchemaFromDate($schema, $today);
|
||||
$existingByDate = [];
|
||||
foreach ($futureTasks as $occ) {
|
||||
$existingByDate[$occ->getDate()->format('Y-m-d')] = $occ;
|
||||
foreach ($futureTasks as $task) {
|
||||
$existingByDate[$task->getDate()->format('Y-m-d')] = $task;
|
||||
}
|
||||
|
||||
// Null-Datum Tasks laden
|
||||
$nullDateTasks = $this->taskRepository->findBy(['schema' => $schema, 'date' => null]);
|
||||
return $existingByDate;
|
||||
}
|
||||
|
||||
// Nicht mehr im Schema -> entfernen
|
||||
foreach ($existingByDate as $dateKey => $occ) {
|
||||
/**
|
||||
* @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($occ);
|
||||
$this->em->remove($task);
|
||||
unset($existingByDate[$dateKey]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function handleNullDateTasks(TaskSchema $schema): void
|
||||
{
|
||||
$nullDateTasks = $this->taskRepository->findBy(['schema' => $schema, 'date' => null]);
|
||||
|
||||
// Einzel ohne Deadline: null-date Task behalten
|
||||
if ($schema->getTaskType() === TaskSchemaType::Single && $schema->getDeadline() === null) {
|
||||
foreach ($nullDateTasks as $occ) {
|
||||
$occ->setName(null);
|
||||
$occ->setCategory(null);
|
||||
$occ->setCategoryOverridden(false);
|
||||
foreach ($nullDateTasks as $task) {
|
||||
$task->setName(null);
|
||||
$task->setCategory(null);
|
||||
$task->setCategoryOverridden(false);
|
||||
}
|
||||
} else {
|
||||
// Sonst null-date Tasks entfernen
|
||||
foreach ($nullDateTasks as $occ) {
|
||||
$this->em->remove($occ);
|
||||
foreach ($nullDateTasks as $task) {
|
||||
$this->em->remove($task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bestehende zukünftige Overrides zurücksetzen
|
||||
foreach ($existingByDate as $occ) {
|
||||
$occ->setName(null);
|
||||
$occ->setCategory(null);
|
||||
$occ->setCategoryOverridden(false);
|
||||
/**
|
||||
* @param array<string, Task> $existingByDate
|
||||
*/
|
||||
private function resetFutureOverrides(array $existingByDate): void
|
||||
{
|
||||
foreach ($existingByDate as $task) {
|
||||
$task->setName(null);
|
||||
$task->setCategory(null);
|
||||
$task->setCategoryOverridden(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Fehlende Tasks erstellen
|
||||
foreach ($deadlines as $dl) {
|
||||
$dateKey = $dl->format('Y-m-d');
|
||||
/**
|
||||
* @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])) {
|
||||
$occ = new Task();
|
||||
$occ->setSchema($schema);
|
||||
$occ->setDate(new \DateTime($dateKey));
|
||||
$task = new Task();
|
||||
$task->setSchema($schema);
|
||||
$task->setDate(new \DateTime($dateKey));
|
||||
|
||||
$this->em->persist($occ);
|
||||
$this->em->persist($task);
|
||||
}
|
||||
}
|
||||
|
||||
$this->em->flush();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user