Passed
Pull Request — 2.6 (#7821)
by Marco
08:12
created

WhereInWalker::walkSelectStatement()   B

Complexity

Conditions 9
Paths 21

Size

Total Lines 80
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 47
CRAP Score 9.0174

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 9
eloc 50
c 1
b 0
f 0
nc 21
nop 1
dl 0
loc 80
ccs 47
cts 50
cp 0.94
crap 9.0174
rs 7.5353

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ORM\Tools\Pagination;
21
22
use Doctrine\ORM\Mapping\ClassMetadata;
23
use Doctrine\ORM\Query\AST\ArithmeticExpression;
24
use Doctrine\ORM\Query\AST\ConditionalExpression;
25
use Doctrine\ORM\Query\AST\ConditionalFactor;
26
use Doctrine\ORM\Query\AST\ConditionalPrimary;
27
use Doctrine\ORM\Query\AST\ConditionalTerm;
28
use Doctrine\ORM\Query\AST\InExpression;
29
use Doctrine\ORM\Query\AST\InputParameter;
30
use Doctrine\ORM\Query\AST\NullComparisonExpression;
31
use Doctrine\ORM\Query\AST\PathExpression;
32
use Doctrine\ORM\Query\AST\SelectStatement;
33
use Doctrine\ORM\Query\AST\SimpleArithmeticExpression;
34
use Doctrine\ORM\Query\AST\WhereClause;
35
use Doctrine\ORM\Query\TreeWalkerAdapter;
36
use Doctrine\ORM\Utility\PersisterHelper;
37
use function array_map;
38
use function assert;
39
use function is_array;
40
41
/**
42
 * Replaces the whereClause of the AST with a WHERE id IN (:foo_1, :foo_2) equivalent.
43
 *
44
 * @category    DoctrineExtensions
45
 * @package     DoctrineExtensions\Paginate
46
 * @author      David Abdemoulaie <[email protected]>
47
 * @copyright   Copyright (c) 2010 David Abdemoulaie (http://hobodave.com/)
48
 * @license     http://hobodave.com/license.txt New BSD License
49
 */
50
class WhereInWalker extends TreeWalkerAdapter
51
{
52
    /**
53
     * ID Count hint name.
54
     */
55
    const HINT_PAGINATOR_ID_COUNT = 'doctrine.id.count';
56
57
    /**
58
     * Primary key alias for query.
59
     */
60
    const PAGINATOR_ID_ALIAS = 'dpid';
61
62
    /**
63
     * Replaces the whereClause in the AST.
64
     *
65
     * Generates a clause equivalent to WHERE IN (:dpid_1, :dpid_2, ...)
66
     *
67
     * The parameter namespace (dpid) is defined by
68
     * the PAGINATOR_ID_ALIAS
69
     *
70
     * The total number of parameters is retrieved from
71
     * the HINT_PAGINATOR_ID_COUNT query hint.
72
     *
73
     * @param SelectStatement $AST
74
     *
75
     * @return void
76
     *
77
     * @throws \RuntimeException
78
     */
79 63
    public function walkSelectStatement(SelectStatement $AST)
80
    {
81 63
        $queryComponents = $this->_getQueryComponents();
82
        // Get the root entity and alias from the AST fromClause
83 63
        $from = $AST->fromClause->identificationVariableDeclarations;
84
85 63
        if (count($from) > 1) {
86
            throw new \RuntimeException("Cannot count query which selects two FROM components, cannot make distinction");
87
        }
88
89 63
        $fromRoot            = reset($from);
90 63
        $rootAlias           = $fromRoot->rangeVariableDeclaration->aliasIdentificationVariable;
91
        /** @var ClassMetadata $rootClass */
92 63
        $rootClass           = $queryComponents[$rootAlias]['metadata'];
93 63
        $identifierFieldName = $rootClass->getSingleIdentifierFieldName();
94
95 63
        $pathType = PathExpression::TYPE_STATE_FIELD;
96 63
        if (isset($rootClass->associationMappings[$identifierFieldName])) {
97 2
            $pathType = PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION;
98
        }
99
100 63
        $pathExpression       = new PathExpression(PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, $rootAlias, $identifierFieldName);
101 63
        $pathExpression->type = $pathType;
102
103 63
        $count = $this->_getQuery()->getHint(self::HINT_PAGINATOR_ID_COUNT);
104
105 63
        if ($count > 0) {
106 63
            $arithmeticExpression = new ArithmeticExpression();
107 63
            $arithmeticExpression->simpleArithmeticExpression = new SimpleArithmeticExpression(
108 63
                [$pathExpression]
109
            );
110 63
            $expression = new InExpression($arithmeticExpression);
111 63
            $expression->literals[] = new InputParameter(":" . self::PAGINATOR_ID_ALIAS);
112
113 63
            $this->convertWhereInIdentifiersToDatabaseValue(
114 63
                PersisterHelper::getTypeOfField(
115 63
                    $identifierFieldName,
116 63
                    $rootClass,
117 63
                    $this->_getQuery()
118 63
                        ->getEntityManager()
119 63
                )[0]
120
            );
121
        } else {
122
            $expression = new NullComparisonExpression($pathExpression);
123
            $expression->not = false;
124
        }
125
126 63
        $conditionalPrimary = new ConditionalPrimary;
127 63
        $conditionalPrimary->simpleConditionalExpression = $expression;
128 63
        if ($AST->whereClause) {
129 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...
130 2
                $AST->whereClause->conditionalExpression->conditionalFactors[] = $conditionalPrimary;
131 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...
132 5
                $AST->whereClause->conditionalExpression = new ConditionalExpression(
133
                    [
134 5
                        new ConditionalTerm(
135
                            [
136 5
                                $AST->whereClause->conditionalExpression,
137 5
                                $conditionalPrimary
138
                            ]
139
                        )
140
                    ]
141
                );
142 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...
143 3
                || $AST->whereClause->conditionalExpression instanceof ConditionalFactor
144
            ) {
145 3
                $tmpPrimary = new ConditionalPrimary;
146 3
                $tmpPrimary->conditionalExpression = $AST->whereClause->conditionalExpression;
147 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...
148
                    [
149 3
                        $tmpPrimary,
150 10
                        $conditionalPrimary
151
                    ]
152
                );
153
            }
154
        } else {
155 53
            $AST->whereClause = new WhereClause(
156 53
                new ConditionalExpression(
157
                    [
158 53
                        new ConditionalTerm([$conditionalPrimary])
159
                    ]
160
                )
161
            );
162
        }
163 63
    }
164
165 63
    private function convertWhereInIdentifiersToDatabaseValue(string $type) : void
166
    {
167 63
        $query                = $this->_getQuery();
168 63
        $identifiersParameter = $query->getParameter(self::PAGINATOR_ID_ALIAS);
169
170 63
        assert($identifiersParameter !== null);
171
172 63
        $identifiers = $identifiersParameter->getValue();
173
174 63
        assert(is_array($identifiers));
175
176 63
        $connection = $this->_getQuery()
177 63
            ->getEntityManager()
178 63
            ->getConnection();
179
180
        $query->setParameter(self::PAGINATOR_ID_ALIAS, array_map(static function ($id) use ($connection, $type) {
181 63
            return $connection->convertToDatabaseValue($id, $type);
182 63
        }, $identifiers));
183 63
    }
184
}
185