Skip to content

Commit 5144e62

Browse files
author
Xavier Leune
committed
fix(graphql): remove count query if paginationInfo is not requested
1 parent ee1e4ee commit 5144e62

File tree

5 files changed

+305
-117
lines changed

5 files changed

+305
-117
lines changed

src/GraphQl/Resolver/Stage/SerializeStage.php

+66-42
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public function __invoke(object|array|null $itemOrCollection, string $resourceCl
8888
} else {
8989
$data = 'cursor' === $this->pagination->getGraphQlPaginationType($operation) ?
9090
$this->serializeCursorBasedPaginatedCollection($itemOrCollection, $normalizationContext, $context) :
91-
$this->serializePageBasedPaginatedCollection($itemOrCollection, $normalizationContext);
91+
$this->serializePageBasedPaginatedCollection($itemOrCollection, $normalizationContext, $context);
9292
}
9393
}
9494

@@ -117,53 +117,61 @@ private function serializeCursorBasedPaginatedCollection(iterable $collection, a
117117
throw new \LogicException(sprintf('Collection returned by the collection data provider must implement %s or %s.', PaginatorInterface::class, PartialPaginatorInterface::class));
118118
}
119119

120+
$selection = $context['info']->getFieldSelection(1);
121+
120122
$offset = 0;
121123
$totalItems = 1; // For partial pagination, always consider there is at least one item.
122-
$nbPageItems = $collection->count();
123-
if (isset($args['after'])) {
124-
$after = base64_decode($args['after'], true);
125-
if (false === $after || '' === $args['after']) {
126-
throw new \UnexpectedValueException('' === $args['after'] ? 'Empty cursor is invalid' : sprintf('Cursor %s is invalid', $args['after']));
124+
$data = ['edges' => []];
125+
if (isset($selection['pageInfo']) || isset($selection['totalCount']) || isset($selection['edges']['cursor'])) {
126+
$nbPageItems = $collection->count();
127+
if (isset($args['after'])) {
128+
$after = base64_decode($args['after'], true);
129+
if (false === $after || '' === $args['after']) {
130+
throw new \UnexpectedValueException('' === $args['after'] ? 'Empty cursor is invalid' : sprintf('Cursor %s is invalid', $args['after']));
131+
}
132+
$offset = 1 + (int) $after;
127133
}
128-
$offset = 1 + (int) $after;
129-
}
130134

131-
if ($collection instanceof PaginatorInterface) {
132-
$totalItems = $collection->getTotalItems();
133-
134-
if (isset($args['before'])) {
135-
$before = base64_decode($args['before'], true);
136-
if (false === $before || '' === $args['before']) {
137-
throw new \UnexpectedValueException('' === $args['before'] ? 'Empty cursor is invalid' : sprintf('Cursor %s is invalid', $args['before']));
135+
if ($collection instanceof PaginatorInterface && (isset($selection['pageInfo']) || isset($selection['totalCount']))) {
136+
$totalItems = $collection->getTotalItems();
137+
if (isset($args['before'])) {
138+
$before = base64_decode($args['before'], true);
139+
if (false === $before || '' === $args['before']) {
140+
throw new \UnexpectedValueException('' === $args['before'] ? 'Empty cursor is invalid' : sprintf('Cursor %s is invalid', $args['before']));
141+
}
142+
$offset = (int) $before - $nbPageItems;
143+
}
144+
if (isset($args['last']) && !isset($args['before'])) {
145+
$offset = $totalItems - $args['last'];
138146
}
139-
$offset = (int) $before - $nbPageItems;
140-
}
141-
if (isset($args['last']) && !isset($args['before'])) {
142-
$offset = $totalItems - $args['last'];
143147
}
144-
}
145148

146-
$offset = 0 > $offset ? 0 : $offset;
147-
148-
$data = $this->getDefaultCursorBasedPaginatedData();
149-
if ($totalItems > 0) {
150-
$data['pageInfo']['startCursor'] = base64_encode((string) $offset);
151-
$end = $offset + $nbPageItems - 1;
152-
$data['pageInfo']['endCursor'] = base64_encode((string) ($end >= 0 ? $end : 0));
153-
$data['pageInfo']['hasPreviousPage'] = $offset > 0;
154-
if ($collection instanceof PaginatorInterface) {
155-
$data['totalCount'] = $totalItems;
156-
$itemsPerPage = $collection->getItemsPerPage();
157-
$data['pageInfo']['hasNextPage'] = (float) ($itemsPerPage > 0 ? $offset % $itemsPerPage : $offset) + $itemsPerPage * $collection->getCurrentPage() < $totalItems;
149+
$offset = max(0, $offset);
150+
151+
$data = $this->getDefaultCursorBasedPaginatedData();
152+
if ((isset($selection['pageInfo']) || isset($selection['totalCount'])) && $totalItems > 0) {
153+
isset($selection['pageInfo']['startCursor']) && $data['pageInfo']['startCursor'] = base64_encode((string) $offset);
154+
$end = $offset + $nbPageItems - 1;
155+
isset($selection['pageInfo']['endCursor']) && $data['pageInfo']['endCursor'] = base64_encode((string) max($end, 0));
156+
isset($selection['pageInfo']['hasPreviousPage']) && $data['pageInfo']['hasPreviousPage'] = $offset > 0;
157+
if ($collection instanceof PaginatorInterface) {
158+
isset($selection['totalCount']) && $data['totalCount'] = $totalItems;
159+
160+
$itemsPerPage = $collection->getItemsPerPage();
161+
isset($selection['pageInfo']['hasNextPage']) && $data['pageInfo']['hasNextPage'] = (float) ($itemsPerPage > 0 ? $offset % $itemsPerPage : $offset) + $itemsPerPage * $collection->getCurrentPage() < $totalItems;
162+
}
158163
}
159164
}
160165

161166
$index = 0;
162167
foreach ($collection as $object) {
163-
$data['edges'][$index] = [
168+
$edge = [
164169
'node' => $this->normalizer->normalize($object, ItemNormalizer::FORMAT, $normalizationContext),
165-
'cursor' => base64_encode((string) ($index + $offset)),
166170
];
171+
if (isset($selection['edges']['cursor'])) {
172+
$edge['cursor'] = base64_encode((string) ($index + $offset));
173+
}
174+
$data['edges'][$index] = $edge;
167175
++$index;
168176
}
169177

@@ -173,17 +181,33 @@ private function serializeCursorBasedPaginatedCollection(iterable $collection, a
173181
/**
174182
* @throws \LogicException
175183
*/
176-
private function serializePageBasedPaginatedCollection(iterable $collection, array $normalizationContext): array
184+
private function serializePageBasedPaginatedCollection(iterable $collection, array $normalizationContext, array $context): array
177185
{
178-
if (!($collection instanceof PaginatorInterface)) {
179-
throw new \LogicException(sprintf('Collection returned by the collection data provider must implement %s.', PaginatorInterface::class));
186+
$data = ['collection' => []];
187+
188+
$selection = $context['info']->getFieldSelection(1);
189+
if (isset($selection['paginationInfo'])) {
190+
$data['paginationInfo'] = [];
191+
if (isset($selection['paginationInfo']['itemsPerPage'])) {
192+
if (!($collection instanceof PartialPaginatorInterface)) {
193+
throw new \LogicException(sprintf('Collection returned by the collection data provider must implement %s to return itemsPerPage field.', PartialPaginatorInterface::class));
194+
}
195+
$data['paginationInfo']['itemsPerPage'] = $collection->getItemsPerPage();
196+
}
197+
if (isset($selection['paginationInfo']['totalCount'])) {
198+
if (!($collection instanceof PaginatorInterface)) {
199+
throw new \LogicException(sprintf('Collection returned by the collection data provider must implement %s to return totalCount field.', PaginatorInterface::class));
200+
}
201+
$data['paginationInfo']['totalCount'] = $collection->getTotalItems();
202+
}
203+
if (isset($selection['paginationInfo']['lastPage'])) {
204+
if (!($collection instanceof PaginatorInterface)) {
205+
throw new \LogicException(sprintf('Collection returned by the collection data provider must implement %s to return lastPage field.', PaginatorInterface::class));
206+
}
207+
$data['paginationInfo']['lastPage'] = $collection->getLastPage();
208+
}
180209
}
181210

182-
$data = $this->getDefaultPageBasedPaginatedData();
183-
$data['paginationInfo']['totalCount'] = $collection->getTotalItems();
184-
$data['paginationInfo']['lastPage'] = $collection->getLastPage();
185-
$data['paginationInfo']['itemsPerPage'] = $collection->getItemsPerPage();
186-
187211
foreach ($collection as $object) {
188212
$data['collection'][] = $this->normalizer->normalize($object, ItemNormalizer::FORMAT, $normalizationContext);
189213
}

src/GraphQl/State/Processor/NormalizeProcessor.php

+66-42
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ private function getData(mixed $itemOrCollection, GraphQlOperation $operation, a
9898
} else {
9999
$data = 'cursor' === $this->pagination->getGraphQlPaginationType($operation) ?
100100
$this->serializeCursorBasedPaginatedCollection($itemOrCollection, $normalizationContext, $context) :
101-
$this->serializePageBasedPaginatedCollection($itemOrCollection, $normalizationContext);
101+
$this->serializePageBasedPaginatedCollection($itemOrCollection, $normalizationContext, $context);
102102
}
103103
}
104104

@@ -129,53 +129,61 @@ private function serializeCursorBasedPaginatedCollection(iterable $collection, a
129129
throw new \LogicException(sprintf('Collection returned by the collection data provider must implement %s or %s.', PaginatorInterface::class, PartialPaginatorInterface::class));
130130
}
131131

132+
$selection = $context['info']->getFieldSelection(1);
133+
132134
$offset = 0;
133135
$totalItems = 1; // For partial pagination, always consider there is at least one item.
134-
$nbPageItems = $collection->count();
135-
if (isset($args['after'])) {
136-
$after = base64_decode($args['after'], true);
137-
if (false === $after || '' === $args['after']) {
138-
throw new \UnexpectedValueException('' === $args['after'] ? 'Empty cursor is invalid' : sprintf('Cursor %s is invalid', $args['after']));
136+
$data = ['edges' => []];
137+
if (isset($selection['pageInfo']) || isset($selection['totalCount']) || isset($selection['edges']['cursor'])) {
138+
$nbPageItems = $collection->count();
139+
if (isset($args['after'])) {
140+
$after = base64_decode($args['after'], true);
141+
if (false === $after || '' === $args['after']) {
142+
throw new \UnexpectedValueException('' === $args['after'] ? 'Empty cursor is invalid' : sprintf('Cursor %s is invalid', $args['after']));
143+
}
144+
$offset = 1 + (int) $after;
139145
}
140-
$offset = 1 + (int) $after;
141-
}
142146

143-
if ($collection instanceof PaginatorInterface) {
144-
$totalItems = $collection->getTotalItems();
145-
146-
if (isset($args['before'])) {
147-
$before = base64_decode($args['before'], true);
148-
if (false === $before || '' === $args['before']) {
149-
throw new \UnexpectedValueException('' === $args['before'] ? 'Empty cursor is invalid' : sprintf('Cursor %s is invalid', $args['before']));
147+
if ($collection instanceof PaginatorInterface && (isset($selection['pageInfo']) || isset($selection['totalCount']))) {
148+
$totalItems = $collection->getTotalItems();
149+
if (isset($args['before'])) {
150+
$before = base64_decode($args['before'], true);
151+
if (false === $before || '' === $args['before']) {
152+
throw new \UnexpectedValueException('' === $args['before'] ? 'Empty cursor is invalid' : sprintf('Cursor %s is invalid', $args['before']));
153+
}
154+
$offset = (int) $before - $nbPageItems;
155+
}
156+
if (isset($args['last']) && !isset($args['before'])) {
157+
$offset = $totalItems - $args['last'];
150158
}
151-
$offset = (int) $before - $nbPageItems;
152-
}
153-
if (isset($args['last']) && !isset($args['before'])) {
154-
$offset = $totalItems - $args['last'];
155159
}
156-
}
157160

158-
$offset = 0 > $offset ? 0 : $offset;
159-
160-
$data = $this->getDefaultCursorBasedPaginatedData();
161-
if ($totalItems > 0) {
162-
$data['pageInfo']['startCursor'] = base64_encode((string) $offset);
163-
$end = $offset + $nbPageItems - 1;
164-
$data['pageInfo']['endCursor'] = base64_encode((string) ($end >= 0 ? $end : 0));
165-
$data['pageInfo']['hasPreviousPage'] = $offset > 0;
166-
if ($collection instanceof PaginatorInterface) {
167-
$data['totalCount'] = $totalItems;
168-
$itemsPerPage = $collection->getItemsPerPage();
169-
$data['pageInfo']['hasNextPage'] = (float) ($itemsPerPage > 0 ? $offset % $itemsPerPage : $offset) + $itemsPerPage * $collection->getCurrentPage() < $totalItems;
161+
$offset = max(0, $offset);
162+
163+
$data = $this->getDefaultCursorBasedPaginatedData();
164+
if ((isset($selection['pageInfo']) || isset($selection['totalCount'])) && $totalItems > 0) {
165+
isset($selection['pageInfo']['startCursor']) && $data['pageInfo']['startCursor'] = base64_encode((string) $offset);
166+
$end = $offset + $nbPageItems - 1;
167+
isset($selection['pageInfo']['endCursor']) && $data['pageInfo']['endCursor'] = base64_encode((string) max($end, 0));
168+
isset($selection['pageInfo']['hasPreviousPage']) && $data['pageInfo']['hasPreviousPage'] = $offset > 0;
169+
if ($collection instanceof PaginatorInterface) {
170+
isset($selection['totalCount']) && $data['totalCount'] = $totalItems;
171+
172+
$itemsPerPage = $collection->getItemsPerPage();
173+
isset($selection['pageInfo']['hasNextPage']) && $data['pageInfo']['hasNextPage'] = (float) ($itemsPerPage > 0 ? $offset % $itemsPerPage : $offset) + $itemsPerPage * $collection->getCurrentPage() < $totalItems;
174+
}
170175
}
171176
}
172177

173178
$index = 0;
174179
foreach ($collection as $object) {
175-
$data['edges'][$index] = [
180+
$edge = [
176181
'node' => $this->normalizer->normalize($object, ItemNormalizer::FORMAT, $normalizationContext),
177-
'cursor' => base64_encode((string) ($index + $offset)),
178182
];
183+
if (isset($selection['edges']['cursor'])) {
184+
$edge['cursor'] = base64_encode((string) ($index + $offset));
185+
}
186+
$data['edges'][$index] = $edge;
179187
++$index;
180188
}
181189

@@ -185,17 +193,33 @@ private function serializeCursorBasedPaginatedCollection(iterable $collection, a
185193
/**
186194
* @throws \LogicException
187195
*/
188-
private function serializePageBasedPaginatedCollection(iterable $collection, array $normalizationContext): array
196+
private function serializePageBasedPaginatedCollection(iterable $collection, array $normalizationContext, array $context): array
189197
{
190-
if (!($collection instanceof PaginatorInterface)) {
191-
throw new \LogicException(sprintf('Collection returned by the collection data provider must implement %s.', PaginatorInterface::class));
198+
$data = ['collection' => []];
199+
200+
$selection = $context['info']->getFieldSelection(1);
201+
if (isset($selection['paginationInfo'])) {
202+
$data['paginationInfo'] = [];
203+
if (isset($selection['paginationInfo']['itemsPerPage'])) {
204+
if (!($collection instanceof PartialPaginatorInterface)) {
205+
throw new \LogicException(sprintf('Collection returned by the collection data provider must implement %s to return itemsPerPage field.', PartialPaginatorInterface::class));
206+
}
207+
$data['paginationInfo']['itemsPerPage'] = $collection->getItemsPerPage();
208+
}
209+
if (isset($selection['paginationInfo']['totalCount'])) {
210+
if (!($collection instanceof PaginatorInterface)) {
211+
throw new \LogicException(sprintf('Collection returned by the collection data provider must implement %s to return totalCount field.', PaginatorInterface::class));
212+
}
213+
$data['paginationInfo']['totalCount'] = $collection->getTotalItems();
214+
}
215+
if (isset($selection['paginationInfo']['lastPage'])) {
216+
if (!($collection instanceof PaginatorInterface)) {
217+
throw new \LogicException(sprintf('Collection returned by the collection data provider must implement %s to return lastPage field.', PaginatorInterface::class));
218+
}
219+
$data['paginationInfo']['lastPage'] = $collection->getLastPage();
220+
}
192221
}
193222

194-
$data = $this->getDefaultPageBasedPaginatedData();
195-
$data['paginationInfo']['totalCount'] = $collection->getTotalItems();
196-
$data['paginationInfo']['lastPage'] = $collection->getLastPage();
197-
$data['paginationInfo']['itemsPerPage'] = $collection->getItemsPerPage();
198-
199223
foreach ($collection as $object) {
200224
$data['collection'][] = $this->normalizer->normalize($object, ItemNormalizer::FORMAT, $normalizationContext);
201225
}

0 commit comments

Comments
 (0)