Passed
Pull Request — feature/publishable (#31)
by Vincent
05:42
created

PublishableExtension::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 2
c 1
b 0
f 0
dl 0
loc 4
ccs 0
cts 3
cp 0
rs 10
cc 1
nc 1
nop 2
crap 2
1
<?php
2
3
/*
4
 * This file is part of the Silverback API Component Bundle Project
5
 *
6
 * (c) Daniel West <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Silverback\ApiComponentBundle\Extension;
15
16
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryItemExtensionInterface;
17
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
18
use Doctrine\ORM\QueryBuilder;
19
use Silverback\ApiComponentBundle\Entity\Utility\PublishableInterface;
20
use Symfony\Component\ExpressionLanguage\Expression;
21
use Symfony\Component\Security\Core\Security;
22
23
/**
24
 * @author Vincent Chalamon <[email protected]>
25
 */
26
final class PublishableExtension implements QueryItemExtensionInterface
27
{
28
    private Security $security;
29
    private string $permission;
30
31
    public function __construct(Security $security, string $permission)
32
    {
33
        $this->security = $security;
34
        $this->permission = $permission;
35
    }
36
37
    public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, string $operationName = null, array $context = [])
38
    {
39
        if (!is_a($resourceClass, PublishableInterface::class, true)) {
40
            return;
41
        }
42
43
        $alias = $queryBuilder->getRootAliases()[0];
44
        if (!$this->security->isGranted(new Expression($this->permission))) {
45
            // User has no access to draft object
46
            $queryBuilder
47
                ->andWhere("$alias.publishedAt IS NOT NULL")
48
                ->andWhere("$alias.publishedAt >= :currentTime");
49
50
            return;
51
        }
52
53
        // Reset queryBuilder to prevent an invalid DQL
54
        $queryBuilder->where('1 = 1');
55
        $publishedResourceAlias = $queryNameGenerator->generateJoinAlias('publishedResource');
56
        $queryBuilder->leftJoin("$alias.publishedResource", $publishedResourceAlias);
57
58
        foreach ($identifiers as $identifier) {
59
            // (o.id = :id AND o.publishedAt IS NOT NULL AND o.publishedAt <= :currentTime)
60
            // OR ((o.publishedAt IS NULL OR o.publishedAt > :currentTime) AND o.publishedResource = :id)
61
            $queryBuilder->orWhere(
62
                $queryBuilder->expr()->andX(
63
                    $queryBuilder->expr()->eq("$alias.$identifier", ":id_$identifier"),
64
                    $queryBuilder->expr()->isNotNull("$alias.publishedAt"),
65
                    $queryBuilder->expr()->lte("$alias.publishedAt", ":currentTime"),
66
                ),
67
                $queryBuilder->expr()->andX(
68
                    $queryBuilder->expr()->orX(
69
                        $queryBuilder->expr()->isNull("$alias.publishedAt"),
70
                        $queryBuilder->expr()->gt("$alias.publishedAt", ":currentTime"),
71
                    ),
72
                    $queryBuilder->expr()->eq("$publishedResourceAlias.id", ":id_$identifier"),
73
                )
74
            )->setParameter('currentTime', new \DateTimeImmutable());
75
        }
76
    }
77
}
78