feat: put query functionality to QueryBuilderExtractor

This commit is contained in:
2026-07-14 15:36:05 +02:00
parent 13bd92053b
commit 892921f41f
3 changed files with 93 additions and 1 deletions
+1 -1
View File
@@ -91,7 +91,7 @@ services:
arguments:
- !tagged 'app.service.scout.processor'
App\State\MoneyTotalStateProvider:
App\State\QueryBuilderExtractor:
arguments:
- !tagged 'api_platform.doctrine.orm.query_extension.collection'
+25
View File
@@ -0,0 +1,25 @@
<?php
namespace App\State;
use ApiPlatform\Doctrine\Orm\State\Options;
use ApiPlatform\Metadata\Operation;
trait EntityOperationStateTrait
{
/**
* Extract the FQCN for the Entity behind a given Operation.
*
* @return string A FQCN
*/
public function getEntityClass(Operation $operation): string
{
$entityClass = $operation->getClass();
if (($options = $operation->getStateOptions()) && $options instanceof Options && $options->getEntityClass()) {
$entityClass = $options->getEntityClass();
}
return $entityClass;
}
}
+67
View File
@@ -0,0 +1,67 @@
<?php
namespace App\State;
use ApiPlatform\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
use ApiPlatform\Doctrine\Orm\Util\QueryNameGenerator;
use ApiPlatform\Metadata\Exception\RuntimeException;
use ApiPlatform\Metadata\Operation;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;
class QueryBuilderExtractor
{
use EntityOperationStateTrait;
/**
* @param iterable<QueryCollectionExtensionInterface> $collectionExtensions
*/
public function __construct(
private readonly iterable $collectionExtensions,
private ManagerRegistry $managerRegistry,
) {}
/**
* Get the QueryBuilder behind a given API operation.
*
* @param callable(QueryCollectionExtensionInterface): bool|null $extensionFilter A function
*
* @return QueryBuilder The query builder for the given params
*/
public function getQueryBuilder(
Operation $operation,
array $context = [],
?callable $extensionFilter = null,
): QueryBuilder {
$entityClass = $this->getEntityClass($operation);
$manager = $this->managerRegistry->getManagerForClass($entityClass);
$repository = $manager->getRepository($entityClass);
if (!method_exists($repository, 'createQueryBuilder')) {
throw new RuntimeException('The repository class must have a "createQueryBuilder" method.');
}
$queryBuilder = $repository->createQueryBuilder('o');
$queryNameGenerator = new QueryNameGenerator();
$extensionFilter ??= static fn($extension) => true;
foreach ($this->getCollectionExtensions() as $extension) {
if (!$extensionFilter($extension)) {
continue;
}
$extension->applyToCollection($queryBuilder, $queryNameGenerator, $entityClass, $operation, $context);
}
return $queryBuilder;
}
/**
* Get the collection extensions injected by default.
*
* @return iterable<QueryCollectionExtensionInterface>
*/
public function getCollectionExtensions(): iterable
{
return $this->collectionExtensions;
}
}