diff --git a/composer.json b/composer.json index dcd893df01..607109142f 100644 --- a/composer.json +++ b/composer.json @@ -53,6 +53,7 @@ "ibexa/user": "~4.6.0@dev", "ibexa/fieldtype-richtext": "~4.6.0@dev", "ibexa/rest": "~4.6.0@dev", + "ibexa/polyfill-php82": "^1.0", "ibexa/search": "~4.6.x-dev", "babdev/pagerfanta-bundle": "^2.1", "knplabs/knp-menu-bundle": "^3.0", diff --git a/src/bundle/Controller/Content/ContentTreeController.php b/src/bundle/Controller/Content/ContentTreeController.php index 4998774152..29a10e06e6 100644 --- a/src/bundle/Controller/Content/ContentTreeController.php +++ b/src/bundle/Controller/Content/ContentTreeController.php @@ -77,7 +77,8 @@ public function loadChildrenAction( Request $request, int $parentLocationId, int $limit, - int $offset + int $offset, + Query\Criterion $filter ): Node { $location = $this->locationService->loadLocation($parentLocationId); $loadSubtreeRequestNode = new LoadSubtreeRequestNode($parentLocationId, $limit, $offset); @@ -91,7 +92,8 @@ public function loadChildrenAction( true, 0, $sortClause, - $sortOrder + $sortOrder, + $filter ); } diff --git a/src/bundle/ControllerArgumentResolver/ContentTreeChildrenQueryArgumentResolver.php b/src/bundle/ControllerArgumentResolver/ContentTreeChildrenQueryArgumentResolver.php new file mode 100644 index 0000000000..2f42f3e7d9 --- /dev/null +++ b/src/bundle/ControllerArgumentResolver/ContentTreeChildrenQueryArgumentResolver.php @@ -0,0 +1,71 @@ +criterionProcessor = $criterionProcessor; + } + + public function supports(Request $request, ArgumentMetadata $argument): bool + { + return Criterion::class === $argument->getType() + && 'filter' === $argument->getName(); + } + + /** + * @return iterable<\Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion> + * + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException + */ + public function resolve(Request $request, ArgumentMetadata $argument): iterable + { + yield new LogicalAnd($this->processFilterQueryCriteria($request)); + } + + /** + * @return array<\Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion> + */ + private function processFilterQueryCriteria(Request $request): array + { + if (!$request->query->has('filter')) { + return []; + } + + /** @var array> $criteriaData */ + $criteriaData = $request->query->all('filter'); + if (empty($criteriaData)) { + return []; + } + + $criteria = $this->criterionProcessor->processCriteria($criteriaData); + + return iterator_to_array($criteria); + } +} diff --git a/src/bundle/Resources/config/services/controller_argument_resolvers.yaml b/src/bundle/Resources/config/services/controller_argument_resolvers.yaml index c7f362e61d..a78ab2f092 100644 --- a/src/bundle/Resources/config/services/controller_argument_resolvers.yaml +++ b/src/bundle/Resources/config/services/controller_argument_resolvers.yaml @@ -7,3 +7,9 @@ services: Ibexa\Bundle\AdminUi\ControllerArgumentResolver\UniversalDiscoveryRequestQueryArgumentResolver: tags: - { name: controller.argument_value_resolver, priority: 50 } + + Ibexa\Bundle\AdminUi\ControllerArgumentResolver\ContentTreeChildrenQueryArgumentResolver: + arguments: + $criterionProcessor: '@Ibexa\AdminUi\REST\Input\Parser\CriterionProcessor' + tags: + - { name: controller.argument_value_resolver, priority: 50 } diff --git a/src/bundle/Resources/config/services/rest.yaml b/src/bundle/Resources/config/services/rest.yaml index 334b6831de..3bfbca3019 100644 --- a/src/bundle/Resources/config/services/rest.yaml +++ b/src/bundle/Resources/config/services/rest.yaml @@ -92,3 +92,7 @@ services: $applicationConfigRestGeneratorRegistry: '@Ibexa\Contracts\AdminUi\REST\ApplicationConfigRestGeneratorRegistryInterface' tags: - { name: ibexa.rest.output.value_object.visitor, type: Ibexa\AdminUi\REST\Value\ApplicationConfig } + + Ibexa\AdminUi\REST\Input\Parser\CriterionProcessor: + parent: Ibexa\Contracts\Rest\Input\Parser\Query\Criterion\BaseCriterionProcessor + diff --git a/src/lib/REST/Input/Parser/CriterionProcessor.php b/src/lib/REST/Input/Parser/CriterionProcessor.php new file mode 100644 index 0000000000..0505c6c1b9 --- /dev/null +++ b/src/lib/REST/Input/Parser/CriterionProcessor.php @@ -0,0 +1,35 @@ + + * + * @extends \Ibexa\Contracts\Rest\Input\Parser\Query\Criterion\BaseCriterionProcessor< + * \Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion + * > + * + * @internal + */ +final class CriterionProcessor extends BaseCriterionProcessor +{ + protected function getMediaTypePrefix(): string + { + return 'application/vnd.ibexa.api.internal.criterion'; + } + + protected function getParserInvalidCriterionMessage(string $criterionName): string + { + return "Invalid Criterion <$criterionName>"; + } +} diff --git a/src/lib/REST/Output/ValueObjectVisitor/ContentTree/Node.php b/src/lib/REST/Output/ValueObjectVisitor/ContentTree/Node.php index 41e666161f..f8d18f0bbb 100644 --- a/src/lib/REST/Output/ValueObjectVisitor/ContentTree/Node.php +++ b/src/lib/REST/Output/ValueObjectVisitor/ContentTree/Node.php @@ -49,10 +49,10 @@ public function visit(Visitor $visitor, Generator $generator, $data) $generator->startValueElement('contentTypeIdentifier', $data->contentTypeIdentifier); $generator->endValueElement('contentTypeIdentifier'); - $generator->startValueElement('isContainer', $data->isContainer); + $generator->startValueElement('isContainer', $generator->serializeBool($data->isContainer)); $generator->endValueElement('isContainer'); - $generator->startValueElement('isInvisible', $data->isInvisible); + $generator->startValueElement('isInvisible', $generator->serializeBool($data->isInvisible)); $generator->endValueElement('isInvisible'); $generator->startValueElement('displayLimit', $data->displayLimit); @@ -63,7 +63,7 @@ public function visit(Visitor $visitor, Generator $generator, $data) $generator->valueElement('reverseRelationsCount', $data->reverseRelationsCount); - $generator->valueElement('isBookmarked', $data->isBookmarked); + $generator->valueElement('isBookmarked', $generator->serializeBool($data->isBookmarked)); $generator->startList('children'); diff --git a/tests/bundle/ControllerArgumentResolver/ContentTreeChildrenQueryArgumentResolverTest.php b/tests/bundle/ControllerArgumentResolver/ContentTreeChildrenQueryArgumentResolverTest.php new file mode 100644 index 0000000000..0a65bdbfb8 --- /dev/null +++ b/tests/bundle/ControllerArgumentResolver/ContentTreeChildrenQueryArgumentResolverTest.php @@ -0,0 +1,213 @@ + + * + * @covers \Ibexa\Bundle\AdminUi\ControllerArgumentResolver\ContentTreeChildrenQueryArgumentResolver + */ +final class ContentTreeChildrenQueryArgumentResolverTest extends TestCase +{ + private ArgumentValueResolverInterface $resolver; + + /** @phpstan-var TCriterionProcessor&\PHPUnit\Framework\MockObject\MockObject */ + private CriterionProcessorInterface $criterionProcessor; + + protected function setUp(): void + { + $this->criterionProcessor = $this->createMock(CriterionProcessorInterface::class); + $this->resolver = new ContentTreeChildrenQueryArgumentResolver( + $this->criterionProcessor + ); + } + + /** + * @dataProvider provideDataForTestSupports + */ + public function testSupports( + bool $expected, + ArgumentMetadata $argumentMetadata + ): void { + self::assertSame( + $expected, + $this->resolver->supports( + new Request(), + $argumentMetadata + ) + ); + } + + /** + * @return iterable + */ + public function provideDataForTestSupports(): iterable + { + yield 'Not supported' => [ + false, + $this->createMock(ArgumentMetadata::class), + ]; + + yield 'Not supported - invalid argument type' => [ + false, + $this->createArgumentMetadata( + 'filter', + 'foo', + ), + ]; + + yield 'Not supported - invalid argument name' => [ + false, + $this->createArgumentMetadata( + 'foo', + Criterion::class, + ), + ]; + + yield 'Supported' => [ + true, + $this->createArgumentMetadata( + 'filter', + Criterion::class, + ), + ]; + } + + /** + * @dataProvider provideDataForTestResolve + * + * @param array> $criteriaToProcess + * @param Traversable<\Ibexa\Contracts\Core\Repository\Values\Content\Query\CriterionInterface> $expectedCriteria + * + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException + */ + public function testResolve( + Criterion $expected, + Request $request, + Traversable $expectedCriteria, + array $criteriaToProcess = [] + ): void { + if (!empty($criteriaToProcess)) { + $this->mockCriterionProcessorProcessCriteria($criteriaToProcess, $expectedCriteria); + } + + $generator = $this->resolver->resolve( + $request, + $this->createMock(ArgumentMetadata::class) + ); + + self::assertInstanceOf(Generator::class, $generator); + $resolvedArguments = iterator_to_array($generator); + + self::assertCount(1, $resolvedArguments); + + self::assertEquals( + $expected, + $resolvedArguments[0] + ); + } + + /** + * @return iterable, + * 3?: array, + * }> + * + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidCriterionArgumentException + */ + public function provideDataForTestResolve(): iterable + { + yield 'Return null - missing filter query param' => [ + new LogicalAnd([]), + $this->createRequest(null), + new ArrayIterator(), + ]; + + yield 'Return null - empty value for filter query param' => [ + new LogicalAnd([]), + $this->createRequest([]), + new ArrayIterator(), + ]; + + $criteriaToProcess = [ + 'ContentTypeIdentifierCriterion' => 'folder', + ]; + $expectedCriteria = [ + new ContentTypeIdentifier('folder'), + ]; + + yield 'Return filter with ContentTypeIdentifier criterion' => [ + new LogicalAnd($expectedCriteria), + $this->createRequest($criteriaToProcess), + new ArrayIterator($expectedCriteria), + $criteriaToProcess, + ]; + } + + /** + * @param array> $criteriaToProcess + * @param Traversable<\Ibexa\Contracts\Core\Repository\Values\Content\Query\CriterionInterface> $expectedCriteria + */ + private function mockCriterionProcessorProcessCriteria( + ?array $criteriaToProcess, + Traversable $expectedCriteria + ): void { + $this->criterionProcessor + ->method('processCriteria') + ->with($criteriaToProcess) + ->willReturn($expectedCriteria); + } + + /** + * @param array|null $filter + */ + private function createRequest(?array $filter): Request + { + $request = Request::create('/'); + + if (null !== $filter) { + $request->query->set('filter', $filter); + } + + return $request; + } + + private function createArgumentMetadata( + string $name, + string $type + ): ArgumentMetadata { + return new ArgumentMetadata( + $name, + $type, + true, + false, + '' + ); + } +} diff --git a/tests/integration/REST/GetContentTreeChildrenTest.php b/tests/integration/REST/GetContentTreeChildrenTest.php new file mode 100644 index 0000000000..b43282a9bf --- /dev/null +++ b/tests/integration/REST/GetContentTreeChildrenTest.php @@ -0,0 +1,126 @@ +withSnapshotName(self::SNAPSHOT_FILTER_PATH), + self::SNAPSHOT_NO_FILTER + ); + + foreach (self::getFilterQuery() as $snapshotName => $filterQuery) { + yield ( + new EndpointRequestDefinition( + 'GET', + self::ENDPOINT_CONTENT_TREE_CHILDREN_URL . '?' . $filterQuery, + self::RESOURCE_TYPE, + self::generateMediaTypeString(self::RESOURCE_TYPE, 'json') + ) + )->withSnapshotName( + sprintf( + self::SNAPSHOT_FILTER_PATH, + '/json/', + $snapshotName + ) + ); + } + } + + /** + * @return iterable<\Ibexa\Contracts\Test\Rest\Request\Value\EndpointRequestDefinition> + */ + private static function generateRequestDefinitionsWithAllFormats( + EndpointRequestDefinition $endpointRequestDefinition, + string $snapshotName + ): iterable { + foreach (self::REQUIRED_FORMATS as $format) { + $resourceType = $endpointRequestDefinition->getExpectedResourceType(); + self::assertNotNull($resourceType, "Expected resource type for $endpointRequestDefinition cannot be null"); + yield $endpointRequestDefinition + ->withAcceptHeader( + self::generateMediaTypeString($resourceType, $format) + ) + ->withSnapshotName( + sprintf( + self::SNAPSHOT_FILTER_PATH, + $format, + $snapshotName + ) + ); + } + } + + /** + * @return iterable + */ + private static function getFilterQuery(): iterable + { + foreach (self::getFilterQueryStructure() as $filterSnapshotName => $filter) { + yield "$filterSnapshotName" => urldecode( + http_build_query($filter) + ); + } + } + + /** + * @return iterable}> + */ + private static function getFilterQueryStructure(): iterable + { + yield self::SNAPSHOT_NO_FILTER => []; + + yield 'filter-by-content-type-identifier-folder' => [ + 'filter' => [ + 'ContentTypeIdentifierCriterion' => 'folder', + ], + ]; + + yield 'filter-by-content-type-identifier-folder-and-landing-page' => [ + 'filter' => [ + 'ContentTypeIdentifierCriterion' => [ + 'folder', 'landing_page', + ], + ], + ]; + + yield 'filter-by-content-type-identifier-folder-and-media-location-id' => [ + 'filter' => [ + 'AND' => [ + 'ContentTypeIdentifierCriterion' => 'folder', + 'LocationIdCriterion' => self::LOCATION_ID_MEDIA, + ], + ], + ]; + + yield 'filter-by-content-type-identifier-folder-or-subtree' => [ + 'filter' => [ + 'OR' => [ + 'ContentTypeIdentifierCriterion' => 'folder', + 'SubtreeCriterion' => '/1/5/', + ], + ], + ]; + } +} diff --git a/tests/integration/Resources/REST/Schemas/ContentTreeNode.json b/tests/integration/Resources/REST/Schemas/ContentTreeNode.json new file mode 100644 index 0000000000..8652632758 --- /dev/null +++ b/tests/integration/Resources/REST/Schemas/ContentTreeNode.json @@ -0,0 +1,128 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "ContentTreeNode": { + "type": "object", + "properties": { + "_media-type": { + "type": "string" + }, + "locationId": { + "type": "integer" + }, + "contentId": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "contentTypeIdentifier": { + "type": "string" + }, + "isContainer": { + "type": "boolean" + }, + "isInvisible": { + "type": "boolean" + }, + "displayLimit": { + "type": "integer" + }, + "totalChildrenCount": { + "type": "integer" + }, + "reverseRelationsCount": { + "type": "integer" + }, + "isBookmarked": { + "type": "boolean" + }, + "children": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "_media-type": { + "type": "string" + }, + "locationId": { + "type": "integer" + }, + "contentId": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "contentTypeIdentifier": { + "type": "string" + }, + "isContainer": { + "type": "boolean" + }, + "isInvisible": { + "type": "boolean" + }, + "displayLimit": { + "type": "integer" + }, + "totalChildrenCount": { + "type": "integer" + }, + "reverseRelationsCount": { + "type": "integer" + }, + "isBookmarked": { + "type": "boolean" + }, + "children": { + "type": "array", + "items": {} + } + }, + "required": [ + "_media-type", + "locationId", + "pathString", + "contentId", + "versionNo", + "translations", + "name", + "contentTypeIdentifier", + "isContainer", + "isInvisible", + "displayLimit", + "totalChildrenCount", + "reverseRelationsCount", + "isBookmarked", + "children" + ] + } + ] + } + }, + "required": [ + "_media-type", + "locationId", + "pathString", + "contentId", + "versionNo", + "translations", + "name", + "contentTypeIdentifier", + "isContainer", + "isInvisible", + "displayLimit", + "totalChildrenCount", + "reverseRelationsCount", + "isBookmarked", + "children" + ] + } + }, + "required": [ + "ContentTreeNode" + ] +} diff --git a/tests/integration/Resources/REST/Schemas/ContentTreeNode.xsd b/tests/integration/Resources/REST/Schemas/ContentTreeNode.xsd new file mode 100644 index 0000000000..d3cd136b92 --- /dev/null +++ b/tests/integration/Resources/REST/Schemas/ContentTreeNode.xsd @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/integration/Resources/REST/Snapshots/ContentTreeNode/filter/json/filter-by-content-type-identifier-folder-and-landing-page.json b/tests/integration/Resources/REST/Snapshots/ContentTreeNode/filter/json/filter-by-content-type-identifier-folder-and-landing-page.json new file mode 100644 index 0000000000..b93aa863fd --- /dev/null +++ b/tests/integration/Resources/REST/Snapshots/ContentTreeNode/filter/json/filter-by-content-type-identifier-folder-and-landing-page.json @@ -0,0 +1,93 @@ +{ + "ContentTreeNode": { + "_media-type": "application/vnd.ibexa.api.ContentTreeNode+json", + "children": [ + { + "_media-type": "application/vnd.ibexa.api.ContentTreeNode+json", + "children": [], + "contentId": 57, + "contentTypeIdentifier": "landing_page", + "displayLimit": 30, + "isBookmarked": false, + "isContainer": true, + "isInvisible": false, + "locationId": 2, + "mainLanguageCode": "eng-GB", + "name": "Home", + "pathString": "/1/2/", + "reverseRelationsCount": 0, + "totalChildrenCount": 0, + "translations": "eng-GB", + "versionNo": 1 + }, + { + "_media-type": "application/vnd.ibexa.api.ContentTreeNode+json", + "children": [], + "contentId": 41, + "contentTypeIdentifier": "folder", + "displayLimit": 30, + "isBookmarked": false, + "isContainer": true, + "isInvisible": false, + "locationId": 43, + "mainLanguageCode": "eng-US", + "name": "Media", + "pathString": "/1/43/", + "reverseRelationsCount": 0, + "totalChildrenCount": 3, + "translations": "eng-US", + "versionNo": 1 + }, + { + "_media-type": "application/vnd.ibexa.api.ContentTreeNode+json", + "children": [], + "contentId": 45, + "contentTypeIdentifier": "folder", + "displayLimit": 30, + "isBookmarked": false, + "isContainer": true, + "isInvisible": false, + "locationId": 48, + "mainLanguageCode": "eng-US", + "name": "Setup", + "pathString": "/1/48/", + "reverseRelationsCount": 0, + "totalChildrenCount": 0, + "translations": "eng-US", + "versionNo": 1 + }, + { + "_media-type": "application/vnd.ibexa.api.ContentTreeNode+json", + "children": [], + "contentId": 56, + "contentTypeIdentifier": "folder", + "displayLimit": 30, + "isBookmarked": false, + "isContainer": true, + "isInvisible": false, + "locationId": 58, + "mainLanguageCode": "eng-US", + "name": "Design", + "pathString": "/1/58/", + "reverseRelationsCount": 0, + "totalChildrenCount": 0, + "translations": "eng-US", + "versionNo": 1 + } + ], + "contentId": 0, + "contentTypeIdentifier": "", + "displayLimit": 10, + "isBookmarked": false, + "isContainer": true, + "isInvisible": false, + "locationId": 1, + "mainLanguageCode": "eng-GB", + "name": "", + "pathString": "/1/", + "reverseRelationsCount": 0, + "totalChildrenCount": 4, + "translations": "", + "versionNo": 1 + } +} diff --git a/tests/integration/Resources/REST/Snapshots/ContentTreeNode/filter/json/filter-by-content-type-identifier-folder-and-media-location-id.json b/tests/integration/Resources/REST/Snapshots/ContentTreeNode/filter/json/filter-by-content-type-identifier-folder-and-media-location-id.json new file mode 100644 index 0000000000..8d133ecb73 --- /dev/null +++ b/tests/integration/Resources/REST/Snapshots/ContentTreeNode/filter/json/filter-by-content-type-identifier-folder-and-media-location-id.json @@ -0,0 +1,39 @@ +{ + "ContentTreeNode": { + "_media-type": "application/vnd.ibexa.api.ContentTreeNode+json", + "children": [ + { + "_media-type": "application/vnd.ibexa.api.ContentTreeNode+json", + "children": [], + "contentId": 41, + "contentTypeIdentifier": "folder", + "displayLimit": 30, + "isBookmarked": false, + "isContainer": true, + "isInvisible": false, + "locationId": 43, + "mainLanguageCode": "eng-US", + "name": "Media", + "pathString": "/1/43/", + "reverseRelationsCount": 0, + "totalChildrenCount": 0, + "translations": "eng-US", + "versionNo": 1 + } + ], + "contentId": 0, + "contentTypeIdentifier": "", + "displayLimit": 10, + "isBookmarked": false, + "isContainer": true, + "isInvisible": false, + "locationId": 1, + "mainLanguageCode": "eng-GB", + "name": "", + "pathString": "/1/", + "reverseRelationsCount": 0, + "totalChildrenCount": 1, + "translations": "", + "versionNo": 1 + } +} diff --git a/tests/integration/Resources/REST/Snapshots/ContentTreeNode/filter/json/filter-by-content-type-identifier-folder-or-subtree.json b/tests/integration/Resources/REST/Snapshots/ContentTreeNode/filter/json/filter-by-content-type-identifier-folder-or-subtree.json new file mode 100644 index 0000000000..240568a68f --- /dev/null +++ b/tests/integration/Resources/REST/Snapshots/ContentTreeNode/filter/json/filter-by-content-type-identifier-folder-or-subtree.json @@ -0,0 +1,93 @@ +{ + "ContentTreeNode": { + "_media-type": "application/vnd.ibexa.api.ContentTreeNode+json", + "children": [ + { + "_media-type": "application/vnd.ibexa.api.ContentTreeNode+json", + "children": [], + "contentId": 41, + "contentTypeIdentifier": "folder", + "displayLimit": 30, + "isBookmarked": false, + "isContainer": true, + "isInvisible": false, + "locationId": 43, + "mainLanguageCode": "eng-US", + "name": "Media", + "pathString": "/1/43/", + "reverseRelationsCount": 0, + "totalChildrenCount": 3, + "translations": "eng-US", + "versionNo": 1 + }, + { + "_media-type": "application/vnd.ibexa.api.ContentTreeNode+json", + "children": [], + "contentId": 45, + "contentTypeIdentifier": "folder", + "displayLimit": 30, + "isBookmarked": false, + "isContainer": true, + "isInvisible": false, + "locationId": 48, + "mainLanguageCode": "eng-US", + "name": "Setup", + "pathString": "/1/48/", + "reverseRelationsCount": 0, + "totalChildrenCount": 0, + "translations": "eng-US", + "versionNo": 1 + }, + { + "_media-type": "application/vnd.ibexa.api.ContentTreeNode+json", + "children": [], + "contentId": 4, + "contentTypeIdentifier": "user_group", + "displayLimit": 30, + "isBookmarked": true, + "isContainer": true, + "isInvisible": false, + "locationId": 5, + "mainLanguageCode": "eng-US", + "name": "Users", + "pathString": "/1/5/", + "reverseRelationsCount": 0, + "totalChildrenCount": 5, + "translations": "eng-US", + "versionNo": 1 + }, + { + "_media-type": "application/vnd.ibexa.api.ContentTreeNode+json", + "children": [], + "contentId": 56, + "contentTypeIdentifier": "folder", + "displayLimit": 30, + "isBookmarked": false, + "isContainer": true, + "isInvisible": false, + "locationId": 58, + "mainLanguageCode": "eng-US", + "name": "Design", + "pathString": "/1/58/", + "reverseRelationsCount": 0, + "totalChildrenCount": 0, + "translations": "eng-US", + "versionNo": 1 + } + ], + "contentId": 0, + "contentTypeIdentifier": "", + "displayLimit": 10, + "isBookmarked": false, + "isContainer": true, + "isInvisible": false, + "locationId": 1, + "mainLanguageCode": "eng-GB", + "name": "", + "pathString": "/1/", + "reverseRelationsCount": 0, + "totalChildrenCount": 4, + "translations": "", + "versionNo": 1 + } +} diff --git a/tests/integration/Resources/REST/Snapshots/ContentTreeNode/filter/json/filter-by-content-type-identifier-folder.json b/tests/integration/Resources/REST/Snapshots/ContentTreeNode/filter/json/filter-by-content-type-identifier-folder.json new file mode 100644 index 0000000000..ded51eb7fd --- /dev/null +++ b/tests/integration/Resources/REST/Snapshots/ContentTreeNode/filter/json/filter-by-content-type-identifier-folder.json @@ -0,0 +1,75 @@ +{ + "ContentTreeNode": { + "_media-type": "application/vnd.ibexa.api.ContentTreeNode+json", + "children": [ + { + "_media-type": "application/vnd.ibexa.api.ContentTreeNode+json", + "children": [], + "contentId": 41, + "contentTypeIdentifier": "folder", + "displayLimit": 30, + "isBookmarked": false, + "isContainer": true, + "isInvisible": false, + "locationId": 43, + "mainLanguageCode": "eng-US", + "name": "Media", + "pathString": "/1/43/", + "reverseRelationsCount": 0, + "totalChildrenCount": 3, + "translations": "eng-US", + "versionNo": 1 + }, + { + "_media-type": "application/vnd.ibexa.api.ContentTreeNode+json", + "children": [], + "contentId": 45, + "contentTypeIdentifier": "folder", + "displayLimit": 30, + "isBookmarked": false, + "isContainer": true, + "isInvisible": false, + "locationId": 48, + "mainLanguageCode": "eng-US", + "name": "Setup", + "pathString": "/1/48/", + "reverseRelationsCount": 0, + "totalChildrenCount": 0, + "translations": "eng-US", + "versionNo": 1 + }, + { + "_media-type": "application/vnd.ibexa.api.ContentTreeNode+json", + "children": [], + "contentId": 56, + "contentTypeIdentifier": "folder", + "displayLimit": 30, + "isBookmarked": false, + "isContainer": true, + "isInvisible": false, + "locationId": 58, + "mainLanguageCode": "eng-US", + "name": "Design", + "pathString": "/1/58/", + "reverseRelationsCount": 0, + "totalChildrenCount": 0, + "translations": "eng-US", + "versionNo": 1 + } + ], + "contentId": 0, + "contentTypeIdentifier": "", + "displayLimit": 10, + "isBookmarked": false, + "isContainer": true, + "isInvisible": false, + "locationId": 1, + "mainLanguageCode": "eng-GB", + "name": "", + "pathString": "/1/", + "reverseRelationsCount": 0, + "totalChildrenCount": 3, + "translations": "", + "versionNo": 1 + } +} diff --git a/tests/integration/Resources/REST/Snapshots/ContentTreeNode/filter/json/no-filter.json b/tests/integration/Resources/REST/Snapshots/ContentTreeNode/filter/json/no-filter.json new file mode 100644 index 0000000000..0337e22d7e --- /dev/null +++ b/tests/integration/Resources/REST/Snapshots/ContentTreeNode/filter/json/no-filter.json @@ -0,0 +1,111 @@ +{ + "ContentTreeNode": { + "_media-type": "application/vnd.ibexa.api.ContentTreeNode+json", + "children": [ + { + "_media-type": "application/vnd.ibexa.api.ContentTreeNode+json", + "children": [], + "contentId": 57, + "contentTypeIdentifier": "landing_page", + "displayLimit": 30, + "isBookmarked": false, + "isContainer": true, + "isInvisible": false, + "locationId": 2, + "mainLanguageCode": "eng-GB", + "name": "Home", + "pathString": "/1/2/", + "reverseRelationsCount": 0, + "totalChildrenCount": 1, + "translations": "eng-GB", + "versionNo": 1 + }, + { + "_media-type": "application/vnd.ibexa.api.ContentTreeNode+json", + "children": [], + "contentId": 41, + "contentTypeIdentifier": "folder", + "displayLimit": 30, + "isBookmarked": false, + "isContainer": true, + "isInvisible": false, + "locationId": 43, + "mainLanguageCode": "eng-US", + "name": "Media", + "pathString": "/1/43/", + "reverseRelationsCount": 0, + "totalChildrenCount": 3, + "translations": "eng-US", + "versionNo": 1 + }, + { + "_media-type": "application/vnd.ibexa.api.ContentTreeNode+json", + "children": [], + "contentId": 45, + "contentTypeIdentifier": "folder", + "displayLimit": 30, + "isBookmarked": false, + "isContainer": true, + "isInvisible": false, + "locationId": 48, + "mainLanguageCode": "eng-US", + "name": "Setup", + "pathString": "/1/48/", + "reverseRelationsCount": 0, + "totalChildrenCount": 0, + "translations": "eng-US", + "versionNo": 1 + }, + { + "_media-type": "application/vnd.ibexa.api.ContentTreeNode+json", + "children": [], + "contentId": 4, + "contentTypeIdentifier": "user_group", + "displayLimit": 30, + "isBookmarked": true, + "isContainer": true, + "isInvisible": false, + "locationId": 5, + "mainLanguageCode": "eng-US", + "name": "Users", + "pathString": "/1/5/", + "reverseRelationsCount": 0, + "totalChildrenCount": 5, + "translations": "eng-US", + "versionNo": 1 + }, + { + "_media-type": "application/vnd.ibexa.api.ContentTreeNode+json", + "children": [], + "contentId": 56, + "contentTypeIdentifier": "folder", + "displayLimit": 30, + "isBookmarked": false, + "isContainer": true, + "isInvisible": false, + "locationId": 58, + "mainLanguageCode": "eng-US", + "name": "Design", + "pathString": "/1/58/", + "reverseRelationsCount": 0, + "totalChildrenCount": 0, + "translations": "eng-US", + "versionNo": 1 + } + ], + "contentId": 0, + "contentTypeIdentifier": "", + "displayLimit": 10, + "isBookmarked": false, + "isContainer": true, + "isInvisible": false, + "locationId": 1, + "mainLanguageCode": "eng-GB", + "name": "", + "pathString": "/1/", + "reverseRelationsCount": 0, + "totalChildrenCount": 5, + "translations": "", + "versionNo": 1 + } +} diff --git a/tests/integration/Resources/REST/Snapshots/ContentTreeNode/filter/xml/no-filter.xml b/tests/integration/Resources/REST/Snapshots/ContentTreeNode/filter/xml/no-filter.xml new file mode 100644 index 0000000000..e4a55a1fc0 --- /dev/null +++ b/tests/integration/Resources/REST/Snapshots/ContentTreeNode/filter/xml/no-filter.xml @@ -0,0 +1,97 @@ + + + 1 + /1/ + 0 + 1 + + eng-GB + + + true + false + 10 + 5 + 0 + false + + 2 + /1/2/ + 57 + 1 + eng-GB + eng-GB + Home + landing_page + true + false + 30 + 1 + 0 + false + + + 43 + /1/43/ + 41 + 1 + eng-US + eng-US + Media + folder + true + false + 30 + 3 + 0 + false + + + 48 + /1/48/ + 45 + 1 + eng-US + eng-US + Setup + folder + true + false + 30 + 0 + 0 + false + + + 5 + /1/5/ + 4 + 1 + eng-US + eng-US + Users + user_group + true + false + 30 + 5 + 0 + true + + + 58 + /1/58/ + 56 + 1 + eng-US + eng-US + Design + folder + true + false + 30 + 0 + 0 + false + +