From c2ddc806c3425f89f4b3d62e36a335d7eb1587b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20COURJEAN?= Date: Tue, 16 Apr 2024 11:15:24 +0200 Subject: [PATCH 1/7] fix(jsonapi): add support for pagination array parameter name --- src/JsonApi/State/JsonApiProvider.php | 2 +- src/State/Pagination/Pagination.php | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/JsonApi/State/JsonApiProvider.php b/src/JsonApi/State/JsonApiProvider.php index bf86cb406de..92936e0717c 100644 --- a/src/JsonApi/State/JsonApiProvider.php +++ b/src/JsonApi/State/JsonApiProvider.php @@ -60,7 +60,7 @@ public function provide(Operation $operation, array $uriVariables = [], array $c $filterParameter && \is_array($filterParameter) ) { - $filters = array_merge($filterParameter, $filters); + $filters = array_merge(['page' => $filterParameter], $filterParameter, $filters); } $pageParameter = $queryParameters['page'] ?? null; diff --git a/src/State/Pagination/Pagination.php b/src/State/Pagination/Pagination.php index 9d070631122..45ba61000a9 100644 --- a/src/State/Pagination/Pagination.php +++ b/src/State/Pagination/Pagination.php @@ -219,13 +219,28 @@ private function getGraphQlEnabled(?Operation $operation): bool return $operation?->getPaginationEnabled() ?? $enabled; } + private function extractParameter(array $contextFilters, string $parameterName) + { + \preg_match_all("/[\w-]+/", $parameterName, $matches); + + foreach($matches[0] as $key){ + if (!\array_key_exists($key, $contextFilters)) { + return null; + } + $contextFilters = $contextFilters[$key]; + } + + return $contextFilters; + } + /** * Gets the given pagination parameter name from the given context. */ private function getParameterFromContext(array $context, string $parameterName, mixed $default = null) { $filters = $context['filters'] ?? []; + $filterValue = $this->extractParameter($filters, $parameterName); - return \array_key_exists($parameterName, $filters) ? $filters[$parameterName] : $default; + return $filterValue ?? $default; } } From 69739f0cd15b0c80b721860910ea11295e55874f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20COURJEAN?= Date: Tue, 16 Apr 2024 15:12:46 +0200 Subject: [PATCH 2/7] fix(jsonapi): support both page & page[number] --- src/JsonApi/State/JsonApiProvider.php | 5 +++-- src/State/Pagination/Pagination.php | 16 +++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/JsonApi/State/JsonApiProvider.php b/src/JsonApi/State/JsonApiProvider.php index 92936e0717c..6e96c7ad0ce 100644 --- a/src/JsonApi/State/JsonApiProvider.php +++ b/src/JsonApi/State/JsonApiProvider.php @@ -60,14 +60,15 @@ public function provide(Operation $operation, array $uriVariables = [], array $c $filterParameter && \is_array($filterParameter) ) { - $filters = array_merge(['page' => $filterParameter], $filterParameter, $filters); + $filters = array_merge($filterParameter, $filters); } $pageParameter = $queryParameters['page'] ?? null; if ( \is_array($pageParameter) ) { - $filters = array_merge($pageParameter, $filters); + // To not break existing integration, put page array in _page + $filters = array_merge(['_page' => $pageParameter], $pageParameter, $filters); } [$included, $properties] = $this->transformFieldsetsParameters($queryParameters, $operation->getShortName() ?? ''); diff --git a/src/State/Pagination/Pagination.php b/src/State/Pagination/Pagination.php index 45ba61000a9..65029aa38a3 100644 --- a/src/State/Pagination/Pagination.php +++ b/src/State/Pagination/Pagination.php @@ -219,11 +219,21 @@ private function getGraphQlEnabled(?Operation $operation): bool return $operation?->getPaginationEnabled() ?? $enabled; } + /** + * Extract pagination parameter + * page[page] => $contextFilters['page'] with default configuration page_parameter_name: page + * page[number] => $contextFilters['_page'][number] with configuration page_parameter_name: page[number] + */ private function extractParameter(array $contextFilters, string $parameterName) { - \preg_match_all("/[\w-]+/", $parameterName, $matches); - - foreach($matches[0] as $key){ + preg_match_all("/[\w-]+/", $parameterName, $matches); + foreach ($matches[0] as $i => $key) { + if ($i === 0 && $key === 'page' && count($matches[0]) > 1) { + $key = '_page'; + } + if (\is_array($contextFilters) === false) { + return $contextFilters; + } if (!\array_key_exists($key, $contextFilters)) { return null; } From bd0d6a4bddcab1b1f301afc8d523c9792cb11d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20COURJEAN?= Date: Tue, 16 Apr 2024 15:23:31 +0200 Subject: [PATCH 3/7] fix(jsonapi): fix cs --- src/State/Pagination/Pagination.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/State/Pagination/Pagination.php b/src/State/Pagination/Pagination.php index 65029aa38a3..6e60f13af94 100644 --- a/src/State/Pagination/Pagination.php +++ b/src/State/Pagination/Pagination.php @@ -222,16 +222,16 @@ private function getGraphQlEnabled(?Operation $operation): bool /** * Extract pagination parameter * page[page] => $contextFilters['page'] with default configuration page_parameter_name: page - * page[number] => $contextFilters['_page'][number] with configuration page_parameter_name: page[number] + * page[number] => $contextFilters['_page'][number] with configuration page_parameter_name: page[number]. */ private function extractParameter(array $contextFilters, string $parameterName) { preg_match_all("/[\w-]+/", $parameterName, $matches); foreach ($matches[0] as $i => $key) { - if ($i === 0 && $key === 'page' && count($matches[0]) > 1) { + if (0 === $i && 'page' === $key && \count($matches[0]) > 1) { $key = '_page'; } - if (\is_array($contextFilters) === false) { + if (false === \is_array($contextFilters)) { return $contextFilters; } if (!\array_key_exists($key, $contextFilters)) { From f27049945463e9f7016c373e6f7f104a24763399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20COURJEAN?= Date: Thu, 18 Apr 2024 08:59:43 +0200 Subject: [PATCH 4/7] fix(jsonapi): fix typehint --- src/State/Pagination/Pagination.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/State/Pagination/Pagination.php b/src/State/Pagination/Pagination.php index 6e60f13af94..7652d3f2cb8 100644 --- a/src/State/Pagination/Pagination.php +++ b/src/State/Pagination/Pagination.php @@ -224,7 +224,7 @@ private function getGraphQlEnabled(?Operation $operation): bool * page[page] => $contextFilters['page'] with default configuration page_parameter_name: page * page[number] => $contextFilters['_page'][number] with configuration page_parameter_name: page[number]. */ - private function extractParameter(array $contextFilters, string $parameterName) + private function extractParameter(array $contextFilters, string $parameterName): mixed { preg_match_all("/[\w-]+/", $parameterName, $matches); foreach ($matches[0] as $i => $key) { @@ -246,7 +246,7 @@ private function extractParameter(array $contextFilters, string $parameterName) /** * Gets the given pagination parameter name from the given context. */ - private function getParameterFromContext(array $context, string $parameterName, mixed $default = null) + private function getParameterFromContext(array $context, string $parameterName, mixed $default = null): mixed { $filters = $context['filters'] ?? []; $filterValue = $this->extractParameter($filters, $parameterName); From 8b5d9e142031d13bc1c15990c57b91a90335d5d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20COURJEAN?= Date: Mon, 13 May 2024 14:38:48 +0200 Subject: [PATCH 5/7] fix(jsonapi): add unit tests on State/Pagination --- src/State/Tests/PaginationTest.php | 55 ++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/State/Tests/PaginationTest.php diff --git a/src/State/Tests/PaginationTest.php b/src/State/Tests/PaginationTest.php new file mode 100644 index 00000000000..ecc19acf87f --- /dev/null +++ b/src/State/Tests/PaginationTest.php @@ -0,0 +1,55 @@ +getPagination($operation); + $this->assertSame(1, $paginationInfo[0]); + $this->assertSame(0, $paginationInfo[1]); + $this->assertSame(30, $paginationInfo[2]); + } + public function testPaginationGetPaginationWithPageParameterNameAsArrayAndDefaultContext(): void + { + $operation = new GetCollection(name: 'hello', provider: 'provider'); + $pagination = new Pagination(['page_parameter_name' => 'page[number]']); + $paginationInfo = $pagination->getPagination($operation); + $this->assertSame(1, $paginationInfo[0]); + $this->assertSame(0, $paginationInfo[1]); + $this->assertSame(30, $paginationInfo[2]); + } + public function testPaginationGetPaginationWithPageParametersAsArrayAndCustomContext(): void + { + $operation = new GetCollection(paginationClientItemsPerPage: true, name: 'hello', provider: 'provider'); + $pagination = new Pagination([ + 'page_parameter_name' => 'page[number]', + 'items_per_page_parameter_name' => 'page[size]', + ]); + $paginationInfo = $pagination->getPagination( + $operation, + [ + 'filters' => [ + 'number' => 2, + 'size' => 10, + '_page' => [ + 'number' => 2, + 'size' => 10, + ], + ], + ], + ); + $this->assertSame(2, $paginationInfo[0]); + $this->assertSame(10, $paginationInfo[1]); + $this->assertSame(10, $paginationInfo[2]); + } +} From 47e1c4b542dc3cee0453da52a8d3e59b47844295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20COURJEAN?= Date: Mon, 13 May 2024 14:42:50 +0200 Subject: [PATCH 6/7] fix(jsonapi): fix cs --- src/State/Tests/PaginationTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/State/Tests/PaginationTest.php b/src/State/Tests/PaginationTest.php index ecc19acf87f..bacd80860c0 100644 --- a/src/State/Tests/PaginationTest.php +++ b/src/State/Tests/PaginationTest.php @@ -19,6 +19,7 @@ public function testPaginationGetPaginationWithDefaultOptionsAndDefaultContext() $this->assertSame(0, $paginationInfo[1]); $this->assertSame(30, $paginationInfo[2]); } + public function testPaginationGetPaginationWithPageParameterNameAsArrayAndDefaultContext(): void { $operation = new GetCollection(name: 'hello', provider: 'provider'); @@ -28,6 +29,7 @@ public function testPaginationGetPaginationWithPageParameterNameAsArrayAndDefaul $this->assertSame(0, $paginationInfo[1]); $this->assertSame(30, $paginationInfo[2]); } + public function testPaginationGetPaginationWithPageParametersAsArrayAndCustomContext(): void { $operation = new GetCollection(paginationClientItemsPerPage: true, name: 'hello', provider: 'provider'); From 8c88d0d6059c34ddf87ca4a78158174a8e83503d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20COURJEAN?= Date: Mon, 13 May 2024 14:51:30 +0200 Subject: [PATCH 7/7] fix(jsonapi): fix cs comment --- src/State/Tests/PaginationTest.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/State/Tests/PaginationTest.php b/src/State/Tests/PaginationTest.php index bacd80860c0..3c399410294 100644 --- a/src/State/Tests/PaginationTest.php +++ b/src/State/Tests/PaginationTest.php @@ -1,5 +1,14 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + declare(strict_types=1); namespace ApiPlatform\State\Tests;