Completed
Push — master ( 8c259e...a3e53b )
by Guilherme
27:10 queued 12:02
created

WhereInWalker   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 98
Duplicated Lines 0 %

Test Coverage

Coverage 93.62%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 51
c 1
b 0
f 0
dl 0
loc 98
ccs 44
cts 47
cp 0.9362
rs 10
wmc 10

1 Method

Rating   Name   Duplication   Size   Complexity  
B walkSelectStatement() 0 73 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ORM\Tools\Pagination;
6
7
use Doctrine\ORM\Mapping\AssociationMetadata;
8
use Doctrine\ORM\Mapping\ToOneAssociationMetadata;
9
use Doctrine\ORM\Query\AST\ArithmeticExpression;
10
use Doctrine\ORM\Query\AST\ConditionalExpression;
11
use Doctrine\ORM\Query\AST\ConditionalFactor;
12
use Doctrine\ORM\Query\AST\ConditionalPrimary;
13
use Doctrine\ORM\Query\AST\ConditionalTerm;
14
use Doctrine\ORM\Query\AST\InExpression;
15
use Doctrine\ORM\Query\AST\InputParameter;
16
use Doctrine\ORM\Query\AST\NullComparisonExpression;
17
use Doctrine\ORM\Query\AST\PathExpression;
18
use Doctrine\ORM\Query\AST\SelectStatement;
19
use Doctrine\ORM\Query\AST\SimpleArithmeticExpression;
20
use Doctrine\ORM\Query\AST\WhereClause;
21
use Doctrine\ORM\Query\TreeWalkerAdapter;
22
use RuntimeException;
23
use function count;
24
use function reset;
25
26
/**
27
 * Replaces the whereClause of the AST with a WHERE id IN (:foo_1, :foo_2) equivalent.
28
 */
29
class WhereInWalker extends TreeWalkerAdapter
30
{
31
    /**
32
     * ID Count hint name.
33
     */
34
    public const HINT_PAGINATOR_ID_COUNT = 'doctrine.id.count';
35
36
    /**
37
     * Primary key alias for query.
38
     */
39
    public const PAGINATOR_ID_ALIAS = 'dpid';
40
41
    /**
42
     * Replaces the whereClause in the AST.
43
     *
44
     * Generates a clause equivalent to WHERE IN (:dpid_1, :dpid_2, ...)
45
     *
46
     * The parameter namespace (dpid) is defined by
47
     * the PAGINATOR_ID_ALIAS
48
     *
49
     * The total number of parameters is retrieved from
50
     * the HINT_PAGINATOR_ID_COUNT query hint.
51
     *
52
     * @throws RuntimeException
53
     */
54 60
    public function walkSelectStatement(SelectStatement $AST)
55
    {
56 60
        $queryComponents = $this->getQueryComponents();
57
        // Get the root entity and alias from the AST fromClause
58 60
        $from = $AST->fromClause->identificationVariableDeclarations;
59
60 60
        if (count($from) > 1) {
61
            throw new RuntimeException('Cannot count query which selects two FROM components, cannot make distinction');
62
        }
63
64 60
        $fromRoot  = reset($from);
65 60
        $rootAlias = $fromRoot->rangeVariableDeclaration->aliasIdentificationVariable;
66 60
        $rootClass = $queryComponents[$rootAlias]['metadata'];
67 60
        $property  = $rootClass->getProperty($rootClass->getSingleIdentifierFieldName());
68 60
        $pathType  = PathExpression::TYPE_STATE_FIELD;
69
70 60
        if ($property instanceof AssociationMetadata) {
71 1
            $pathType = $property instanceof ToOneAssociationMetadata
72 1
                ? PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION
73 1
                : PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION;
74
        }
75
76 60
        $pathExpression = new PathExpression(
77 60
            PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION,
78
            $rootAlias,
79 60
            $property->getName()
80
        );
81
82 60
        $pathExpression->type = $pathType;
83
84 60
        $count = $this->getQuery()->getHint(self::HINT_PAGINATOR_ID_COUNT);
85
86 60
        if ($count > 0) {
87 60
            $arithmeticExpression                             = new ArithmeticExpression();
88 60
            $arithmeticExpression->simpleArithmeticExpression = new SimpleArithmeticExpression(
89 60
                [$pathExpression]
90
            );
91 60
            $expression                                       = new InExpression($arithmeticExpression);
92 60
            $expression->literals[]                           = new InputParameter(':' . self::PAGINATOR_ID_ALIAS);
93
        } else {
94
            $expression      = new NullComparisonExpression($pathExpression);
95
            $expression->not = false;
96
        }
97
98 60
        $conditionalPrimary                              = new ConditionalPrimary();
99 60
        $conditionalPrimary->simpleConditionalExpression = $expression;
100
101 60
        if ($AST->whereClause) {
102 10
            if ($AST->whereClause->conditionalExpression instanceof ConditionalTerm) {
0 ignored issues
show
introduced by
$AST->whereClause->conditionalExpression is never a sub-type of Doctrine\ORM\Query\AST\ConditionalTerm.
Loading history...
103 2
                $AST->whereClause->conditionalExpression->conditionalFactors[] = $conditionalPrimary;
104 8
            } elseif ($AST->whereClause->conditionalExpression instanceof ConditionalPrimary) {
0 ignored issues
show
introduced by
$AST->whereClause->conditionalExpression is never a sub-type of Doctrine\ORM\Query\AST\ConditionalPrimary.
Loading history...
105 5
                $AST->whereClause->conditionalExpression = new ConditionalExpression([
106 5
                    new ConditionalTerm([
107 5
                        $AST->whereClause->conditionalExpression,
108 5
                        $conditionalPrimary,
109
                    ]),
110
                ]);
111 3
            } elseif ($AST->whereClause->conditionalExpression instanceof ConditionalExpression
0 ignored issues
show
introduced by
$AST->whereClause->conditionalExpression is always a sub-type of Doctrine\ORM\Query\AST\ConditionalExpression.
Loading history...
112 3
                || $AST->whereClause->conditionalExpression instanceof ConditionalFactor
113
            ) {
114 3
                $tmpPrimary                              = new ConditionalPrimary();
115 3
                $tmpPrimary->conditionalExpression       = $AST->whereClause->conditionalExpression;
116 3
                $AST->whereClause->conditionalExpression = new ConditionalTerm(
0 ignored issues
show
Documentation Bug introduced by
It seems like new Doctrine\ORM\Query\A..., $conditionalPrimary)) of type Doctrine\ORM\Query\AST\ConditionalTerm is incompatible with the declared type Doctrine\ORM\Query\AST\ConditionalExpression of property $conditionalExpression.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
117
                    [
118 3
                        $tmpPrimary,
119 10
                        $conditionalPrimary,
120
                    ]
121
                );
122
            }
123
        } else {
124 50
            $AST->whereClause = new WhereClause(
125 50
                new ConditionalExpression(
126 50
                    [new ConditionalTerm([$conditionalPrimary])]
127
                )
128
            );
129
        }
130 60
    }
131
}
132