feat(08-02): add mode dispatch, filter params, and cascade endpoints

This commit is contained in:
Christopher Mühl 2026-04-09 21:44:19 +02:00
parent 86e7d5f209
commit f8b22da9de
No known key found for this signature in database
GPG key ID: 925AC7D69955293F
2 changed files with 51 additions and 10 deletions

View file

@ -21,16 +21,51 @@ class HeatmapController extends AbstractController
$end = new \DateTimeImmutable('today'); $end = new \DateTimeImmutable('today');
$begin = $end->modify('-1 year'); $begin = $end->modify('-1 year');
$mode = $request->query->getString('mode', 'daily');
$projectId = $request->query->getInt('project') ?: null;
$customerId = $request->query->getInt('customer') ?: null;
$activityId = $request->query->getInt('activity') ?: null;
$range = ['begin' => $begin->format('Y-m-d'), 'end' => $end->format('Y-m-d')];
return match ($mode) {
'hourly' => new JsonResponse([
'hours' => $service->getHourlyAggregation($user, $begin, $end, $projectId, $customerId, $activityId),
'range' => $range,
]),
'dayhour' => new JsonResponse([
'matrix' => $service->getDayHourAggregation($user, $begin, $end, $projectId, $customerId, $activityId, $user->getFirstDayOfWeek()),
'range' => $range,
]),
default => new JsonResponse([
'days' => $service->getDailyAggregation($user, $begin, $end, $projectId, $customerId, $activityId),
'range' => $range,
]),
};
}
#[Route(path: '/customers', name: 'heatmap_customers', methods: ['GET'])]
#[IsGranted('view_own_timesheet')]
public function customers(HeatmapService $service): JsonResponse
{
return new JsonResponse($service->getUserCustomers($this->getUser()));
}
#[Route(path: '/projects', name: 'heatmap_projects', methods: ['GET'])]
#[IsGranted('view_own_timesheet')]
public function projects(Request $request, HeatmapService $service): JsonResponse
{
$customerId = $request->query->getInt('customer') ?: null;
return new JsonResponse($service->getUserProjects($this->getUser(), $customerId));
}
#[Route(path: '/activities', name: 'heatmap_activities', methods: ['GET'])]
#[IsGranted('view_own_timesheet')]
public function activities(Request $request, HeatmapService $service): JsonResponse
{
$projectId = $request->query->getInt('project') ?: null; $projectId = $request->query->getInt('project') ?: null;
$days = $service->getDailyAggregation($user, $begin, $end, $projectId); return new JsonResponse($service->getUserActivities($this->getUser(), $projectId));
return new JsonResponse([
'days' => $days,
'range' => [
'begin' => $begin->format('Y-m-d'),
'end' => $end->format('Y-m-d'),
],
]);
} }
} }

View file

@ -167,7 +167,7 @@ class HeatmapService
/** /**
* @return array<int, array{id: int, name: string}> * @return array<int, array{id: int, name: string}>
*/ */
public function getUserProjects(User $user): array public function getUserProjects(User $user, ?int $customerId = null): array
{ {
$qb = $this->repository->createQueryBuilder('t'); $qb = $this->repository->createQueryBuilder('t');
$qb->select('DISTINCT IDENTITY(t.project) as projectId, p.name') $qb->select('DISTINCT IDENTITY(t.project) as projectId, p.name')
@ -177,6 +177,12 @@ class HeatmapService
->setParameter('user', $user) ->setParameter('user', $user)
->orderBy('p.name', 'ASC'); ->orderBy('p.name', 'ASC');
if ($customerId !== null) {
$qb->join('p.customer', 'c')
->andWhere($qb->expr()->eq('c.id', ':customer'))
->setParameter('customer', $customerId);
}
return array_map(fn(array $row) => [ return array_map(fn(array $row) => [
'id' => (int) $row['projectId'], 'id' => (int) $row['projectId'],
'name' => $row['name'], 'name' => $row['name'],