Completed
Push — master ( f1cbd3...96a412 )
by Kévin
03:19
created

QueryChecker   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 132
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 4

Importance

Changes 0
Metric Value
wmc 19
lcom 0
cbo 4
dl 0
loc 132
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A hasHavingClause() 0 4 1
A hasRootEntityWithForeignKeyIdentifier() 0 4 1
A hasRootEntityWithCompositeIdentifier() 0 4 1
A hasRootEntityWithIdentifier() 0 14 4
A hasMaxResults() 0 4 1
C hasOrderByOnToManyJoin() 0 46 11
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
namespace ApiPlatform\Core\Bridge\Doctrine\Orm\Util;
13
14
use Doctrine\Common\Persistence\ManagerRegistry;
15
use Doctrine\ORM\QueryBuilder;
16
17
/**
18
 * Utility functions for working with Doctrine ORM query.
19
 *
20
 * @author Teoh Han Hui <[email protected]>
21
 * @author Vincent Chalamon <[email protected]>
22
 */
23
abstract class QueryChecker
24
{
25
    /**
26
     * Determines whether the query builder uses a HAVING clause.
27
     *
28
     * @param QueryBuilder $queryBuilder
29
     *
30
     * @return bool
31
     */
32
    public static function hasHavingClause(QueryBuilder $queryBuilder) : bool
33
    {
34
        return !empty($queryBuilder->getDQLPart('having'));
35
    }
36
37
    /**
38
     * Determines whether the query builder has any root entity with foreign key identifier.
39
     *
40
     * @param QueryBuilder    $queryBuilder
41
     * @param ManagerRegistry $managerRegistry
42
     *
43
     * @return bool
44
     */
45
    public static function hasRootEntityWithForeignKeyIdentifier(QueryBuilder $queryBuilder, ManagerRegistry $managerRegistry) : bool
46
    {
47
        return self::hasRootEntityWithIdentifier($queryBuilder, $managerRegistry, true);
48
    }
49
50
    /**
51
     * Determines whether the query builder has any composite identifier.
52
     *
53
     * @param QueryBuilder    $queryBuilder
54
     * @param ManagerRegistry $managerRegistry
55
     *
56
     * @return bool
57
     */
58
    public static function hasRootEntityWithCompositeIdentifier(QueryBuilder $queryBuilder, ManagerRegistry $managerRegistry) : bool
59
    {
60
        return self::hasRootEntityWithIdentifier($queryBuilder, $managerRegistry, false);
61
    }
62
63
    /**
64
     * Detects if the root entity has the given identifier.
65
     *
66
     * @param QueryBuilder    $queryBuilder
67
     * @param ManagerRegistry $managerRegistry
68
     * @param bool            $isForeign
69
     *
70
     * @return bool
71
     */
72
    private static function hasRootEntityWithIdentifier(QueryBuilder $queryBuilder, ManagerRegistry $managerRegistry, bool $isForeign) : bool
73
    {
74
        foreach ($queryBuilder->getRootEntities() as $rootEntity) {
75
            $rootMetadata = $managerRegistry
76
                ->getManagerForClass($rootEntity)
77
                ->getClassMetadata($rootEntity);
78
79
            if ($isForeign ? $rootMetadata->isIdentifierComposite : $rootMetadata->containsForeignIdentifier) {
80
                return true;
81
            }
82
        }
83
84
        return false;
85
    }
86
87
    /**
88
     * Determines whether the query builder has the maximum number of results specified.
89
     *
90
     * @param QueryBuilder $queryBuilder
91
     *
92
     * @return bool
93
     */
94
    public static function hasMaxResults(QueryBuilder $queryBuilder) : bool
95
    {
96
        return null !== $queryBuilder->getMaxResults();
97
    }
98
99
    /**
100
     * Determines whether the query builder has ORDER BY on entity joined through
101
     * to-many association.
102
     *
103
     * @param QueryBuilder    $queryBuilder
104
     * @param ManagerRegistry $managerRegistry
105
     *
106
     * @return bool
107
     */
108
    public static function hasOrderByOnToManyJoin(QueryBuilder $queryBuilder, ManagerRegistry $managerRegistry) : bool
109
    {
110
        if (
111
            empty($orderByParts = $queryBuilder->getDQLPart('orderBy')) ||
112
            empty($joinParts = $queryBuilder->getDQLPart('join'))
113
        ) {
114
            return false;
115
        }
116
117
        $orderByAliases = [];
118
        foreach ($orderByParts as $orderBy) {
119
            $parts = QueryNameGenerator::getOrderByParts($orderBy);
120
121
            foreach ($parts as $part) {
122
                if (false !== ($pos = strpos($part, '.'))) {
123
                    $alias = substr($part, 0, $pos);
124
125
                    $orderByAliases[$alias] = true;
126
                }
127
            }
128
        }
129
130
        if (!empty($orderByAliases)) {
131
            foreach ($joinParts as $rootAlias => $joins) {
132
                foreach ($joins as $join) {
133
                    $alias = QueryNameGenerator::getJoinAlias($join);
134
135
                    if (isset($orderByAliases[$alias])) {
136
                        $relationship = QueryNameGenerator::getJoinRelationship($join);
137
138
                        $relationshipParts = explode('.', $relationship);
139
                        $parentAlias = $relationshipParts[0];
140
                        $association = $relationshipParts[1];
141
142
                        $parentMetadata = QueryNameGenerator::getClassMetadataFromJoinAlias($parentAlias, $queryBuilder, $managerRegistry);
143
144
                        if ($parentMetadata->isCollectionValuedAssociation($association)) {
145
                            return true;
146
                        }
147
                    }
148
                }
149
            }
150
        }
151
152
        return false;
153
    }
154
}
155