Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ services:
public: true

MalteHuebner\DataQueryBundle\:
resource: '../src/{DataQueryManager,Factory,FieldList,FinderFactory,Manager,Parameter,Query,RequestParameterList,Validator}'
resource: '../src/{DataQueryManager,Factory,FieldList,FinderFactory,Manager,PaginatedResult,Parameter,Query,RequestParameterList,Validator}'
exclude: '../src/{DependencyInjection,Factory/ConflictResolver,Factory/ValueAssigner/ValueType.php,RequestParameterList/ArrayToListConverter.php,RequestParameterList/QueryStringToListConverter.php,RequestParameterList/RequestToListConverter.php,tests,MalteHuebnerDataQueryBundle}'

Psr\Container\ContainerInterface:
Expand Down
5 changes: 5 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ parameters:
count: 2
path: src/FieldList/QueryFieldList/QueryFieldListFactory.php

-
message: "#^Call to method createPaginatorAdapter\\(\\) on an unknown class FOS\\\\ElasticaBundle\\\\Repository\\.$#"
count: 1
path: src/Finder/Finder.php

-
message: "#^Call to method find\\(\\) on an unknown class FOS\\\\ElasticaBundle\\\\Repository\\.$#"
count: 1
Expand Down
27 changes: 27 additions & 0 deletions src/DataQueryManager/DataQueryManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
use MalteHuebner\DataQueryBundle\Factory\ParameterFactory\ParameterFactoryInterface;
use MalteHuebner\DataQueryBundle\Factory\QueryFactory\QueryFactoryInterface;
use MalteHuebner\DataQueryBundle\FinderFactory\FinderFactoryInterface;
use MalteHuebner\DataQueryBundle\PaginatedResult\PaginatedResult;
use MalteHuebner\DataQueryBundle\Parameter\PageParameter;
use MalteHuebner\DataQueryBundle\Parameter\SizeParameter;
use MalteHuebner\DataQueryBundle\RequestParameterList\RequestParameterList;

class DataQueryManager implements DataQueryManagerInterface
Expand All @@ -27,4 +30,28 @@ public function query(RequestParameterList $requestParameterList, string $entity

return $finder->executeQuery($queryList, $parameterList);
}

#[\Override]
public function paginatedQuery(RequestParameterList $requestParameterList, string $entityFqcn): PaginatedResult
{
$queryList = $this->queryFactory->setEntityFqcn($entityFqcn)->createFromList($requestParameterList);
$parameterList = $this->parameterFactory->setEntityFqcn($entityFqcn)->createFromList($requestParameterList);

$page = 0;
$size = 10;

foreach ($parameterList as $parameter) {
if ($parameter instanceof PageParameter) {
$page = $parameter->getPage();
}

if ($parameter instanceof SizeParameter) {
$size = $parameter->getSize();
}
}

$finder = $this->finderFactory->createFinderForFqcn($entityFqcn);

return $finder->executePaginatedQuery($queryList, $parameterList, $page, $size);
}
}
2 changes: 2 additions & 0 deletions src/DataQueryManager/DataQueryManagerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

namespace MalteHuebner\DataQueryBundle\DataQueryManager;

use MalteHuebner\DataQueryBundle\PaginatedResult\PaginatedResult;
use MalteHuebner\DataQueryBundle\RequestParameterList\RequestParameterList;

interface DataQueryManagerInterface
{
public function query(RequestParameterList $requestParameterList, string $entityFqcn): array;
public function paginatedQuery(RequestParameterList $requestParameterList, string $entityFqcn): PaginatedResult;
}
82 changes: 82 additions & 0 deletions src/Finder/Finder.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
namespace MalteHuebner\DataQueryBundle\Finder;

use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Tools\Pagination\Paginator;
use FOS\ElasticaBundle\Repository;
use MalteHuebner\DataQueryBundle\PaginatedResult\PaginatedResult;
use MalteHuebner\DataQueryBundle\Parameter\FromParameter;
use MalteHuebner\DataQueryBundle\Parameter\PageParameter;
use MalteHuebner\DataQueryBundle\Parameter\ParameterInterface;
use MalteHuebner\DataQueryBundle\Parameter\SizeParameter;
use MalteHuebner\DataQueryBundle\Query\ElasticQueryInterface;
Expand Down Expand Up @@ -96,4 +100,82 @@ protected function executeOrmQuery(array $queryList, array $parameterList): arra

return $qb->getQuery()->getResult();
}

#[\Override]
public function executePaginatedQuery(array $queryList, array $parameterList, int $page, int $size): PaginatedResult
{
if ($this->entityManager) {
return $this->executePaginatedOrmQuery($queryList, $parameterList, $page, $size);
}

if ($this->repository) {
return $this->executePaginatedElasticQuery($queryList, $parameterList, $page, $size);
}

return new PaginatedResult([], $page, $size, 0);
}

protected function executePaginatedElasticQuery(array $queryList, array $parameterList, int $page, int $size): PaginatedResult
{
$boolQuery = new \Elastica\Query\BoolQuery();

/** @var ElasticQueryInterface $query */
foreach ($queryList as $query) {
if ($query instanceof QueryInterface) {
$boolQuery->addMust($query->createElasticQuery());
}
}

$query = new \Elastica\Query($boolQuery);
$query->setFrom($page * $size);
$query->setSize($size);

/** @var ParameterInterface $parameter */
foreach ($parameterList as $parameter) {
if ($parameter instanceof ParameterInterface) {
$query = $parameter->addToElasticQuery($query);
}
}

$paginatorAdapter = $this->repository->createPaginatorAdapter($query);
$totalItems = $paginatorAdapter->getNbResults();
$results = $paginatorAdapter->getSlice(0, $size)->toArray();

return new PaginatedResult($results, $page, $size, $totalItems);
}

protected function executePaginatedOrmQuery(array $queryList, array $parameterList, int $page, int $size): PaginatedResult
{
$qb = $this->entityManager->createQueryBuilder()
->select('e')
->from($this->fqcn, 'e')
;

/** @var OrmQueryInterface $query */
foreach ($queryList as $query) {
if ($query instanceof OrmQueryInterface) {
$qb = $query->createOrmQuery($qb);
}
}

/** @var ParameterInterface $parameter */
foreach ($parameterList as $parameter) {
if ($parameter instanceof SizeParameter || $parameter instanceof FromParameter || $parameter instanceof PageParameter) {
continue;
}

if ($parameter instanceof ParameterInterface && method_exists($parameter, 'addToOrmQuery')) {
$parameter->addToOrmQuery($qb);
}
}

$qb->setFirstResult($page * $size);
$qb->setMaxResults($size);

$paginator = new Paginator($qb->getQuery());
$totalItems = count($paginator);
$data = iterator_to_array($paginator);

return new PaginatedResult($data, $page, $size, $totalItems);
}
}
3 changes: 3 additions & 0 deletions src/Finder/FinderInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

namespace MalteHuebner\DataQueryBundle\Finder;

use MalteHuebner\DataQueryBundle\PaginatedResult\PaginatedResult;

interface FinderInterface
{
public function executeQuery(array $queryList, array $parameterList): array;
public function executePaginatedQuery(array $queryList, array $parameterList, int $page, int $size): PaginatedResult;
}
44 changes: 44 additions & 0 deletions src/PaginatedResult/PaginatedResult.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php declare(strict_types=1);

namespace MalteHuebner\DataQueryBundle\PaginatedResult;

class PaginatedResult
{
public function __construct(
private readonly iterable $data,
private readonly int $page,
private readonly int $size,
private readonly int $totalItems,
) {
}

/** @return iterable<object> */
public function getData(): iterable
{
return $this->data;
}

public function getPage(): int
{
return $this->page;
}

public function getSize(): int
{
return $this->size;
}

public function getTotalItems(): int
{
return $this->totalItems;
}

public function getTotalPages(): int
{
if ($this->size === 0) {
return 0;
}

return (int) ceil($this->totalItems / $this->size);
}
}
51 changes: 51 additions & 0 deletions src/Parameter/PageParameter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php declare(strict_types=1);

namespace MalteHuebner\DataQueryBundle\Parameter;

use MalteHuebner\DataQueryBundle\Attribute\ParameterAttribute as DataQuery;
use Doctrine\ORM\AbstractQuery as AbstractOrmQuery;
use Doctrine\ORM\QueryBuilder;
use Elastica\Query;
use Symfony\Component\Validator\Constraints as Constraints;

class PageParameter extends AbstractParameter
{
#[Constraints\NotNull]
#[Constraints\Type('int')]
#[Constraints\Range(min: 0)]
private int $page;

private int $size = 10;

#[DataQuery\RequiredParameter(parameterName: 'page')]
public function setPage(int $page): PageParameter
{
$this->page = $page;
return $this;
}

public function getPage(): int
{
return $this->page;
}

public function setPageSize(int $size): PageParameter
{
$this->size = $size;
return $this;
}

#[\Override]
public function addToElasticQuery(Query $query): Query
{
return $query->setFrom($this->page * $this->size);
}

#[\Override]
public function addToOrmQuery(QueryBuilder $queryBuilder): AbstractOrmQuery
{
$queryBuilder->setFirstResult($this->page * $this->size);

return $queryBuilder->getQuery();
}
}
5 changes: 5 additions & 0 deletions src/Parameter/SizeParameter.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ public function setSize(int $size): SizeParameter
return $this;
}

public function getSize(): int
{
return $this->size;
}

#[\Override]
public function addToElasticQuery(Query $query): Query
{
Expand Down
Loading