Skip to content

Commit

Permalink
Merge 3.2
Browse files Browse the repository at this point in the history
  • Loading branch information
soyuka committed Jan 19, 2024
2 parents f299bba + ac8031e commit 2e9b9ff
Show file tree
Hide file tree
Showing 6 changed files with 313 additions and 117 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Expand Up @@ -56,6 +56,14 @@ These namespaces are deprecated:

Most of the classes have moved to `ApiPlatform\Metadata`.

## v3.2.12

### Bug fixes

* [1c1023a71](https://github.com/api-platform/core/commit/1c1023a71dd6ea9302c6065aade72f3e93deb6b6) fix: better generics support for State\ProcessorInterface (#6103)
* [dcab6c79e](https://github.com/api-platform/core/commit/dcab6c79e96ccf8351d855013474d32d5cf129e5) fix(jsonschema): keep integer and number properties draft 4 compliant (#6098)
* [ef4b261f1](https://github.com/api-platform/core/commit/ef4b261f1e4d67d064be9745d2b9e0c68d3032aa) fix(graphql): remove count query if paginationInfo is not requested (#6068)

## v3.2.11

### Bug fixes
Expand Down
108 changes: 66 additions & 42 deletions src/GraphQl/Resolver/Stage/SerializeStage.php
Expand Up @@ -88,7 +88,7 @@ public function __invoke(object|array|null $itemOrCollection, string $resourceCl
} else {
$data = 'cursor' === $this->pagination->getGraphQlPaginationType($operation) ?
$this->serializeCursorBasedPaginatedCollection($itemOrCollection, $normalizationContext, $context) :
$this->serializePageBasedPaginatedCollection($itemOrCollection, $normalizationContext);
$this->serializePageBasedPaginatedCollection($itemOrCollection, $normalizationContext, $context);
}
}

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

$selection = $context['info']->getFieldSelection(1);

$offset = 0;
$totalItems = 1; // For partial pagination, always consider there is at least one item.
$nbPageItems = $collection->count();
if (isset($args['after'])) {
$after = base64_decode($args['after'], true);
if (false === $after || '' === $args['after']) {
throw new \UnexpectedValueException('' === $args['after'] ? 'Empty cursor is invalid' : sprintf('Cursor %s is invalid', $args['after']));
$data = ['edges' => []];
if (isset($selection['pageInfo']) || isset($selection['totalCount']) || isset($selection['edges']['cursor'])) {
$nbPageItems = $collection->count();
if (isset($args['after'])) {
$after = base64_decode($args['after'], true);
if (false === $after || '' === $args['after']) {
throw new \UnexpectedValueException('' === $args['after'] ? 'Empty cursor is invalid' : sprintf('Cursor %s is invalid', $args['after']));
}
$offset = 1 + (int) $after;
}
$offset = 1 + (int) $after;
}

if ($collection instanceof PaginatorInterface) {
$totalItems = $collection->getTotalItems();

if (isset($args['before'])) {
$before = base64_decode($args['before'], true);
if (false === $before || '' === $args['before']) {
throw new \UnexpectedValueException('' === $args['before'] ? 'Empty cursor is invalid' : sprintf('Cursor %s is invalid', $args['before']));
if ($collection instanceof PaginatorInterface && (isset($selection['pageInfo']) || isset($selection['totalCount']))) {
$totalItems = $collection->getTotalItems();
if (isset($args['before'])) {
$before = base64_decode($args['before'], true);
if (false === $before || '' === $args['before']) {
throw new \UnexpectedValueException('' === $args['before'] ? 'Empty cursor is invalid' : sprintf('Cursor %s is invalid', $args['before']));
}
$offset = (int) $before - $nbPageItems;
}
if (isset($args['last']) && !isset($args['before'])) {
$offset = $totalItems - $args['last'];
}
$offset = (int) $before - $nbPageItems;
}
if (isset($args['last']) && !isset($args['before'])) {
$offset = $totalItems - $args['last'];
}
}

$offset = 0 > $offset ? 0 : $offset;

$data = $this->getDefaultCursorBasedPaginatedData();
if ($totalItems > 0) {
$data['pageInfo']['startCursor'] = base64_encode((string) $offset);
$end = $offset + $nbPageItems - 1;
$data['pageInfo']['endCursor'] = base64_encode((string) ($end >= 0 ? $end : 0));
$data['pageInfo']['hasPreviousPage'] = $offset > 0;
if ($collection instanceof PaginatorInterface) {
$data['totalCount'] = $totalItems;
$itemsPerPage = $collection->getItemsPerPage();
$data['pageInfo']['hasNextPage'] = (float) ($itemsPerPage > 0 ? $offset % $itemsPerPage : $offset) + $itemsPerPage * $collection->getCurrentPage() < $totalItems;
$offset = max(0, $offset);

$data = $this->getDefaultCursorBasedPaginatedData();
if ((isset($selection['pageInfo']) || isset($selection['totalCount'])) && $totalItems > 0) {
isset($selection['pageInfo']['startCursor']) && $data['pageInfo']['startCursor'] = base64_encode((string) $offset);
$end = $offset + $nbPageItems - 1;
isset($selection['pageInfo']['endCursor']) && $data['pageInfo']['endCursor'] = base64_encode((string) max($end, 0));
isset($selection['pageInfo']['hasPreviousPage']) && $data['pageInfo']['hasPreviousPage'] = $offset > 0;
if ($collection instanceof PaginatorInterface) {
isset($selection['totalCount']) && $data['totalCount'] = $totalItems;

$itemsPerPage = $collection->getItemsPerPage();
isset($selection['pageInfo']['hasNextPage']) && $data['pageInfo']['hasNextPage'] = (float) ($itemsPerPage > 0 ? $offset % $itemsPerPage : $offset) + $itemsPerPage * $collection->getCurrentPage() < $totalItems;
}
}
}

$index = 0;
foreach ($collection as $object) {
$data['edges'][$index] = [
$edge = [
'node' => $this->normalizer->normalize($object, ItemNormalizer::FORMAT, $normalizationContext),
'cursor' => base64_encode((string) ($index + $offset)),
];
if (isset($selection['edges']['cursor'])) {
$edge['cursor'] = base64_encode((string) ($index + $offset));
}
$data['edges'][$index] = $edge;
++$index;
}

Expand All @@ -173,17 +181,33 @@ private function serializeCursorBasedPaginatedCollection(iterable $collection, a
/**
* @throws \LogicException
*/
private function serializePageBasedPaginatedCollection(iterable $collection, array $normalizationContext): array
private function serializePageBasedPaginatedCollection(iterable $collection, array $normalizationContext, array $context): array
{
if (!($collection instanceof PaginatorInterface)) {
throw new \LogicException(sprintf('Collection returned by the collection data provider must implement %s.', PaginatorInterface::class));
$data = ['collection' => []];

$selection = $context['info']->getFieldSelection(1);
if (isset($selection['paginationInfo'])) {
$data['paginationInfo'] = [];
if (isset($selection['paginationInfo']['itemsPerPage'])) {
if (!($collection instanceof PartialPaginatorInterface)) {
throw new \LogicException(sprintf('Collection returned by the collection data provider must implement %s to return itemsPerPage field.', PartialPaginatorInterface::class));
}
$data['paginationInfo']['itemsPerPage'] = $collection->getItemsPerPage();
}
if (isset($selection['paginationInfo']['totalCount'])) {
if (!($collection instanceof PaginatorInterface)) {
throw new \LogicException(sprintf('Collection returned by the collection data provider must implement %s to return totalCount field.', PaginatorInterface::class));
}
$data['paginationInfo']['totalCount'] = $collection->getTotalItems();
}
if (isset($selection['paginationInfo']['lastPage'])) {
if (!($collection instanceof PaginatorInterface)) {
throw new \LogicException(sprintf('Collection returned by the collection data provider must implement %s to return lastPage field.', PaginatorInterface::class));
}
$data['paginationInfo']['lastPage'] = $collection->getLastPage();
}
}

$data = $this->getDefaultPageBasedPaginatedData();
$data['paginationInfo']['totalCount'] = $collection->getTotalItems();
$data['paginationInfo']['lastPage'] = $collection->getLastPage();
$data['paginationInfo']['itemsPerPage'] = $collection->getItemsPerPage();

foreach ($collection as $object) {
$data['collection'][] = $this->normalizer->normalize($object, ItemNormalizer::FORMAT, $normalizationContext);
}
Expand Down
108 changes: 66 additions & 42 deletions src/GraphQl/State/Processor/NormalizeProcessor.php
Expand Up @@ -98,7 +98,7 @@ private function getData(mixed $itemOrCollection, GraphQlOperation $operation, a
} else {
$data = 'cursor' === $this->pagination->getGraphQlPaginationType($operation) ?
$this->serializeCursorBasedPaginatedCollection($itemOrCollection, $normalizationContext, $context) :
$this->serializePageBasedPaginatedCollection($itemOrCollection, $normalizationContext);
$this->serializePageBasedPaginatedCollection($itemOrCollection, $normalizationContext, $context);
}
}

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

$selection = $context['info']->getFieldSelection(1);

$offset = 0;
$totalItems = 1; // For partial pagination, always consider there is at least one item.
$nbPageItems = $collection->count();
if (isset($args['after'])) {
$after = base64_decode($args['after'], true);
if (false === $after || '' === $args['after']) {
throw new \UnexpectedValueException('' === $args['after'] ? 'Empty cursor is invalid' : sprintf('Cursor %s is invalid', $args['after']));
$data = ['edges' => []];
if (isset($selection['pageInfo']) || isset($selection['totalCount']) || isset($selection['edges']['cursor'])) {
$nbPageItems = $collection->count();
if (isset($args['after'])) {
$after = base64_decode($args['after'], true);
if (false === $after || '' === $args['after']) {
throw new \UnexpectedValueException('' === $args['after'] ? 'Empty cursor is invalid' : sprintf('Cursor %s is invalid', $args['after']));
}
$offset = 1 + (int) $after;
}
$offset = 1 + (int) $after;
}

if ($collection instanceof PaginatorInterface) {
$totalItems = $collection->getTotalItems();

if (isset($args['before'])) {
$before = base64_decode($args['before'], true);
if (false === $before || '' === $args['before']) {
throw new \UnexpectedValueException('' === $args['before'] ? 'Empty cursor is invalid' : sprintf('Cursor %s is invalid', $args['before']));
if ($collection instanceof PaginatorInterface && (isset($selection['pageInfo']) || isset($selection['totalCount']))) {
$totalItems = $collection->getTotalItems();
if (isset($args['before'])) {
$before = base64_decode($args['before'], true);
if (false === $before || '' === $args['before']) {
throw new \UnexpectedValueException('' === $args['before'] ? 'Empty cursor is invalid' : sprintf('Cursor %s is invalid', $args['before']));
}
$offset = (int) $before - $nbPageItems;
}
if (isset($args['last']) && !isset($args['before'])) {
$offset = $totalItems - $args['last'];
}
$offset = (int) $before - $nbPageItems;
}
if (isset($args['last']) && !isset($args['before'])) {
$offset = $totalItems - $args['last'];
}
}

$offset = 0 > $offset ? 0 : $offset;

$data = $this->getDefaultCursorBasedPaginatedData();
if ($totalItems > 0) {
$data['pageInfo']['startCursor'] = base64_encode((string) $offset);
$end = $offset + $nbPageItems - 1;
$data['pageInfo']['endCursor'] = base64_encode((string) ($end >= 0 ? $end : 0));
$data['pageInfo']['hasPreviousPage'] = $offset > 0;
if ($collection instanceof PaginatorInterface) {
$data['totalCount'] = $totalItems;
$itemsPerPage = $collection->getItemsPerPage();
$data['pageInfo']['hasNextPage'] = (float) ($itemsPerPage > 0 ? $offset % $itemsPerPage : $offset) + $itemsPerPage * $collection->getCurrentPage() < $totalItems;
$offset = max(0, $offset);

$data = $this->getDefaultCursorBasedPaginatedData();
if ((isset($selection['pageInfo']) || isset($selection['totalCount'])) && $totalItems > 0) {
isset($selection['pageInfo']['startCursor']) && $data['pageInfo']['startCursor'] = base64_encode((string) $offset);
$end = $offset + $nbPageItems - 1;
isset($selection['pageInfo']['endCursor']) && $data['pageInfo']['endCursor'] = base64_encode((string) max($end, 0));
isset($selection['pageInfo']['hasPreviousPage']) && $data['pageInfo']['hasPreviousPage'] = $offset > 0;
if ($collection instanceof PaginatorInterface) {
isset($selection['totalCount']) && $data['totalCount'] = $totalItems;

$itemsPerPage = $collection->getItemsPerPage();
isset($selection['pageInfo']['hasNextPage']) && $data['pageInfo']['hasNextPage'] = (float) ($itemsPerPage > 0 ? $offset % $itemsPerPage : $offset) + $itemsPerPage * $collection->getCurrentPage() < $totalItems;
}
}
}

$index = 0;
foreach ($collection as $object) {
$data['edges'][$index] = [
$edge = [
'node' => $this->normalizer->normalize($object, ItemNormalizer::FORMAT, $normalizationContext),
'cursor' => base64_encode((string) ($index + $offset)),
];
if (isset($selection['edges']['cursor'])) {
$edge['cursor'] = base64_encode((string) ($index + $offset));
}
$data['edges'][$index] = $edge;
++$index;
}

Expand All @@ -185,17 +193,33 @@ private function serializeCursorBasedPaginatedCollection(iterable $collection, a
/**
* @throws \LogicException
*/
private function serializePageBasedPaginatedCollection(iterable $collection, array $normalizationContext): array
private function serializePageBasedPaginatedCollection(iterable $collection, array $normalizationContext, array $context): array
{
if (!($collection instanceof PaginatorInterface)) {
throw new \LogicException(sprintf('Collection returned by the collection data provider must implement %s.', PaginatorInterface::class));
$data = ['collection' => []];

$selection = $context['info']->getFieldSelection(1);
if (isset($selection['paginationInfo'])) {
$data['paginationInfo'] = [];
if (isset($selection['paginationInfo']['itemsPerPage'])) {
if (!($collection instanceof PartialPaginatorInterface)) {
throw new \LogicException(sprintf('Collection returned by the collection data provider must implement %s to return itemsPerPage field.', PartialPaginatorInterface::class));
}
$data['paginationInfo']['itemsPerPage'] = $collection->getItemsPerPage();
}
if (isset($selection['paginationInfo']['totalCount'])) {
if (!($collection instanceof PaginatorInterface)) {
throw new \LogicException(sprintf('Collection returned by the collection data provider must implement %s to return totalCount field.', PaginatorInterface::class));
}
$data['paginationInfo']['totalCount'] = $collection->getTotalItems();
}
if (isset($selection['paginationInfo']['lastPage'])) {
if (!($collection instanceof PaginatorInterface)) {
throw new \LogicException(sprintf('Collection returned by the collection data provider must implement %s to return lastPage field.', PaginatorInterface::class));
}
$data['paginationInfo']['lastPage'] = $collection->getLastPage();
}
}

$data = $this->getDefaultPageBasedPaginatedData();
$data['paginationInfo']['totalCount'] = $collection->getTotalItems();
$data['paginationInfo']['lastPage'] = $collection->getLastPage();
$data['paginationInfo']['itemsPerPage'] = $collection->getItemsPerPage();

foreach ($collection as $object) {
$data['collection'][] = $this->normalizer->normalize($object, ItemNormalizer::FORMAT, $normalizationContext);
}
Expand Down

0 comments on commit 2e9b9ff

Please sign in to comment.