From 9f3037c5c4638a83fbe4395e281d44f87144b203 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Mon, 1 Jun 2026 15:44:00 +0200 Subject: [PATCH] feat(commercial) : add clients XLSX export endpoint --- .../Repository/ClientRepositoryInterface.php | 14 +- .../State/Provider/ClientProvider.php | 63 +----- .../Controller/ClientExportController.php | 201 ++++++++++++++++++ .../Doctrine/DoctrineClientRepository.php | 55 ++++- .../Api/ClientExportControllerTest.php | 185 ++++++++++++++++ 5 files changed, 460 insertions(+), 58 deletions(-) create mode 100644 src/Module/Commercial/Infrastructure/Controller/ClientExportController.php create mode 100644 tests/Module/Commercial/Api/ClientExportControllerTest.php diff --git a/src/Module/Commercial/Domain/Repository/ClientRepositoryInterface.php b/src/Module/Commercial/Domain/Repository/ClientRepositoryInterface.php index a3d6ca3..a5c43d7 100644 --- a/src/Module/Commercial/Domain/Repository/ClientRepositoryInterface.php +++ b/src/Module/Commercial/Domain/Repository/ClientRepositoryInterface.php @@ -18,6 +18,18 @@ interface ClientRepositoryInterface * - Exclut toujours les clients soft-deletes (deleted_at IS NOT NULL, RG-1.24). * - Exclut les archives sauf si $includeArchived = true (RG-1.25). * - Tri par defaut : companyName ASC (RG-1.26). + * - $search : recherche fuzzy insensible a la casse sur companyName + + * lastName + email (metacaracteres LIKE echappes). Ignore si null/vide. + * - $categoryType : restreint aux clients possedant au moins une categorie + * du type donne (code). Ignore si null/vide. + * + * Filtrage centralise ICI (et non dans les providers/controllers) pour que + * la liste paginee (ClientProvider) et l'export (ClientExportController) + * partagent strictement la meme logique de selection. */ - public function createListQueryBuilder(bool $includeArchived = false): QueryBuilder; + public function createListQueryBuilder( + bool $includeArchived = false, + ?string $search = null, + ?string $categoryType = null, + ): QueryBuilder; } diff --git a/src/Module/Commercial/Infrastructure/ApiPlatform/State/Provider/ClientProvider.php b/src/Module/Commercial/Infrastructure/ApiPlatform/State/Provider/ClientProvider.php index f401375..8d7c640 100644 --- a/src/Module/Commercial/Infrastructure/ApiPlatform/State/Provider/ClientProvider.php +++ b/src/Module/Commercial/Infrastructure/ApiPlatform/State/Provider/ClientProvider.php @@ -11,8 +11,6 @@ use ApiPlatform\State\Pagination\Pagination; use ApiPlatform\State\ProviderInterface; use App\Module\Commercial\Domain\Entity\Client; use App\Module\Commercial\Domain\Repository\ClientRepositoryInterface; -use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\Tools\Pagination\Paginator as DoctrinePaginator; use Symfony\Component\DependencyInjection\Attribute\Autowire; @@ -46,7 +44,6 @@ final class ClientProvider implements ProviderInterface #[Autowire(service: 'App\Module\Commercial\Infrastructure\Doctrine\DoctrineClientRepository')] private readonly ClientRepositoryInterface $repository, private readonly Pagination $pagination, - private readonly EntityManagerInterface $em, ) {} public function provide(Operation $operation, array $uriVariables = [], array $context = []): Client|iterable|Paginator|null @@ -67,10 +64,15 @@ final class ClientProvider implements ProviderInterface { $filters = $context['filters'] ?? []; $includeArchived = $this->readBool($filters['includeArchived'] ?? false); + $search = $filters['search'] ?? null; + $categoryType = $filters['categoryType'] ?? null; - $qb = $this->repository->createListQueryBuilder($includeArchived); - $this->applySearch($qb, $filters['search'] ?? null); - $this->applyCategoryType($qb, $filters['categoryType'] ?? null); + // Filtrage delegue au repository (logique partagee avec l'export XLSX). + $qb = $this->repository->createListQueryBuilder( + $includeArchived, + is_string($search) ? $search : null, + is_string($categoryType) ? $categoryType : null, + ); // Echappatoire ?pagination=false : collection complete sans Paginator // (cf. convention ERP-72 — utile pour un