Skip to content

Commit

Permalink
fix(Api): Added AttributeValueQueryExtension and `NodesTagsQueryExt…
Browse files Browse the repository at this point in the history
…ension` to restrict tags and attributes linked to any published node.
  • Loading branch information
ambroisemaupate committed Dec 13, 2023
1 parent 06bf63d commit cd2a017
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 0 deletions.
15 changes: 15 additions & 0 deletions lib/RoadizCoreBundle/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

declare(strict_types=1);

namespace RZ\Roadiz\CoreBundle\Api\Extension;

use ApiPlatform\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
use ApiPlatform\Doctrine\Orm\Extension\QueryItemExtensionInterface;
use ApiPlatform\Doctrine\Orm\Util\QueryBuilderHelper;
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use ApiPlatform\Metadata\Operation;
use Doctrine\ORM\QueryBuilder;
use RZ\Roadiz\CoreBundle\Entity\AttributeValue;
use RZ\Roadiz\CoreBundle\Entity\Node;
use RZ\Roadiz\CoreBundle\Preview\PreviewResolverInterface;

final class AttributeValueQueryExtension implements QueryItemExtensionInterface, QueryCollectionExtensionInterface
{
private PreviewResolverInterface $previewResolver;

public function __construct(
PreviewResolverInterface $previewResolver
) {
$this->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;
}
}
89 changes: 89 additions & 0 deletions lib/RoadizCoreBundle/src/Api/Extension/NodesTagsQueryExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

declare(strict_types=1);

namespace RZ\Roadiz\CoreBundle\Api\Extension;

use ApiPlatform\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
use ApiPlatform\Doctrine\Orm\Extension\QueryItemExtensionInterface;
use ApiPlatform\Doctrine\Orm\Util\QueryBuilderHelper;
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use ApiPlatform\Metadata\Operation;
use Doctrine\ORM\QueryBuilder;
use RZ\Roadiz\CoreBundle\Entity\Node;
use RZ\Roadiz\CoreBundle\Entity\Tag;
use RZ\Roadiz\CoreBundle\Preview\PreviewResolverInterface;

final class NodesTagsQueryExtension implements QueryItemExtensionInterface, QueryCollectionExtensionInterface
{
private PreviewResolverInterface $previewResolver;

public function __construct(
PreviewResolverInterface $previewResolver
) {
$this->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;
}
}

0 comments on commit cd2a017

Please sign in to comment.