From 995730236017aff3445f976ccabc31661cec8d50 Mon Sep 17 00:00:00 2001 From: Pep Villalonga Date: Tue, 14 Jul 2026 13:28:51 +0200 Subject: [PATCH] feat: gateway charges stats endpoint --- config/services.yaml | 4 ++ src/ApiResource/Gateway/ChargeApiResource.php | 13 +++++ src/Dto/Gateway/ChargeStats.php | 19 +++++++ .../Gateway/ChargeStatsStateProvider.php | 57 +++++++++++++++++++ 4 files changed, 93 insertions(+) create mode 100644 src/Dto/Gateway/ChargeStats.php create mode 100644 src/State/Gateway/ChargeStatsStateProvider.php diff --git a/config/services.yaml b/config/services.yaml index 0bd2092..02820aa 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -95,6 +95,10 @@ services: arguments: - !tagged 'api_platform.doctrine.orm.query_extension.collection' + App\State\Gateway\ChargeStatsStateProvider: + arguments: + - !tagged 'api_platform.doctrine.orm.query_extension.collection' + App\Money\MoneyService: arguments: - '%env(CURRENCY_DEFAULT)%' diff --git a/src/ApiResource/Gateway/ChargeApiResource.php b/src/ApiResource/Gateway/ChargeApiResource.php index c43174b..baa7512 100644 --- a/src/ApiResource/Gateway/ChargeApiResource.php +++ b/src/ApiResource/Gateway/ChargeApiResource.php @@ -7,6 +7,7 @@ use ApiPlatform\Doctrine\Orm\State\Options; use ApiPlatform\Metadata as API; use App\ApiResource\Accounting\AccountingApiResource; use App\ApiResource\MoneyOutput; +use App\Dto\Gateway\ChargeStats; use App\Dto\Gateway\ChargeUpdationDto; use App\Entity\Gateway\Charge; use App\Filter\GatewayFilter; @@ -14,6 +15,7 @@ use App\Gateway\ChargeStatus; use App\Gateway\ChargeType; use App\State\ApiResourceStateProvider; use App\State\Gateway\ChargeStateProcessor; +use App\State\Gateway\ChargeStatsStateProvider; use Symfony\Component\Validator\Constraints as Assert; /** @@ -26,6 +28,17 @@ use Symfony\Component\Validator\Constraints as Assert; )] #[API\Get()] #[API\GetCollection()] +#[API\GetCollection( + uriTemplate: '/gateway_charges/stats', + priority: -1, + provider: ChargeStatsStateProvider::class, + output: ChargeStats::class, + paginationEnabled: false, + openapi: new \ApiPlatform\OpenApi\Model\Operation( + summary: 'Distinct project count for a charges filter set', + description: 'Returns the number of distinct projects targeted by charges matching the same filters as the charges collection.', + ), +)] #[API\Patch( input: ChargeUpdationDto::class, processor: ChargeStateProcessor::class, diff --git a/src/Dto/Gateway/ChargeStats.php b/src/Dto/Gateway/ChargeStats.php new file mode 100644 index 0000000..c308879 --- /dev/null +++ b/src/Dto/Gateway/ChargeStats.php @@ -0,0 +1,19 @@ +distinctProjectCount; + } +} diff --git a/src/State/Gateway/ChargeStatsStateProvider.php b/src/State/Gateway/ChargeStatsStateProvider.php new file mode 100644 index 0000000..299c3ce --- /dev/null +++ b/src/State/Gateway/ChargeStatsStateProvider.php @@ -0,0 +1,57 @@ +managerRegistry->getManagerForClass(Charge::class); + + $repository = $manager->getRepository(Charge::class); + if (!method_exists($repository, 'createQueryBuilder')) { + throw new RuntimeException('The repository class must have a "createQueryBuilder" method.'); + } + + $queryBuilder = $repository->createQueryBuilder('o'); + $queryNameGenerator = new QueryNameGenerator(); + + foreach ($this->collectionExtensions as $extension) { + $extension->applyToCollection($queryBuilder, $queryNameGenerator, Charge::class, $operation, $context); + } + + $count = (int) $queryBuilder + ->resetDQLPart('orderBy') + ->join('o.target', 'stats_target') + ->join('stats_target.project', 'stats_project') + ->select('COUNT(DISTINCT stats_project.id)') + ->getQuery() + ->getSingleScalarResult(); + + return new ChargeStats($count); + } +}