diff --git a/CHANGELOG.md b/CHANGELOG.md index 90201619..74642d1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [v2.2.1](https://github.com/roadiz/core-bundle-dev-app/compare/v2.2.0...v2.2.1) (2023-12-13) + + +### Bug Fixes + +* **Api:** Added `AttributeValueQueryExtension` and `NodesTagsQueryExtension` to restrict tags and attributes linked to any published node. ([cd2a017](https://github.com/roadiz/core-bundle-dev-app/commit/cd2a017e840ec5fed0efd5c0825bfcb3d09f6275)) + ## [v2.2.0](https://github.com/roadiz/core-bundle-dev-app/compare/v2.1.51...v2.2.0) (2023-12-12) diff --git a/lib/RoadizCoreBundle/config/services.yaml b/lib/RoadizCoreBundle/config/services.yaml index 320fc593..30949db2 100644 --- a/lib/RoadizCoreBundle/config/services.yaml +++ b/lib/RoadizCoreBundle/config/services.yaml @@ -1,6 +1,6 @@ --- parameters: - roadiz_core.cms_version: '2.2.0' + roadiz_core.cms_version: '2.2.1' roadiz_core.cms_version_prefix: 'main' env(APP_NAMESPACE): "roadiz" env(APP_VERSION): "0.1.0" @@ -114,6 +114,21 @@ services: # Extension must be called after all filtering BUT before default pagination extension tags: [ { name: 'api_platform.doctrine.orm.query_extension.collection', priority: -40 } ] + # + # These API doctrine extension must be called last before pagination + # to perform on existing JOIN with node entities (found after filtering) + # + RZ\Roadiz\CoreBundle\Api\Extension\AttributeValueQueryExtension: + tags: [ + { name: 'api_platform.doctrine.orm.query_extension.collection', priority: -40 }, + { name: 'api_platform.doctrine.orm.query_extension.item', priority: -40 }, + ] + RZ\Roadiz\CoreBundle\Api\Extension\NodesTagsQueryExtension: + tags: [ + { name: 'api_platform.doctrine.orm.query_extension.collection', priority: -40 }, + { name: 'api_platform.doctrine.orm.query_extension.item', priority: -40 }, + ] + RZ\Roadiz\CoreBundle\Bag\: resource: '../src/Bag/' autowire: true diff --git a/lib/RoadizCoreBundle/src/Api/Extension/AttributeValueQueryExtension.php b/lib/RoadizCoreBundle/src/Api/Extension/AttributeValueQueryExtension.php new file mode 100644 index 00000000..7915f9bb --- /dev/null +++ b/lib/RoadizCoreBundle/src/Api/Extension/AttributeValueQueryExtension.php @@ -0,0 +1,81 @@ +previewResolver = $previewResolver; + } + + public function applyToItem( + QueryBuilder $queryBuilder, + QueryNameGeneratorInterface $queryNameGenerator, + string $resourceClass, + array $identifiers, + ?Operation $operation = null, + array $context = [] + ): void { + $this->apply($queryBuilder, $resourceClass); + } + + public function applyToCollection( + QueryBuilder $queryBuilder, + QueryNameGeneratorInterface $queryNameGenerator, + string $resourceClass, + ?Operation $operation = null, + array $context = [] + ): void { + $this->apply($queryBuilder, $resourceClass); + } + + private function apply( + QueryBuilder $queryBuilder, + string $resourceClass + ): void { + if ( + $resourceClass !== AttributeValue::class + ) { + return; + } + + $parts = $queryBuilder->getDQLPart('join'); + $rootAlias = $queryBuilder->getRootAliases()[0]; + if (!\is_array($parts) || !isset($parts[$rootAlias])) { + return; + } + + $existingNodeJoin = QueryBuilderHelper::getExistingJoin($queryBuilder, 'o', 'node'); + if (null === $existingNodeJoin || !$existingNodeJoin->getAlias()) { + return; + } + + if ($this->previewResolver->isPreview()) { + $queryBuilder + ->andWhere($queryBuilder->expr()->lte($existingNodeJoin->getAlias() . '.status', ':status')) + ->setParameter(':status', Node::PUBLISHED); + return; + } + + $queryBuilder + ->andWhere($queryBuilder->expr()->eq($existingNodeJoin->getAlias() . '.status', ':status')) + ->setParameter(':status', Node::PUBLISHED); + return; + } +} diff --git a/lib/RoadizCoreBundle/src/Api/Extension/NodesTagsQueryExtension.php b/lib/RoadizCoreBundle/src/Api/Extension/NodesTagsQueryExtension.php new file mode 100644 index 00000000..a5ea3cb3 --- /dev/null +++ b/lib/RoadizCoreBundle/src/Api/Extension/NodesTagsQueryExtension.php @@ -0,0 +1,89 @@ +previewResolver = $previewResolver; + } + + public function applyToItem( + QueryBuilder $queryBuilder, + QueryNameGeneratorInterface $queryNameGenerator, + string $resourceClass, + array $identifiers, + ?Operation $operation = null, + array $context = [] + ): void { + $this->apply($queryBuilder, $resourceClass); + } + + public function applyToCollection( + QueryBuilder $queryBuilder, + QueryNameGeneratorInterface $queryNameGenerator, + string $resourceClass, + ?Operation $operation = null, + array $context = [] + ): void { + $this->apply($queryBuilder, $resourceClass); + } + + private function apply( + QueryBuilder $queryBuilder, + string $resourceClass + ): void { + if ( + $resourceClass !== Tag::class + ) { + return; + } + + $parts = $queryBuilder->getDQLPart('join'); + $rootAlias = $queryBuilder->getRootAliases()[0]; + if (!\is_array($parts) || !isset($parts[$rootAlias])) { + return; + } + + $existingJoin = QueryBuilderHelper::getExistingJoin($queryBuilder, 'o', 'nodesTags'); + if (null === $existingJoin || !$existingJoin->getAlias()) { + return; + } + $existingNodeJoin = QueryBuilderHelper::getExistingJoin( + $queryBuilder, + $existingJoin->getAlias(), + 'node' + ); + if (null === $existingNodeJoin || !$existingNodeJoin->getAlias()) { + return; + } + + if ($this->previewResolver->isPreview()) { + $queryBuilder + ->andWhere($queryBuilder->expr()->lte($existingNodeJoin->getAlias() . '.status', ':status')) + ->setParameter(':status', Node::PUBLISHED); + return; + } + + $queryBuilder + ->andWhere($queryBuilder->expr()->eq($existingNodeJoin->getAlias() . '.status', ':status')) + ->setParameter(':status', Node::PUBLISHED); + return; + } +}