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
5 changes: 3 additions & 2 deletions docs/driver.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ The Driver class
The Driver class is the gateway to much of the functionality of this library.
It has many options and top-level functions, detailed here.

Creating a ``Driver`` with all config options
---------------------------------------------

Creating a Driver with all config options
=========================================

.. code-block:: php

Expand Down
27 changes: 25 additions & 2 deletions docs/events.rst
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,19 @@ user, create a listener.
}
);

The ``QueryBuilder`` event has one function in addition to getters for
Functions of the ``QueryBuilder`` event in addition to getters for
all resolve parameters:

* ``getQueryBuilder`` - Will return a query builder with the user specified
filters already applied.

* ``getOffset`` - Will return the offset for the query. The QueryBuilder passed
to the event is not modified with the offset and limit yet. So if you have a
large dataset and need to fetch it within the event, you may use this method
to get the offset.
* ``getLimit`` - Will return the limit for the query. The QueryBuilder passed
to the event is not modified with the offset and limit yet. So if you have a
large dataset and need to fetch it within the event, you may use this method
to get the limit.

Criteria Event
==============
Expand Down Expand Up @@ -148,6 +155,22 @@ all resolve parameters:
if you need to fetch the collection to apply additional criteria.
* ``setCollection`` - Will set the collection object. This is useful if you
need to filter the collection directly.
* ``getOffset`` - Will return the projected offset for the collection. The collection passed
to the event is not modified with the offset and limit yet. So if you have a
large dataset and need to fetch it within the event, you may use this method
to get the expected offset.
* ``getLimit`` - Will return the projectd limit for the collection. The collection passed
to the event is not modified with the offset and limit yet. So if you have a
large dataset and need to fetch it within the event, you may use this method
to get the expected limit.

.. note::

The offset and limit is calculated before this event is fired and calculated
again after the event. This is because the collection may be fetched and
filtered before the limit is applied. The offset and limit are recalculated
after the event is fired to ensure the correct data is returned.


Modify an Entity Definition
===========================
Expand Down
12 changes: 12 additions & 0 deletions src/Event/Criteria.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public function __construct(
protected readonly string $eventName,
protected readonly DoctrineCriteria $criteria,
protected Collection $collection,
protected readonly int $offset,
protected readonly int $limit,
protected readonly mixed $objectValue,
protected readonly array $args,
protected readonly mixed $context,
Expand Down Expand Up @@ -54,6 +56,16 @@ public function setCollection(Collection $collection): void
$this->collection = $collection;
}

public function getOffset(): int
{
return $this->offset;
}

public function getLimit(): int
{
return $this->limit;
}

public function getObjectValue(): mixed
{
return $this->objectValue;
Expand Down
14 changes: 13 additions & 1 deletion src/Event/QueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ class QueryBuilder implements
{
/** @param mixed[] $args */
public function __construct(
protected readonly DoctrineQueryBuilder $queryBuilder,
protected readonly string $eventName,
protected readonly DoctrineQueryBuilder $queryBuilder,
protected readonly int $offset,
protected readonly int $limit,
protected readonly mixed $objectValue,
protected readonly array $args,
protected readonly mixed $context,
Expand All @@ -35,6 +37,16 @@ public function getQueryBuilder(): DoctrineQueryBuilder
return $this->queryBuilder;
}

public function getOffset(): int
{
return $this->offset;
}

public function getLimit(): int
{
return $this->limit;
}

public function getObjectValue(): mixed
{
return $this->objectValue;
Expand Down
11 changes: 9 additions & 2 deletions src/Resolve/ResolveCollectionFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ protected function buildPagination(
$paginationFields[$field] = (int) base64_decode($value, true);
}

// Calculate offset and limit
$itemCount = count($collection->matching($criteria));
$offsetAndLimit = $this->calculateOffsetAndLimit($resolve[3]->fieldName, $entityClassName, $targetClassName, $paginationFields, $itemCount);

/**
* Fire the event dispatcher using the passed event name.
*/
Expand All @@ -157,17 +161,20 @@ protected function buildPagination(
$criteriaEventName,
$criteria,
$collection,
$offsetAndLimit['offset'],
$offsetAndLimit['limit'],
...$resolve,
);

$this->eventDispatcher->dispatch($event);
$collection = $event->getCollection();
}

$itemCount = count($collection->matching($criteria));
// Recalculate offset and limit after Criteria event
$itemCount = count($collection->matching($criteria));
$offsetAndLimit = $this->calculateOffsetAndLimit($resolve[3]->fieldName, $entityClassName, $targetClassName, $paginationFields, $itemCount);

// Add offset and limit after Criteria event
$offsetAndLimit = $this->calculateOffsetAndLimit($resolve[3]->fieldName, $entityClassName, $targetClassName, $paginationFields, $itemCount);
if ($offsetAndLimit['offset']) {
$criteria->setFirstResult($offsetAndLimit['offset']);
}
Expand Down
20 changes: 11 additions & 9 deletions src/Resolve/ResolveEntityFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,28 +90,30 @@ public function buildPagination(

$offsetAndLimit = $this->calculateOffsetAndLimit($entity, $paginationFields);

if ($offsetAndLimit['offset']) {
$queryBuilder->setFirstResult($offsetAndLimit['offset']);
}

if ($offsetAndLimit['limit']) {
$queryBuilder->setMaxResults($offsetAndLimit['limit']);
}

/**
* Fire the event dispatcher using the passed event name.
* Include all resolve variables.
*/
if ($eventName) {
$this->eventDispatcher->dispatch(
new QueryBuilderEvent(
$queryBuilder,
$eventName,
$queryBuilder,
(int) $offsetAndLimit['offset'],
(int) $offsetAndLimit['limit'],
...$resolve,
),
);
}

if ($offsetAndLimit['offset']) {
$queryBuilder->setFirstResult($offsetAndLimit['offset']);
}

if ($offsetAndLimit['limit']) {
$queryBuilder->setMaxResults($offsetAndLimit['limit']);
}

$edgesAndCursors = $this->buildEdgesAndCursors($queryBuilder, $offsetAndLimit, $paginationFields);

return [
Expand Down
7 changes: 6 additions & 1 deletion test/Feature/Event/CriteriaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,10 @@ function (CriteriaEvent $event): void {

public function testEventFilterCollection(): void
{
$driver = new Driver($this->getEntityManager(), new Config(['group' => 'CriteriaEvent']));
$driver = new Driver($this->getEntityManager(), new Config([
'group' => 'CriteriaEvent',
'limit' => 25,
]));

$driver->get(EventDispatcher::class)->subscribeTo(
Artist::class . '.performances.criteria',
Expand All @@ -109,6 +112,8 @@ static function ($performance) {
},
));

$this->assertEquals(0, $event->getOffset());
$this->assertEquals(25, $event->getLimit());
$this->assertInstanceOf(Collection::class, $event->getCollection());
$this->assertInstanceOf(Artist::class, $event->getObjectValue());
$this->assertEquals('contextTest', $event->getContext());
Expand Down
5 changes: 4 additions & 1 deletion test/Feature/Event/FilterQueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace ApiSkeletonsTest\Doctrine\ORM\GraphQL\Feature\Event;

use ApiSkeletons\Doctrine\ORM\GraphQL\Config;
use ApiSkeletons\Doctrine\ORM\GraphQL\Driver;
use ApiSkeletons\Doctrine\ORM\GraphQL\Event\QueryBuilder as QueryBuilderEvent;
use ApiSkeletonsTest\Doctrine\ORM\GraphQL\AbstractTest;
Expand All @@ -18,11 +19,13 @@ class FilterQueryBuilderTest extends AbstractTest
{
public function testEvent(): void
{
$driver = new Driver($this->getEntityManager());
$driver = new Driver($this->getEntityManager(), new Config(['limit' => 10]));
$driver->get(EventDispatcher::class)->subscribeTo(
'artist.querybuilder',
function (QueryBuilderEvent $event): void {
$this->assertInstanceOf(QueryBuilder::class, $event->getQueryBuilder());
$this->assertEquals(0, $event->getOffset());
$this->assertEquals(10, $event->getLimit());
},
);

Expand Down
Loading