feat : extend export endpoint for multi-user, multi-project, client filters

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-24 21:41:53 +01:00
parent 8f8eeddd91
commit 755c39a0f6
2 changed files with 63 additions and 23 deletions

View File

@@ -47,27 +47,65 @@ class TimeEntryExportController extends AbstractController
throw new BadRequestHttpException('Format de date invalide. Utilisez YYYY-MM-DD.');
}
// Max range: 12 months
if ($after->modify('+12 months') < $before) {
throw new BadRequestHttpException('La plage de dates ne peut pas dépasser 12 mois.');
}
// Authorization: non-admin users can only export their own data
$user = null;
// --- Users ---
$users = null;
if (!$this->security->isGranted('ROLE_ADMIN')) {
/** @var User $user */
$user = $this->security->getUser();
/** @var User $currentUser */
$currentUser = $this->security->getUser();
$users = [$currentUser];
} else {
$userId = $request->query->getInt('user');
if ($userId > 0) {
$user = $this->entityManager->getRepository(User::class)->find($userId);
/** @var int[] $userIds */
$userIds = array_filter(
array_map('intval', (array) $request->query->all('users')),
fn (int $id) => $id > 0,
);
if ([] !== $userIds) {
$users = $this->entityManager->getRepository(User::class)->findBy(['id' => $userIds]);
}
}
$project = null;
$projectId = $request->query->getInt('project');
if ($projectId > 0) {
$project = $this->entityManager->getRepository(Project::class)->find($projectId);
// --- Client (filter projects by client) ---
$clientId = $request->query->getInt('client');
$clientProjects = null;
if ($clientId > 0) {
$clientProjects = $this->entityManager->getRepository(Project::class)->findBy(['client' => $clientId]);
}
// --- Projects ---
$projects = null;
/** @var int[] $projectIds */
$projectIds = array_filter(
array_map('intval', (array) $request->query->all('projects')),
fn (int $id) => $id > 0,
);
if ([] !== $projectIds) {
$projects = $this->entityManager->getRepository(Project::class)->findBy(['id' => $projectIds]);
}
// Merge: if both client and projects are set, intersect; if only client, use client projects
if (null !== $clientProjects && null !== $projects) {
$clientProjectIds = array_map(fn (Project $p) => $p->getId(), $clientProjects);
$projects = array_values(array_filter($projects, fn (Project $p) => in_array($p->getId(), $clientProjectIds, true)));
if ([] === $projects) {
$projects = null;
// No matching projects — force empty result by using a dummy condition
$entries = [];
$tempFile = $this->exportService->generate($entries, $after, $before);
$filename = sprintf('export-temps-%s_%s.xlsx', $after->format('Y-m-d'), $before->format('Y-m-d'));
$response = new BinaryFileResponse($tempFile);
$response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $filename);
$response->headers->set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
$response->deleteFileAfterSend(true);
return $response;
}
} elseif (null !== $clientProjects) {
$projects = $clientProjects;
}
/** @var int[] $tagIds */
@@ -79,8 +117,8 @@ class TimeEntryExportController extends AbstractController
$entries = $this->timeEntryRepository->findForExport(
$after,
$before,
$user,
$project,
$users ?: null,
$projects ?: null,
$tagIds ?: null,
);

View File

@@ -30,15 +30,17 @@ class TimeEntryRepository extends ServiceEntityRepository
}
/**
* @param null|int[] $tagIds
* @param null|User[] $users
* @param null|Project[] $projects
* @param null|int[] $tagIds
*
* @return TimeEntry[]
*/
public function findForExport(
DateTimeImmutable $after,
DateTimeImmutable $before,
?User $user = null,
?Project $project = null,
?array $users = null,
?array $projects = null,
?array $tagIds = null,
): array {
$qb = $this->createQueryBuilder('te')
@@ -49,15 +51,15 @@ class TimeEntryRepository extends ServiceEntityRepository
->orderBy('te.startedAt', 'ASC')
;
if (null !== $user) {
$qb->andWhere('te.user = :user')
->setParameter('user', $user)
if (null !== $users && [] !== $users) {
$qb->andWhere('te.user IN (:users)')
->setParameter('users', $users)
;
}
if (null !== $project) {
$qb->andWhere('te.project = :project')
->setParameter('project', $project)
if (null !== $projects && [] !== $projects) {
$qb->andWhere('te.project IN (:projects)')
->setParameter('projects', $projects)
;
}