Completed
Push — master ( 141530...b88d97 )
by Kévin
18:08
created

QueryChecker::hasRootEntityWithIdentifier()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 8
nc 3
nop 3
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
final class QueryChecker
27
{
28
    private function __construct()
29
    {
30
    }
31
32
    /**
33
     * Determines whether the query builder uses a HAVING clause.
34
     *
35
     * @param QueryBuilder $queryBuilder
36
     *
37
     * @return bool
38
     */
39
    public static function hasHavingClause(QueryBuilder $queryBuilder): bool
40
    {
41
        return !empty($queryBuilder->getDQLPart('having'));
42
    }
43
44
    /**
45
     * Determines whether the query builder has any root entity with foreign key identifier.
46
     *
47
     * @param QueryBuilder    $queryBuilder
48
     * @param ManagerRegistry $managerRegistry
49
     *
50
     * @return bool
51
     */
52
    public static function hasRootEntityWithForeignKeyIdentifier(QueryBuilder $queryBuilder, ManagerRegistry $managerRegistry): bool
53
    {
54
        return self::hasRootEntityWithIdentifier($queryBuilder, $managerRegistry, true);
55
    }
56
57
    /**
58
     * Determines whether the query builder has any composite identifier.
59
     *
60
     * @param QueryBuilder    $queryBuilder
61
     * @param ManagerRegistry $managerRegistry
62
     *
63
     * @return bool
64
     */
65
    public static function hasRootEntityWithCompositeIdentifier(QueryBuilder $queryBuilder, ManagerRegistry $managerRegistry): bool
66
    {
67
        return self::hasRootEntityWithIdentifier($queryBuilder, $managerRegistry, false);
68
    }
69
70
    /**
71
     * Detects if the root entity has the given identifier.
72
     *
73
     * @param QueryBuilder    $queryBuilder
74
     * @param ManagerRegistry $managerRegistry
75
     * @param bool            $isForeign
76
     *
77
     * @return bool
78
     */
79
    private static function hasRootEntityWithIdentifier(QueryBuilder $queryBuilder, ManagerRegistry $managerRegistry, bool $isForeign): bool
80
    {
81
        foreach ($queryBuilder->getRootEntities() as $rootEntity) {
82
            $rootMetadata = $managerRegistry
83
                ->getManagerForClass($rootEntity)
84
                ->getClassMetadata($rootEntity);
85
86
            if ($rootMetadata instanceof ClassMetadata && ($isForeign ? $rootMetadata->isIdentifierComposite : $rootMetadata->containsForeignIdentifier)) {
87
                return true;
88
            }
89
        }
90
91
        return false;
92
    }
93
94
    /**
95
     * Determines whether the query builder has the maximum number of results specified.
96
     *
97
     * @param QueryBuilder $queryBuilder
98
     *
99
     * @return bool
100
     */
101
    public static function hasMaxResults(QueryBuilder $queryBuilder): bool
102
    {
103
        return null !== $queryBuilder->getMaxResults();
104
    }
105
106
    /**
107
     * Determines whether the query builder has ORDER BY on entity joined through
108
     * to-many association.
109
     *
110
     * @param QueryBuilder    $queryBuilder
111
     * @param ManagerRegistry $managerRegistry
112
     *
113
     * @return bool
114
     */
115
    public static function hasOrderByOnToManyJoin(QueryBuilder $queryBuilder, ManagerRegistry $managerRegistry): bool
116
    {
117
        if (
118
            empty($orderByParts = $queryBuilder->getDQLPart('orderBy')) ||
119
            empty($joinParts = $queryBuilder->getDQLPart('join'))
120
        ) {
121
            return false;
122
        }
123
124
        $orderByAliases = [];
125
        foreach ($orderByParts as $orderBy) {
126
            $parts = QueryJoinParser::getOrderByParts($orderBy);
127
128
            foreach ($parts as $part) {
129
                if (false !== ($pos = strpos($part, '.'))) {
130
                    $alias = substr($part, 0, $pos);
131
132
                    $orderByAliases[$alias] = true;
133
                }
134
            }
135
        }
136
137
        if (!empty($orderByAliases)) {
138
            foreach ($joinParts as $joins) {
139
                foreach ($joins as $join) {
140
                    $alias = QueryJoinParser::getJoinAlias($join);
141
142
                    if (isset($orderByAliases[$alias])) {
143
                        $relationship = QueryJoinParser::getJoinRelationship($join);
144
                        list($parentAlias, $association) = explode('.', $relationship);
145
146
                        $parentMetadata = QueryJoinParser::getClassMetadataFromJoinAlias($parentAlias, $queryBuilder, $managerRegistry);
147
148
                        if ($parentMetadata->isCollectionValuedAssociation($association)) {
149
                            return true;
150
                        }
151
                    }
152
                }
153
            }
154
        }
155
156
        return false;
157
    }
158
}
159