update
This commit is contained in:
@@ -5,7 +5,6 @@ namespace App\Controller\Api;
|
||||
use App\DTO\Request\UpdateTaskRequest;
|
||||
use App\Entity\Task;
|
||||
use App\Service\TaskManager;
|
||||
use App\Service\TaskSerializer;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
@@ -17,23 +16,20 @@ class TaskController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private TaskManager $taskManager,
|
||||
private TaskSerializer $taskSerializer,
|
||||
) {}
|
||||
|
||||
#[Route('/{id}', name: 'show', methods: ['GET'])]
|
||||
public function show(Task $task): JsonResponse
|
||||
{
|
||||
$response = $this->taskSerializer->serializeTask($task);
|
||||
|
||||
return $this->json($response);
|
||||
return $this->json($task, context: ['groups' => ['task:read', 'category:read']]);
|
||||
}
|
||||
|
||||
#[Route('/{id}', name: 'update', methods: ['PUT'])]
|
||||
public function update(#[MapRequestPayload] UpdateTaskRequest $dto, Task $task): JsonResponse
|
||||
{
|
||||
$result = $this->taskManager->updateTask($task, $dto);
|
||||
$task = $this->taskManager->updateTask($task, $dto);
|
||||
|
||||
return $this->json($result);
|
||||
return $this->json($task, context: ['groups' => ['task:read', 'category:read']]);
|
||||
}
|
||||
|
||||
#[Route('/{id}', name: 'delete', methods: ['DELETE'])]
|
||||
|
||||
@@ -41,7 +41,7 @@ class TaskSchemaController extends AbstractController
|
||||
$startParam = $request->query->get('start');
|
||||
$start = $startParam ? new \DateTimeImmutable($startParam) : new \DateTimeImmutable('today');
|
||||
|
||||
return $this->json($this->taskViewBuilder->buildWeekView($start));
|
||||
return $this->json($this->taskViewBuilder->buildWeekView($start), context: ['groups' => ['task:read', 'category:read']]);
|
||||
}
|
||||
|
||||
#[Route('/all', name: 'schemas.all', methods: ['GET'])]
|
||||
@@ -55,7 +55,7 @@ class TaskSchemaController extends AbstractController
|
||||
#[Route('/all-tasks', name: 'schemas.allTasks', methods: ['GET'])]
|
||||
public function allTasks(): JsonResponse
|
||||
{
|
||||
return $this->json($this->taskViewBuilder->buildAllTasksView());
|
||||
return $this->json($this->taskViewBuilder->buildAllTasksView(), context: ['groups' => ['task:read', 'category:read']]);
|
||||
}
|
||||
|
||||
#[Route('/{id}', name: 'schemas.show', methods: ['GET'])]
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\DTO\Response;
|
||||
|
||||
class CategoryResponse
|
||||
{
|
||||
public function __construct(
|
||||
public readonly int $id,
|
||||
public readonly string $name,
|
||||
public readonly string $color,
|
||||
) {}
|
||||
}
|
||||
@@ -2,11 +2,15 @@
|
||||
|
||||
namespace App\DTO\Response;
|
||||
|
||||
use Symfony\Component\Serializer\Attribute\Groups;
|
||||
|
||||
class DayResponse
|
||||
{
|
||||
public function __construct(
|
||||
#[Groups(['task:read'])]
|
||||
public readonly string $date,
|
||||
/** @var TaskResponse[] */
|
||||
/** @var \App\Entity\Task[] */
|
||||
#[Groups(['task:read'])]
|
||||
public readonly array $tasks,
|
||||
) {}
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\DTO\Response;
|
||||
|
||||
class TaskResponse
|
||||
{
|
||||
public function __construct(
|
||||
public readonly int $schemaId,
|
||||
public readonly int $taskId,
|
||||
public readonly string $name,
|
||||
public readonly string $status,
|
||||
public readonly string $taskType,
|
||||
public readonly ?string $date,
|
||||
public readonly ?string $deadline,
|
||||
public readonly bool $isPast,
|
||||
public readonly ?CategoryResponse $category,
|
||||
) {}
|
||||
}
|
||||
@@ -2,12 +2,16 @@
|
||||
|
||||
namespace App\DTO\Response;
|
||||
|
||||
use Symfony\Component\Serializer\Attribute\Groups;
|
||||
|
||||
class WeekViewResponse
|
||||
{
|
||||
public function __construct(
|
||||
/** @var TaskResponse[] */
|
||||
/** @var \App\Entity\Task[] */
|
||||
#[Groups(['task:read'])]
|
||||
public readonly array $tasksWithoutDeadline,
|
||||
/** @var DayResponse[] */
|
||||
#[Groups(['task:read'])]
|
||||
public readonly array $days,
|
||||
) {}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ use App\Enum\TaskStatus;
|
||||
use App\Repository\TaskRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Attribute\Groups;
|
||||
use Symfony\Component\Serializer\Attribute\SerializedName;
|
||||
|
||||
#[ORM\Entity(repositoryClass: TaskRepository::class)]
|
||||
#[ORM\UniqueConstraint(columns: ['task_id', 'date'])]
|
||||
@@ -44,11 +46,20 @@ class Task
|
||||
#[ORM\Column(type: Types::DATETIME_MUTABLE)]
|
||||
private \DateTimeInterface $createdAt;
|
||||
|
||||
#[Groups(['task:read'])]
|
||||
#[SerializedName('taskId')]
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
#[Groups(['task:read'])]
|
||||
#[SerializedName('schemaId')]
|
||||
public function getSchemaId(): int
|
||||
{
|
||||
return $this->schema->getId();
|
||||
}
|
||||
|
||||
public function getSchema(): TaskSchema
|
||||
{
|
||||
return $this->schema;
|
||||
@@ -93,27 +104,39 @@ class Task
|
||||
return $this;
|
||||
}
|
||||
|
||||
#[Groups(['task:read'])]
|
||||
#[SerializedName('name')]
|
||||
public function getEffectiveName(): string
|
||||
{
|
||||
return $this->name ?? $this->schema->getName();
|
||||
}
|
||||
|
||||
#[Groups(['task:read'])]
|
||||
#[SerializedName('category')]
|
||||
public function getEffectiveCategory(): ?Category
|
||||
{
|
||||
return $this->categoryOverridden ? $this->category : $this->schema->getCategory();
|
||||
}
|
||||
|
||||
#[Groups(['task:read'])]
|
||||
public function getDate(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->date;
|
||||
}
|
||||
|
||||
#[Groups(['task:read'])]
|
||||
public function getDeadline(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->date;
|
||||
}
|
||||
|
||||
public function setDate(?\DateTimeInterface $date): static
|
||||
{
|
||||
$this->date = $date;
|
||||
return $this;
|
||||
}
|
||||
|
||||
#[Groups(['task:read'])]
|
||||
public function getStatus(): TaskStatus
|
||||
{
|
||||
return $this->status;
|
||||
@@ -125,6 +148,20 @@ class Task
|
||||
return $this;
|
||||
}
|
||||
|
||||
#[Groups(['task:read'])]
|
||||
#[SerializedName('taskType')]
|
||||
public function getTaskType(): string
|
||||
{
|
||||
return $this->schema->getTaskType()->value;
|
||||
}
|
||||
|
||||
#[Groups(['task:read'])]
|
||||
#[SerializedName('isPast')]
|
||||
public function isPast(): bool
|
||||
{
|
||||
return $this->date !== null && $this->date < new \DateTimeImmutable('today');
|
||||
}
|
||||
|
||||
public function getCreatedAt(): \DateTimeInterface
|
||||
{
|
||||
return $this->createdAt;
|
||||
|
||||
@@ -4,12 +4,11 @@ namespace App\Service;
|
||||
|
||||
use App\DTO\Request\ToggleRequest;
|
||||
use App\DTO\Request\UpdateTaskRequest;
|
||||
use App\DTO\Response\TaskResponse;
|
||||
use App\DTO\Response\ToggleResponse;
|
||||
use App\Entity\Task;
|
||||
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;
|
||||
@@ -21,10 +20,9 @@ class TaskManager
|
||||
private EntityManagerInterface $em,
|
||||
private CategoryRepository $categoryRepository,
|
||||
private TaskRepository $taskRepository,
|
||||
private TaskSerializer $taskSerializer,
|
||||
) {}
|
||||
|
||||
public function updateTask(Task $task, UpdateTaskRequest $request): TaskResponse
|
||||
public function updateTask(Task $task, UpdateTaskRequest $request): Task
|
||||
{
|
||||
$task->setName($request->name);
|
||||
|
||||
@@ -43,7 +41,7 @@ class TaskManager
|
||||
|
||||
$this->em->flush();
|
||||
|
||||
return $this->taskSerializer->serializeTask($task, new \DateTimeImmutable('today'));
|
||||
return $task;
|
||||
}
|
||||
|
||||
public function toggleTaskStatus(TaskSchema $schema, ToggleRequest $request): ToggleResponse
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\DTO\Response\CategoryResponse;
|
||||
use App\DTO\Response\TaskResponse;
|
||||
use App\Entity\Category;
|
||||
use App\Entity\Task;
|
||||
|
||||
class TaskSerializer
|
||||
{
|
||||
public function serializeTask(Task $task, ?\DateTimeImmutable $today = null): TaskResponse
|
||||
{
|
||||
$today ??= new \DateTimeImmutable('today');
|
||||
$schema = $task->getSchema();
|
||||
$category = $task->getEffectiveCategory();
|
||||
$date = $task->getDate();
|
||||
|
||||
return new TaskResponse(
|
||||
schemaId: $schema->getId(),
|
||||
taskId: $task->getId(),
|
||||
name: $task->getEffectiveName(),
|
||||
status: $task->getStatus()->value,
|
||||
taskType: $schema->getTaskType()->value,
|
||||
date: $date?->format('Y-m-d'),
|
||||
deadline: $date?->format('Y-m-d'),
|
||||
isPast: $date !== null && $date < $today,
|
||||
category: $category !== null ? $this->serializeCategory($category) : null,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Task[] $tasks
|
||||
* @return TaskResponse[]
|
||||
*/
|
||||
public function serializeTasks(array $tasks, \DateTimeImmutable $today): array
|
||||
{
|
||||
return array_map(fn(Task $task) => $this->serializeTask($task, $today), $tasks);
|
||||
}
|
||||
|
||||
public function serializeCategory(Category $category): CategoryResponse
|
||||
{
|
||||
return new CategoryResponse(
|
||||
id: $category->getId(),
|
||||
name: $category->getName(),
|
||||
color: $category->getColor(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,8 @@
|
||||
namespace App\Service;
|
||||
|
||||
use App\DTO\Response\DayResponse;
|
||||
use App\DTO\Response\TaskResponse;
|
||||
use App\DTO\Response\WeekViewResponse;
|
||||
use App\Entity\Task;
|
||||
use App\Repository\TaskRepository;
|
||||
|
||||
class TaskViewBuilder
|
||||
@@ -12,23 +12,18 @@ class TaskViewBuilder
|
||||
public function __construct(
|
||||
private TaskGenerator $taskGenerator,
|
||||
private TaskRepository $taskRepository,
|
||||
private TaskSerializer $taskSerializer,
|
||||
) {}
|
||||
|
||||
public function buildWeekView(?\DateTimeImmutable $start = null): WeekViewResponse
|
||||
{
|
||||
$start = $start ?? new \DateTimeImmutable('today');
|
||||
$end = $start->modify('+6 days');
|
||||
$today = new \DateTimeImmutable('today');
|
||||
|
||||
// Generate missing tasks
|
||||
$this->taskGenerator->generateForRange($start, $end);
|
||||
$this->taskGenerator->generateForTasksWithoutDate();
|
||||
|
||||
// Load tasks with dates in range
|
||||
$tasks = $this->taskRepository->findInRange($start, $end);
|
||||
|
||||
// Build days structure
|
||||
$days = [];
|
||||
$current = $start;
|
||||
while ($current <= $end) {
|
||||
@@ -39,20 +34,15 @@ class TaskViewBuilder
|
||||
foreach ($tasks as $task) {
|
||||
$dateKey = $task->getDate()->format('Y-m-d');
|
||||
if (isset($days[$dateKey])) {
|
||||
$days[$dateKey][] = $this->taskSerializer->serializeTask($task, $today);
|
||||
$days[$dateKey][] = $task;
|
||||
}
|
||||
}
|
||||
|
||||
// Tasks without date (einzel without deadline)
|
||||
$tasksWithoutDeadline = [];
|
||||
$noDateTasks = $this->taskRepository->findWithoutDate();
|
||||
foreach ($noDateTasks as $task) {
|
||||
$tasksWithoutDeadline[] = $this->taskSerializer->serializeTask($task, $today);
|
||||
}
|
||||
$tasksWithoutDeadline = $this->taskRepository->findWithoutDate();
|
||||
|
||||
$dayResponses = [];
|
||||
foreach ($days as $date => $dayTasks) {
|
||||
usort($dayTasks, fn(TaskResponse $a, TaskResponse $b) => strcmp($a->name, $b->name));
|
||||
usort($dayTasks, fn(Task $a, Task $b) => strcmp($a->getEffectiveName(), $b->getEffectiveName()));
|
||||
$dayResponses[] = new DayResponse(
|
||||
date: $date,
|
||||
tasks: $dayTasks,
|
||||
@@ -66,24 +56,21 @@ class TaskViewBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TaskResponse[]
|
||||
* @return Task[]
|
||||
*/
|
||||
public function buildAllTasksView(): array
|
||||
{
|
||||
$this->taskGenerator->generateForTasksWithoutDate();
|
||||
$today = new \DateTimeImmutable('today');
|
||||
$result = [];
|
||||
|
||||
// Tasks without date first
|
||||
$noDate = $this->taskRepository->findWithoutDate();
|
||||
foreach ($noDate as $task) {
|
||||
$result[] = $this->taskSerializer->serializeTask($task, $today);
|
||||
$result[] = $task;
|
||||
}
|
||||
|
||||
// Then all tasks with date
|
||||
$tasks = $this->taskRepository->findAllSorted();
|
||||
foreach ($tasks as $task) {
|
||||
$result[] = $this->taskSerializer->serializeTask($task, $today);
|
||||
$result[] = $task;
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
Reference in New Issue
Block a user