feat: gateway charges stats endpoint
This commit is contained in:
@@ -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)%'
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto\Gateway;
|
||||
|
||||
/**
|
||||
* Aggregate statistics for a filtered GatewayCharge collection.
|
||||
*/
|
||||
class ChargeStats
|
||||
{
|
||||
public function __construct(private int $distinctProjectCount) {}
|
||||
|
||||
/**
|
||||
* The number of distinct Projects targeted by the charges matching the filter set.
|
||||
*/
|
||||
public function getDistinctProjectCount(): int
|
||||
{
|
||||
return $this->distinctProjectCount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\State\Gateway;
|
||||
|
||||
use ApiPlatform\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
|
||||
use ApiPlatform\Doctrine\Orm\Util\QueryNameGenerator;
|
||||
use ApiPlatform\Metadata\Exception\RuntimeException;
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
use App\Dto\Gateway\ChargeStats;
|
||||
use App\Entity\Gateway\Charge;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* Provides the number of distinct Projects targeted by a filtered GatewayCharge collection.
|
||||
*
|
||||
* Reuses the same ApiFilters declared on the GatewayCharge collection (target, status,
|
||||
* type, money range, dates, ...) by re-applying every registered ORM collection
|
||||
* extension, then runs a single COUNT(DISTINCT project) query.
|
||||
*/
|
||||
class ChargeStatsStateProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* @param QueryCollectionExtensionInterface[] $collectionExtensions
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly iterable $collectionExtensions,
|
||||
private ManagerRegistry $managerRegistry,
|
||||
) {}
|
||||
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): ChargeStats
|
||||
{
|
||||
$manager = $this->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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user