Completed
Pull Request — master (#3308)
by Karol
07:23 queued 01:52
created

QueryChecker::hasLeftJoin()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 11
rs 10
c 0
b 0
f 0
cc 4
nc 4
nop 1
1
<?php
2
3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <[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 ApiPlatform\Core\Bridge\Doctrine\Orm\Util;
15
16
use Doctrine\Common\Persistence\ManagerRegistry;
17
use Doctrine\ORM\Mapping\ClassMetadata;
18
use Doctrine\ORM\QueryBuilder;
19
20
/**
21
 * Utility functions for working with Doctrine ORM query.
22
 *
23
 * @author Teoh Han Hui <[email protected]>
24
 * @author Vincent Chalamon <[email protected]>
25
 *
26
 * @internal
27
 */
28
final class QueryChecker
29
{
30
    private function __construct()
31
    {
32
    }
33
34
    /**
35
     * Determines whether the QueryBuilder uses a HAVING clause.
36
     */
37
    public static function hasHavingClause(QueryBuilder $queryBuilder): bool
38
    {
39
        return null !== $queryBuilder->getDQLPart('having');
40
    }
41
42
    /**
43
     * Determines whether the QueryBuilder has any root entity with foreign key identifier.
44
     */
45
    public static function hasRootEntityWithForeignKeyIdentifier(QueryBuilder $queryBuilder, ManagerRegistry $managerRegistry): bool
46
    {
47
        foreach ($queryBuilder->getRootEntities() as $rootEntity) {
48
            /** @var ClassMetadata $rootMetadata */
49
            $rootMetadata = $managerRegistry
50
                ->getManagerForClass($rootEntity)
51
                ->getClassMetadata($rootEntity);
52
53
            if ($rootMetadata->containsForeignIdentifier) {
54
                return true;
55
            }
56
        }
57
58
        return false;
59
    }
60
61
    /**
62
     * Determines whether the QueryBuilder has any composite identifier.
63
     */
64
    public static function hasRootEntityWithCompositeIdentifier(QueryBuilder $queryBuilder, ManagerRegistry $managerRegistry): bool
65
    {
66
        foreach ($queryBuilder->getRootEntities() as $rootEntity) {
67
            /** @var ClassMetadata $rootMetadata */
68
            $rootMetadata = $managerRegistry
69
                ->getManagerForClass($rootEntity)
70
                ->getClassMetadata($rootEntity);
71
72
            if ($rootMetadata->isIdentifierComposite) {
73
                return true;
74
            }
75
        }
76
77
        return false;
78
    }
79
80
    /**
81
     * Determines whether the QueryBuilder has a limit on the maximum number of results.
82
     */
83
    public static function hasMaxResults(QueryBuilder $queryBuilder): bool
84
    {
85
        return null !== $queryBuilder->getMaxResults();
86
    }
87
88
    /**
89
     * Determines whether the QueryBuilder has ORDER BY on a column from a fetch joined to-many association.
90
     */
91
    public static function hasOrderByOnFetchJoinedToManyAssociation(QueryBuilder $queryBuilder, ManagerRegistry $managerRegistry): bool
92
    {
93
        if (
94
            0 === \count($selectParts = $queryBuilder->getDQLPart('select')) ||
95
            0 === \count($queryBuilder->getDQLPart('join')) ||
96
            0 === \count($orderByParts = $queryBuilder->getDQLPart('orderBy'))
97
        ) {
98
            return false;
99
        }
100
101
        $rootAliases = $queryBuilder->getRootAliases();
102
103
        $selectAliases = [];
104
105
        foreach ($selectParts as $select) {
106
            foreach ($select->getParts() as $part) {
107
                [$alias] = explode('.', $part);
108
109
                $selectAliases[] = $alias;
110
            }
111
        }
112
113
        $selectAliases = array_diff($selectAliases, $rootAliases);
114
        if (0 === \count($selectAliases)) {
115
            return false;
116
        }
117
118
        $orderByAliases = [];
119
120
        foreach ($orderByParts as $orderBy) {
121
            foreach ($orderBy->getParts() as $part) {
122
                if (false !== strpos($part, '.')) {
123
                    [$alias] = explode('.', $part);
124
125
                    $orderByAliases[] = $alias;
126
                }
127
            }
128
        }
129
130
        $orderByAliases = array_diff($orderByAliases, $rootAliases);
131
        if (0 === \count($orderByAliases)) {
132
            return false;
133
        }
134
135
        foreach ($orderByAliases as $orderByAlias) {
136
            $inToManyContext = false;
137
138
            foreach (QueryBuilderHelper::traverseJoins($orderByAlias, $queryBuilder, $managerRegistry) as $alias => [$metadata, $association]) {
139
                if ($inToManyContext && \in_array($alias, $selectAliases, true)) {
140
                    return true;
141
                }
142
143
                if (null !== $association && $metadata->isCollectionValuedAssociation($association)) {
144
                    $inToManyContext = true;
145
                }
146
            }
147
        }
148
149
        return false;
150
    }
151
152
    /**
153
     * Determines whether the QueryBuilder has ORDER BY on a column from a fetch joined to-many association.
154
     *
155
     * @deprecated
156
     */
157
    public static function hasOrderByOnToManyJoin(QueryBuilder $queryBuilder, ManagerRegistry $managerRegistry): bool
158
    {
159
        @trigger_error(sprintf('The use of "%s::hasOrderByOnToManyJoin()" is deprecated since 2.4 and will be removed in 3.0. Use "%1$s::hasOrderByOnFetchJoinedToManyAssociation()" instead.', __CLASS__), E_USER_DEPRECATED);
160
161
        return self::hasOrderByOnFetchJoinedToManyAssociation($queryBuilder, $managerRegistry);
162
    }
163
164
    /**
165
     * Determines whether the QueryBuilder has a joined to-many association.
166
     */
167
    public static function hasJoinedToManyAssociation(QueryBuilder $queryBuilder, ManagerRegistry $managerRegistry): bool
168
    {
169
        if (
170
            0 === \count($queryBuilder->getDQLPart('join'))
171
        ) {
172
            return false;
173
        }
174
175
        $joinAliases = array_diff($queryBuilder->getAllAliases(), $queryBuilder->getRootAliases());
176
        if (0 === \count($joinAliases)) {
177
            return false;
178
        }
179
180
        foreach ($joinAliases as $joinAlias) {
181
            foreach (QueryBuilderHelper::traverseJoins($joinAlias, $queryBuilder, $managerRegistry) as $alias => [$metadata, $association]) {
182
                if (null !== $association && $metadata->isCollectionValuedAssociation($association)) {
183
                    return true;
184
                }
185
            }
186
        }
187
188
        return false;
189
    }
190
}
191