From 42892b50eb5128960274af596df3c3278903dc94 Mon Sep 17 00:00:00 2001 From: tischsoic Date: Mon, 12 Feb 2024 08:14:22 +0100 Subject: [PATCH 01/11] IBX-7653: Add FilterParser and IsContainer criterion parser --- src/bundle/Resources/config/input_parsers.yml | 13 +++ .../Input/Parser/Criterion/IsContainer.php | 35 +++++++ src/lib/Server/Input/Parser/FilterParser.php | 98 +++++++++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 src/lib/Server/Input/Parser/Criterion/IsContainer.php create mode 100644 src/lib/Server/Input/Parser/FilterParser.php diff --git a/src/bundle/Resources/config/input_parsers.yml b/src/bundle/Resources/config/input_parsers.yml index 4965346a..80f50e1f 100644 --- a/src/bundle/Resources/config/input_parsers.yml +++ b/src/bundle/Resources/config/input_parsers.yml @@ -285,6 +285,11 @@ services: tags: - { name: ibexa.rest.input.parser, mediaType: application/vnd.ibexa.api.internal.ContentQuery } + Ibexa\Rest\Server\Input\Parser\FilterParser: + parent: Ibexa\Rest\Server\Common\Parser + tags: + - { name: ibexa.rest.input.parser, mediaType: application/vnd.ibexa.api.internal.Filter } + Ibexa\Rest\Server\Input\Parser\LocationQuery: parent: Ibexa\Rest\Server\Common\Parser class: Ibexa\Rest\Server\Input\Parser\LocationQuery @@ -441,6 +446,14 @@ services: tags: - { name: ibexa.rest.input.parser, mediaType: application/vnd.ibexa.api.internal.criterion.UserMetadata } + Ibexa\Rest\Server\Input\Parser\Criterion\IsContainer: + parent: Ibexa\Rest\Server\Common\Parser + class: Ibexa\Rest\Server\Input\Parser\Criterion\IsContainer + arguments: + $parserTools: '@Ibexa\Rest\Input\ParserTools' + tags: + - { name: ibexa.rest.input.parser, mediaType: application/vnd.ibexa.api.internal.criterion.IsContainer } + Ibexa\Rest\Server\Input\Parser\Criterion\IsUserBased: parent: Ibexa\Rest\Server\Common\Parser arguments: diff --git a/src/lib/Server/Input/Parser/Criterion/IsContainer.php b/src/lib/Server/Input/Parser/Criterion/IsContainer.php new file mode 100644 index 00000000..3cea08bd --- /dev/null +++ b/src/lib/Server/Input/Parser/Criterion/IsContainer.php @@ -0,0 +1,35 @@ +parserTools = $parserTools; + } + + public function parse(array $data, ParsingDispatcher $parsingDispatcher): IsContainerCriterion + { + if (!array_key_exists('IsContainer', $data)) { + throw new Exceptions\Parser('Invalid format'); + } + + return new IsContainerCriterion($this->parserTools->parseBooleanValue($data['IsContainer'])); + } +} diff --git a/src/lib/Server/Input/Parser/FilterParser.php b/src/lib/Server/Input/Parser/FilterParser.php new file mode 100644 index 00000000..fe45c849 --- /dev/null +++ b/src/lib/Server/Input/Parser/FilterParser.php @@ -0,0 +1,98 @@ +andWithCriterion($this->processCriteriaArray($data['criteria'], $parsingDispatcher)); + } + + // limit + if (array_key_exists('limit', $data)) { + $filter->withLimit((int)$data['limit']); + } + + // offset + if (array_key_exists('offset', $data)) { + $filter->withOffset((int)$data['offset']); + } + + return $filter; + } + + /** + * @param array $criteriaArray + * @param \Ibexa\Contracts\Rest\Input\ParsingDispatcher $parsingDispatcher + * + * @return \Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion|null A criterion, or a LogicalAnd with a set of Criterion, or null if an empty array was given + */ + private function processCriteriaArray(array $criteriaArray, ParsingDispatcher $parsingDispatcher) + { + if (count($criteriaArray) === 0) { + return null; + } + + $criteria = []; + foreach ($criteriaArray as $criteriaSpec) { + $criterionName = $criteriaSpec['type']; + $criterionData = $criteriaSpec['value']; + + $criteria[] = $this->dispatchCriterion($criterionName, $criterionData, $parsingDispatcher); + } + + return (count($criteria) === 1) ? $criteria[0] : new CriterionValue\LogicalAnd($criteria); + } + + /** + * Dispatches parsing of a criterion name + data to its own parser. + * + * @param string $criterionName + * @param mixed $criterionData + * @param \Ibexa\Contracts\Rest\Input\ParsingDispatcher $parsingDispatcher + * + * @throws \Ibexa\Contracts\Rest\Exceptions\Parser + * + * @return \Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion + */ + public function dispatchCriterion($criterionName, $criterionData, ParsingDispatcher $parsingDispatcher) + { + $mediaType = $this->getCriterionMediaType($criterionName); + try { + return $parsingDispatcher->parse([$criterionName => $criterionData], $mediaType); + } catch (Exceptions\Parser $e) { + throw new Exceptions\Parser("Invalid Criterion id <$criterionName> in ", 0, $e); + } + } + + protected function getCriterionMediaType($criterionName) + { + return 'application/vnd.ibexa.api.internal.criterion.' . $criterionName; + } +} From f5b6572b3107ea3e386e8351b0269bb693d05d77 Mon Sep 17 00:00:00 2001 From: tischsoic Date: Wed, 21 Feb 2024 14:45:50 +0100 Subject: [PATCH 02/11] IsContainerTest --- .../SearchView/Criterion/IsContainerTest.php | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/bundle/Functional/SearchView/Criterion/IsContainerTest.php diff --git a/tests/bundle/Functional/SearchView/Criterion/IsContainerTest.php b/tests/bundle/Functional/SearchView/Criterion/IsContainerTest.php new file mode 100644 index 00000000..e25376e1 --- /dev/null +++ b/tests/bundle/Functional/SearchView/Criterion/IsContainerTest.php @@ -0,0 +1,30 @@ + [ + 'json', + $this->buildJsonCriterionQuery('"IsContainer": true'), + 11, + ], + 'is not container' => [ + 'json', + $this->buildJsonCriterionQuery('"IsContainer": false'), + 2, + ], + ]; + } +} From 74faa301c360671b40403013423290be18cd12a2 Mon Sep 17 00:00:00 2001 From: tischsoic Date: Thu, 22 Feb 2024 10:22:03 +0100 Subject: [PATCH 03/11] phpstan fix --- src/lib/Server/Input/Parser/FilterParser.php | 6 +++--- .../SearchView/Criterion/IsContainerTest.php | 10 ++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/lib/Server/Input/Parser/FilterParser.php b/src/lib/Server/Input/Parser/FilterParser.php index fe45c849..663dbff9 100644 --- a/src/lib/Server/Input/Parser/FilterParser.php +++ b/src/lib/Server/Input/Parser/FilterParser.php @@ -20,7 +20,7 @@ final class FilterParser extends BaseParser /** * Parses input structure to a Query. * - * @param array $data + * @param array $data * @param \Ibexa\Contracts\Rest\Input\ParsingDispatcher $parsingDispatcher * * @throws \Ibexa\Contracts\Rest\Exceptions\Parser @@ -48,7 +48,7 @@ public function parse(array $data, ParsingDispatcher $parsingDispatcher): Filter } /** - * @param array $criteriaArray + * @param array> $criteriaArray * @param \Ibexa\Contracts\Rest\Input\ParsingDispatcher $parsingDispatcher * * @return \Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion|null A criterion, or a LogicalAnd with a set of Criterion, or null if an empty array was given @@ -91,7 +91,7 @@ public function dispatchCriterion($criterionName, $criterionData, ParsingDispatc } } - protected function getCriterionMediaType($criterionName) + protected function getCriterionMediaType(string $criterionName): string { return 'application/vnd.ibexa.api.internal.criterion.' . $criterionName; } diff --git a/tests/bundle/Functional/SearchView/Criterion/IsContainerTest.php b/tests/bundle/Functional/SearchView/Criterion/IsContainerTest.php index e25376e1..cba529dd 100644 --- a/tests/bundle/Functional/SearchView/Criterion/IsContainerTest.php +++ b/tests/bundle/Functional/SearchView/Criterion/IsContainerTest.php @@ -12,6 +12,16 @@ final class IsContainerTest extends SearchCriterionTestCase { + /** + * @phpstan-return iterable< + * string, + * array{ + * string, + * string, + * int, + * }, + * > + */ public function getCriteriaPayloads(): iterable { return [ From a0e1a407993ce168b833ea9bdf283c6e4861aa44 Mon Sep 17 00:00:00 2001 From: tischsoic Date: Thu, 22 Feb 2024 11:38:12 +0100 Subject: [PATCH 04/11] FilteringCriterion check --- src/lib/Server/Input/Parser/FilterParser.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/lib/Server/Input/Parser/FilterParser.php b/src/lib/Server/Input/Parser/FilterParser.php index 663dbff9..650fb33b 100644 --- a/src/lib/Server/Input/Parser/FilterParser.php +++ b/src/lib/Server/Input/Parser/FilterParser.php @@ -8,6 +8,7 @@ use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion as CriterionValue; use Ibexa\Contracts\Core\Repository\Values\Filter\Filter; +use Ibexa\Contracts\Core\Repository\Values\Filter\FilteringCriterion; use Ibexa\Contracts\Rest\Exceptions; use Ibexa\Contracts\Rest\Input\ParsingDispatcher; use Ibexa\Rest\Input\BaseParser; @@ -31,7 +32,11 @@ public function parse(array $data, ParsingDispatcher $parsingDispatcher): Filter { $filter = new Filter(); if (array_key_exists('criteria', $data) && is_array($data['criteria'])) { - $filter->andWithCriterion($this->processCriteriaArray($data['criteria'], $parsingDispatcher)); + $criteria = $this->processCriteriaArray($data['criteria'], $parsingDispatcher); + + if ($criteria instanceof FilteringCriterion) { + $filter->andWithCriterion($criteria); + } } // limit From 2e7d38690e2510f573d2b104905d5097a344c949 Mon Sep 17 00:00:00 2001 From: tischsoic Date: Mon, 25 Mar 2024 09:05:08 +0100 Subject: [PATCH 05/11] IsContainer -> IsContainerCriterion --- src/lib/Server/Input/Parser/Criterion/IsContainer.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/Server/Input/Parser/Criterion/IsContainer.php b/src/lib/Server/Input/Parser/Criterion/IsContainer.php index 3cea08bd..6593d2ad 100644 --- a/src/lib/Server/Input/Parser/Criterion/IsContainer.php +++ b/src/lib/Server/Input/Parser/Criterion/IsContainer.php @@ -26,10 +26,10 @@ public function __construct(ParserTools $parserTools) public function parse(array $data, ParsingDispatcher $parsingDispatcher): IsContainerCriterion { - if (!array_key_exists('IsContainer', $data)) { + if (!array_key_exists('IsContainerCriterion', $data)) { throw new Exceptions\Parser('Invalid format'); } - return new IsContainerCriterion($this->parserTools->parseBooleanValue($data['IsContainer'])); + return new IsContainerCriterion($this->parserTools->parseBooleanValue($data['IsContainerCriterion'])); } } From db78a13dd9b4188e31bcaf3f992b198617f7a30b Mon Sep 17 00:00:00 2001 From: tischsoic Date: Mon, 25 Mar 2024 09:06:45 +0100 Subject: [PATCH 06/11] delete FilterParser --- src/bundle/Resources/config/input_parsers.yml | 5 - src/lib/Server/Input/Parser/FilterParser.php | 103 ------------------ 2 files changed, 108 deletions(-) delete mode 100644 src/lib/Server/Input/Parser/FilterParser.php diff --git a/src/bundle/Resources/config/input_parsers.yml b/src/bundle/Resources/config/input_parsers.yml index 80f50e1f..82e63dcb 100644 --- a/src/bundle/Resources/config/input_parsers.yml +++ b/src/bundle/Resources/config/input_parsers.yml @@ -285,11 +285,6 @@ services: tags: - { name: ibexa.rest.input.parser, mediaType: application/vnd.ibexa.api.internal.ContentQuery } - Ibexa\Rest\Server\Input\Parser\FilterParser: - parent: Ibexa\Rest\Server\Common\Parser - tags: - - { name: ibexa.rest.input.parser, mediaType: application/vnd.ibexa.api.internal.Filter } - Ibexa\Rest\Server\Input\Parser\LocationQuery: parent: Ibexa\Rest\Server\Common\Parser class: Ibexa\Rest\Server\Input\Parser\LocationQuery diff --git a/src/lib/Server/Input/Parser/FilterParser.php b/src/lib/Server/Input/Parser/FilterParser.php deleted file mode 100644 index 650fb33b..00000000 --- a/src/lib/Server/Input/Parser/FilterParser.php +++ /dev/null @@ -1,103 +0,0 @@ - $data - * @param \Ibexa\Contracts\Rest\Input\ParsingDispatcher $parsingDispatcher - * - * @throws \Ibexa\Contracts\Rest\Exceptions\Parser - * - * @return \Ibexa\Contracts\Core\Repository\Values\Filter\Filter - */ - public function parse(array $data, ParsingDispatcher $parsingDispatcher): Filter - { - $filter = new Filter(); - if (array_key_exists('criteria', $data) && is_array($data['criteria'])) { - $criteria = $this->processCriteriaArray($data['criteria'], $parsingDispatcher); - - if ($criteria instanceof FilteringCriterion) { - $filter->andWithCriterion($criteria); - } - } - - // limit - if (array_key_exists('limit', $data)) { - $filter->withLimit((int)$data['limit']); - } - - // offset - if (array_key_exists('offset', $data)) { - $filter->withOffset((int)$data['offset']); - } - - return $filter; - } - - /** - * @param array> $criteriaArray - * @param \Ibexa\Contracts\Rest\Input\ParsingDispatcher $parsingDispatcher - * - * @return \Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion|null A criterion, or a LogicalAnd with a set of Criterion, or null if an empty array was given - */ - private function processCriteriaArray(array $criteriaArray, ParsingDispatcher $parsingDispatcher) - { - if (count($criteriaArray) === 0) { - return null; - } - - $criteria = []; - foreach ($criteriaArray as $criteriaSpec) { - $criterionName = $criteriaSpec['type']; - $criterionData = $criteriaSpec['value']; - - $criteria[] = $this->dispatchCriterion($criterionName, $criterionData, $parsingDispatcher); - } - - return (count($criteria) === 1) ? $criteria[0] : new CriterionValue\LogicalAnd($criteria); - } - - /** - * Dispatches parsing of a criterion name + data to its own parser. - * - * @param string $criterionName - * @param mixed $criterionData - * @param \Ibexa\Contracts\Rest\Input\ParsingDispatcher $parsingDispatcher - * - * @throws \Ibexa\Contracts\Rest\Exceptions\Parser - * - * @return \Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion - */ - public function dispatchCriterion($criterionName, $criterionData, ParsingDispatcher $parsingDispatcher) - { - $mediaType = $this->getCriterionMediaType($criterionName); - try { - return $parsingDispatcher->parse([$criterionName => $criterionData], $mediaType); - } catch (Exceptions\Parser $e) { - throw new Exceptions\Parser("Invalid Criterion id <$criterionName> in ", 0, $e); - } - } - - protected function getCriterionMediaType(string $criterionName): string - { - return 'application/vnd.ibexa.api.internal.criterion.' . $criterionName; - } -} From ead4a441c3e14b343571b7d3d4d66f8dff7556ca Mon Sep 17 00:00:00 2001 From: tischsoic Date: Tue, 26 Mar 2024 12:37:42 +0100 Subject: [PATCH 07/11] phpstan parse --- src/lib/Server/Input/Parser/Criterion/IsContainer.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/Server/Input/Parser/Criterion/IsContainer.php b/src/lib/Server/Input/Parser/Criterion/IsContainer.php index 6593d2ad..aac88a34 100644 --- a/src/lib/Server/Input/Parser/Criterion/IsContainer.php +++ b/src/lib/Server/Input/Parser/Criterion/IsContainer.php @@ -24,6 +24,9 @@ public function __construct(ParserTools $parserTools) $this->parserTools = $parserTools; } + /** + * @param array $data + */ public function parse(array $data, ParsingDispatcher $parsingDispatcher): IsContainerCriterion { if (!array_key_exists('IsContainerCriterion', $data)) { From 6522160352292b2eecb890065e73a2ecd6f0a8ec Mon Sep 17 00:00:00 2001 From: tischsoic Date: Fri, 5 Apr 2024 09:49:43 +0200 Subject: [PATCH 08/11] after CR --- src/lib/Server/Input/Parser/Criterion/IsContainer.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lib/Server/Input/Parser/Criterion/IsContainer.php b/src/lib/Server/Input/Parser/Criterion/IsContainer.php index aac88a34..fec6db62 100644 --- a/src/lib/Server/Input/Parser/Criterion/IsContainer.php +++ b/src/lib/Server/Input/Parser/Criterion/IsContainer.php @@ -14,10 +14,9 @@ use Ibexa\Rest\Input\BaseParser; use Ibexa\Rest\Input\ParserTools; -class IsContainer extends BaseParser +final class IsContainer extends BaseParser { - /** @var \Ibexa\Rest\Input\ParserTools */ - protected $parserTools; + protected ParserTools $parserTools; public function __construct(ParserTools $parserTools) { From fa1ad7de6f6bb793a938e965d9c3e5295c7fad2f Mon Sep 17 00:00:00 2001 From: tischsoic Date: Wed, 17 Apr 2024 11:12:05 +0200 Subject: [PATCH 09/11] after CR --- src/bundle/Resources/config/input_parsers.yml | 1 - src/lib/Server/Input/Parser/Criterion/IsContainer.php | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bundle/Resources/config/input_parsers.yml b/src/bundle/Resources/config/input_parsers.yml index 82e63dcb..225153fd 100644 --- a/src/bundle/Resources/config/input_parsers.yml +++ b/src/bundle/Resources/config/input_parsers.yml @@ -443,7 +443,6 @@ services: Ibexa\Rest\Server\Input\Parser\Criterion\IsContainer: parent: Ibexa\Rest\Server\Common\Parser - class: Ibexa\Rest\Server\Input\Parser\Criterion\IsContainer arguments: $parserTools: '@Ibexa\Rest\Input\ParserTools' tags: diff --git a/src/lib/Server/Input/Parser/Criterion/IsContainer.php b/src/lib/Server/Input/Parser/Criterion/IsContainer.php index fec6db62..6b1b5ae1 100644 --- a/src/lib/Server/Input/Parser/Criterion/IsContainer.php +++ b/src/lib/Server/Input/Parser/Criterion/IsContainer.php @@ -16,7 +16,7 @@ final class IsContainer extends BaseParser { - protected ParserTools $parserTools; + private ParserTools $parserTools; public function __construct(ParserTools $parserTools) { From 35910f3f380cfbaacc63662be685919cf7d083fb Mon Sep 17 00:00:00 2001 From: tischsoic Date: Tue, 23 Apr 2024 09:34:06 +0200 Subject: [PATCH 10/11] Adjust test --- .../Functional/SearchView/Criterion/IsContainerTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/bundle/Functional/SearchView/Criterion/IsContainerTest.php b/tests/bundle/Functional/SearchView/Criterion/IsContainerTest.php index cba529dd..9852de65 100644 --- a/tests/bundle/Functional/SearchView/Criterion/IsContainerTest.php +++ b/tests/bundle/Functional/SearchView/Criterion/IsContainerTest.php @@ -27,12 +27,12 @@ public function getCriteriaPayloads(): iterable return [ 'is container' => [ 'json', - $this->buildJsonCriterionQuery('"IsContainer": true'), + $this->buildJsonCriterionQuery('"IsContainerCriterion": true'), 11, ], 'is not container' => [ 'json', - $this->buildJsonCriterionQuery('"IsContainer": false'), + $this->buildJsonCriterionQuery('"IsContainerCriterion": false'), 2, ], ]; From a3d5a27ae94743ed5fb71b50998067ef0f3e6b40 Mon Sep 17 00:00:00 2001 From: tischsoic Date: Tue, 23 Apr 2024 09:48:15 +0200 Subject: [PATCH 11/11] Adjust tests because limit in the request is set to 10 --- .../bundle/Functional/SearchView/Criterion/IsContainerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bundle/Functional/SearchView/Criterion/IsContainerTest.php b/tests/bundle/Functional/SearchView/Criterion/IsContainerTest.php index 9852de65..c19b966e 100644 --- a/tests/bundle/Functional/SearchView/Criterion/IsContainerTest.php +++ b/tests/bundle/Functional/SearchView/Criterion/IsContainerTest.php @@ -28,7 +28,7 @@ public function getCriteriaPayloads(): iterable 'is container' => [ 'json', $this->buildJsonCriterionQuery('"IsContainerCriterion": true'), - 11, + 10, ], 'is not container' => [ 'json',