Skip to content

Commit 893b91e

Browse files
committed
refactor
1 parent a535803 commit 893b91e

File tree

3 files changed

+114
-76
lines changed

3 files changed

+114
-76
lines changed

src/Hydra/Serializer/PartialCollectionViewNormalizer.php

Lines changed: 27 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
use ApiPlatform\Metadata\Util\IriHelper;
2121
use ApiPlatform\State\Pagination\PaginatorInterface;
2222
use ApiPlatform\State\Pagination\PartialPaginatorInterface;
23+
use ApiPlatform\Hydra\State\Util\PaginationHelperTrait;
24+
use ApiPlatform\Hydra\PartialCollectionView;
2325
use Symfony\Component\PropertyAccess\PropertyAccess;
2426
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
2527
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
@@ -35,6 +37,7 @@
3537
final class PartialCollectionViewNormalizer implements NormalizerInterface, NormalizerAwareInterface
3638
{
3739
use HydraPrefixTrait;
40+
use PaginationHelperTrait;
3841
private readonly PropertyAccessorInterface $propertyAccessor;
3942

4043
/**
@@ -60,21 +63,11 @@ public function normalize(mixed $object, ?string $format = null, array $context
6063
throw new UnexpectedValueException('Expected data to be an array');
6164
}
6265

63-
$currentPage = $lastPage = $itemsPerPage = $pageTotalItems = null;
64-
if ($paginated = ($object instanceof PartialPaginatorInterface)) {
65-
if ($object instanceof PaginatorInterface) {
66-
$paginated = 1. !== $lastPage = $object->getLastPage();
67-
} else {
68-
$itemsPerPage = $object->getItemsPerPage();
69-
$pageTotalItems = (float) \count($object);
70-
}
71-
72-
$currentPage = $object->getCurrentPage();
66+
$paginated = ($object instanceof PartialPaginatorInterface);
67+
if ($paginated && $object instanceof PaginatorInterface) {
68+
$paginated = 1. !== $object->getLastPage();
7369
}
7470

75-
// TODO: This needs to be changed as well as I wrote in the CollectionFiltersNormalizer
76-
// We should not rely on the request_uri but instead rely on the UriTemplate
77-
// This needs that we implement the RFC and that we do more parsing before calling the serialization (MainController)
7871
$parsed = IriHelper::parseIri($context['uri'] ?? $context['request_uri'] ?? '/', $this->pageParameterName);
7972
$appliedFilters = $parsed['parameters'];
8073
unset($appliedFilters[$this->enabledParameterName]);
@@ -94,18 +87,35 @@ public function normalize(mixed $object, ?string $format = null, array $context
9487
$isPaginatedWithCursor = (bool) $cursorPaginationAttribute;
9588

9689
$hydraPrefix = $this->getHydraPrefix($context + $this->defaultContext);
97-
$data[$hydraPrefix.'view'] = ['@id' => null, '@type' => $hydraPrefix.'PartialCollectionView'];
9890

9991
if ($isPaginatedWithCursor) {
92+
$data[$hydraPrefix.'view'] = ['@id' => null, '@type' => $hydraPrefix.'PartialCollectionView'];
93+
10094
return $this->populateDataWithCursorBasedPagination($data, $parsed, $object, $cursorPaginationAttribute, $operation?->getUrlGenerationStrategy() ?? $this->urlGenerationStrategy, $hydraPrefix);
10195
}
10296

103-
$data[$hydraPrefix.'view']['@id'] = IriHelper::createIri($parsed['parts'], $parsed['parameters'], $this->pageParameterName, $paginated ? $currentPage : null, $operation?->getUrlGenerationStrategy() ?? $this->urlGenerationStrategy);
97+
$partialCollectionView = $this->getPartialCollectionView($object, $context['uri'] ?? $context['request_uri'] ?? '/', $this->pageParameterName, $this->enabledParameterName, $operation?->getUrlGenerationStrategy() ?? $this->urlGenerationStrategy);
98+
99+
$view = [
100+
'@id' => $partialCollectionView->id,
101+
'@type' => $hydraPrefix.'PartialCollectionView',
102+
];
103+
104+
if (null !== $partialCollectionView->first) {
105+
$view[$hydraPrefix.'first'] = $partialCollectionView->first;
106+
$view[$hydraPrefix.'last'] = $partialCollectionView->last;
107+
}
104108

105-
if ($paginated) {
106-
return $this->populateDataWithPagination($data, $parsed, $currentPage, $lastPage, $itemsPerPage, $pageTotalItems, $operation?->getUrlGenerationStrategy() ?? $this->urlGenerationStrategy, $hydraPrefix);
109+
if (null !== $partialCollectionView->previous) {
110+
$view[$hydraPrefix.'previous'] = $partialCollectionView->previous;
107111
}
108112

113+
if (null !== $partialCollectionView->next) {
114+
$view[$hydraPrefix.'next'] = $partialCollectionView->next;
115+
}
116+
117+
$data[$hydraPrefix.'view'] = $view;
118+
109119
return $data;
110120
}
111121

@@ -168,22 +178,4 @@ private function populateDataWithCursorBasedPagination(array $data, array $parse
168178

169179
return $data;
170180
}
171-
172-
private function populateDataWithPagination(array $data, array $parsed, ?float $currentPage, ?float $lastPage, ?float $itemsPerPage, ?float $pageTotalItems, ?int $urlGenerationStrategy, string $hydraPrefix): array
173-
{
174-
if (null !== $lastPage) {
175-
$data[$hydraPrefix.'view'][$hydraPrefix.'first'] = IriHelper::createIri($parsed['parts'], $parsed['parameters'], $this->pageParameterName, 1., $urlGenerationStrategy);
176-
$data[$hydraPrefix.'view'][$hydraPrefix.'last'] = IriHelper::createIri($parsed['parts'], $parsed['parameters'], $this->pageParameterName, $lastPage, $urlGenerationStrategy);
177-
}
178-
179-
if (1. !== $currentPage) {
180-
$data[$hydraPrefix.'view'][$hydraPrefix.'previous'] = IriHelper::createIri($parsed['parts'], $parsed['parameters'], $this->pageParameterName, $currentPage - 1., $urlGenerationStrategy);
181-
}
182-
183-
if ((null !== $lastPage && $currentPage < $lastPage) || (null === $lastPage && $pageTotalItems >= $itemsPerPage)) {
184-
$data[$hydraPrefix.'view'][$hydraPrefix.'next'] = IriHelper::createIri($parsed['parts'], $parsed['parameters'], $this->pageParameterName, $currentPage + 1., $urlGenerationStrategy);
185-
}
186-
187-
return $data;
188-
}
189181
}

src/Hydra/State/JsonStreamerProcessor.php

Lines changed: 3 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@
2727
use ApiPlatform\Metadata\UrlGeneratorInterface;
2828
use ApiPlatform\Metadata\Util\IriHelper;
2929
use ApiPlatform\State\Pagination\PaginatorInterface;
30-
use ApiPlatform\State\Pagination\PartialPaginatorInterface;
3130
use ApiPlatform\State\ProcessorInterface;
3231
use ApiPlatform\State\Util\HttpResponseHeadersTrait;
3332
use ApiPlatform\State\Util\HttpResponseStatusTrait;
3433
use Symfony\Component\HttpFoundation\Response;
3534
use Symfony\Component\HttpFoundation\StreamedResponse;
3635
use Symfony\Component\JsonStreamer\StreamWriterInterface;
36+
use ApiPlatform\Hydra\State\Util\PaginationHelperTrait;
3737
use Symfony\Component\TypeInfo\Type;
3838

3939
/**
@@ -43,6 +43,7 @@ final class JsonStreamerProcessor implements ProcessorInterface
4343
{
4444
use HttpResponseHeadersTrait;
4545
use HttpResponseStatusTrait;
46+
use PaginationHelperTrait;
4647

4748
/**
4849
* @param ProcessorInterface<mixed,mixed> $processor
@@ -154,45 +155,6 @@ private function getSearch(Operation $operation, string $requestUri): IriTemplat
154155

155156
private function getView(mixed $object, string $requestUri, Operation $operation): PartialCollectionView
156157
{
157-
$currentPage = $lastPage = $itemsPerPage = $pageTotalItems = null;
158-
if ($paginated = ($object instanceof PartialPaginatorInterface)) {
159-
if ($object instanceof PaginatorInterface) {
160-
$paginated = 1. !== $lastPage = $object->getLastPage();
161-
} else {
162-
$itemsPerPage = $object->getItemsPerPage();
163-
$pageTotalItems = (float) \count($object);
164-
}
165-
166-
$currentPage = $object->getCurrentPage();
167-
}
168-
169-
// TODO: This needs to be changed as well as I wrote in the CollectionFiltersNormalizer
170-
// We should not rely on the request_uri but instead rely on the UriTemplate
171-
// This needs that we implement the RFC and that we do more parsing before calling the serialization (MainController)
172-
$parsed = IriHelper::parseIri($requestUri, $this->pageParameterName);
173-
$appliedFilters = $parsed['parameters'];
174-
unset($appliedFilters[$this->enabledParameterName]);
175-
176-
$urlGenerationStrategy = $operation->getUrlGenerationStrategy() ?? $this->urlGenerationStrategy;
177-
$id = IriHelper::createIri($parsed['parts'], $parsed['parameters'], $this->pageParameterName, $paginated ? $currentPage : null, $urlGenerationStrategy);
178-
if (!$appliedFilters && !$paginated) {
179-
return new PartialCollectionView($id);
180-
}
181-
182-
$first = $last = $previous = $next = null;
183-
if (null !== $lastPage) {
184-
$first = IriHelper::createIri($parsed['parts'], $parsed['parameters'], $this->pageParameterName, 1., $urlGenerationStrategy);
185-
$last = IriHelper::createIri($parsed['parts'], $parsed['parameters'], $this->pageParameterName, $lastPage, $urlGenerationStrategy);
186-
}
187-
188-
if (1. !== $currentPage) {
189-
$previous = IriHelper::createIri($parsed['parts'], $parsed['parameters'], $this->pageParameterName, $currentPage - 1., $urlGenerationStrategy);
190-
}
191-
192-
if ((null !== $lastPage && $currentPage < $lastPage) || (null === $lastPage && $pageTotalItems >= $itemsPerPage)) {
193-
$next = IriHelper::createIri($parsed['parts'], $parsed['parameters'], $this->pageParameterName, $currentPage + 1., $urlGenerationStrategy);
194-
}
195-
196-
return new PartialCollectionView($id, $first, $last, $previous, $next);
158+
return $this->getPartialCollectionView($object, $requestUri, $this->pageParameterName, $this->enabledParameterName, $operation->getUrlGenerationStrategy() ?? $this->urlGenerationStrategy);
197159
}
198160
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Hydra\State\Util;
15+
16+
use ApiPlatform\Hydra\PartialCollectionView;
17+
use ApiPlatform\Metadata\UrlGeneratorInterface;
18+
use ApiPlatform\Metadata\Util\IriHelper;
19+
use ApiPlatform\State\Pagination\PaginatorInterface;
20+
use ApiPlatform\State\Pagination\PartialPaginatorInterface;
21+
22+
trait PaginationHelperTrait
23+
{
24+
private function getPaginationIri(array $parsed, ?float $currentPage, ?float $lastPage, ?float $itemsPerPage, ?float $pageTotalItems, ?int $urlGenerationStrategy, string $pageParameterName): array
25+
{
26+
$first = $last = $previous = $next = null;
27+
28+
if (null !== $lastPage) {
29+
$first = IriHelper::createIri($parsed['parts'], $parsed['parameters'], $pageParameterName, 1., $urlGenerationStrategy);
30+
$last = IriHelper::createIri($parsed['parts'], $parsed['parameters'], $pageParameterName, $lastPage, $urlGenerationStrategy);
31+
}
32+
33+
if (1. !== $currentPage) {
34+
$previous = IriHelper::createIri($parsed['parts'], $parsed['parameters'], $pageParameterName, $currentPage - 1., $urlGenerationStrategy);
35+
}
36+
37+
if ((null !== $lastPage && $currentPage < $lastPage) || (null === $lastPage && $pageTotalItems >= $itemsPerPage)) {
38+
$next = IriHelper::createIri($parsed['parts'], $parsed['parameters'], $pageParameterName, $currentPage + 1., $urlGenerationStrategy);
39+
}
40+
41+
return [
42+
'first' => $first,
43+
'last' => $last,
44+
'previous' => $previous,
45+
'next' => $next,
46+
];
47+
}
48+
49+
private function getPartialCollectionView(mixed $object, string $requestUri, string $pageParameterName, string $enabledParameterName, ?int $urlGenerationStrategy = UrlGeneratorInterface::ABS_PATH): PartialCollectionView
50+
{
51+
$currentPage = $lastPage = $itemsPerPage = $pageTotalItems = null;
52+
$paginated = false;
53+
if ($object instanceof PartialPaginatorInterface) {
54+
$paginated = true;
55+
if ($object instanceof PaginatorInterface) {
56+
$paginated = 1. !== $lastPage = $object->getLastPage();
57+
} else {
58+
$itemsPerPage = $object->getItemsPerPage();
59+
$pageTotalItems = (float) \count($object);
60+
}
61+
$currentPage = $object->getCurrentPage();
62+
}
63+
64+
$parsed = IriHelper::parseIri($requestUri, $pageParameterName);
65+
$appliedFilters = $parsed['parameters'];
66+
unset($appliedFilters[$enabledParameterName]);
67+
68+
$id = IriHelper::createIri($parsed['parts'], $parsed['parameters'], $pageParameterName, $paginated ? $currentPage : null, $urlGenerationStrategy);
69+
70+
if (!$appliedFilters && !$paginated) {
71+
return new PartialCollectionView($id);
72+
}
73+
74+
['first' => $first, 'last' => $last, 'previous' => $previous, 'next' => $next] = $this->getPaginationIri($parsed, $currentPage, $lastPage, $itemsPerPage, $pageTotalItems, $urlGenerationStrategy, $pageParameterName);
75+
76+
return new PartialCollectionView(
77+
$id,
78+
$first,
79+
$last,
80+
$previous,
81+
$next
82+
);
83+
}
84+
}

0 commit comments

Comments
 (0)