From cd2a017e840ec5fed0efd5c0825bfcb3d09f6275 Mon Sep 17 00:00:00 2001 From: Ambroise Maupate Date: Wed, 13 Dec 2023 11:41:35 +0100 Subject: [PATCH] fix(Api): Added `AttributeValueQueryExtension` and `NodesTagsQueryExtension` to restrict tags and attributes linked to any published node. --- lib/RoadizCoreBundle/config/services.yaml | 15 ++++ .../AttributeValueQueryExtension.php | 81 +++++++++++++++++ .../Api/Extension/NodesTagsQueryExtension.php | 89 +++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 lib/RoadizCoreBundle/src/Api/Extension/AttributeValueQueryExtension.php create mode 100644 lib/RoadizCoreBundle/src/Api/Extension/NodesTagsQueryExtension.php diff --git a/lib/RoadizCoreBundle/config/services.yaml b/lib/RoadizCoreBundle/config/services.yaml index 320fc593..bd71d3e9 100644 --- a/lib/RoadizCoreBundle/config/services.yaml +++ b/lib/RoadizCoreBundle/config/services.yaml @@ -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; + } +}