Completed
Push — master ( f4ef0a...d00cab )
by Marco
16s
created

QueryExpressionVisitor::walkCompositeExpression()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4.0312

Importance

Changes 0
Metric Value
cc 4
eloc 10
nc 6
nop 1
dl 0
loc 17
ccs 7
cts 8
cp 0.875
crap 4.0312
rs 9.2
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ORM\Query;
6
7
use Doctrine\Common\Collections\ArrayCollection;
8
use Doctrine\Common\Collections\Collection;
9
use Doctrine\Common\Collections\Expr\Comparison;
10
use Doctrine\Common\Collections\Expr\CompositeExpression;
11
use Doctrine\Common\Collections\Expr\ExpressionVisitor;
12
use Doctrine\Common\Collections\Expr\Value;
13
use function count;
14
use function str_replace;
15
use function strpos;
16
17
/**
18
 * Converts Collection expressions to Query expressions.
19
 */
20
class QueryExpressionVisitor extends ExpressionVisitor
21
{
22
    /**
23
     * @var string[]
24
     */
25
    private static $operatorMap = [
26
        Comparison::GT => Expr\Comparison::GT,
27
        Comparison::GTE => Expr\Comparison::GTE,
28
        Comparison::LT  => Expr\Comparison::LT,
29
        Comparison::LTE => Expr\Comparison::LTE,
30
    ];
31
32
    /**
33
     * @var string[]
34
     */
35
    private $queryAliases;
36
37
    /**
38
     * @var Expr
39
     */
40
    private $expr;
41
42
    /**
43
     * @var mixed[]
44
     */
45
    private $parameters = [];
46
47
    /**
48
     * @param string[] $queryAliases
49
     */
50 34
    public function __construct($queryAliases)
51
    {
52 34
        $this->queryAliases = $queryAliases;
53 34
        $this->expr         = new Expr();
54 34
    }
55
56
    /**
57
     * Gets bound parameters.
58
     * Filled after {@link dispach()}.
59
     *
60
     * @return Collection|mixed[]
61
     */
62 24
    public function getParameters()
63
    {
64 24
        return new ArrayCollection($this->parameters);
65
    }
66
67
    /**
68
     * Clears parameters.
69
     */
70 1
    public function clearParameters()
71
    {
72 1
        $this->parameters = [];
73 1
    }
74
75
    /**
76
     * Converts Criteria expression to Query one based on static map.
77
     *
78
     * @param string $criteriaOperator
79
     *
80
     * @return string|null
81
     */
82 11
    private static function convertComparisonOperator($criteriaOperator)
83
    {
84 11
        return self::$operatorMap[$criteriaOperator] ?? null;
85
    }
86
87
    /**
88
     * {@inheritDoc}
89
     */
90 10
    public function walkCompositeExpression(CompositeExpression $expr)
91
    {
92 10
        $expressionList = [];
93
94 10
        foreach ($expr->getExpressionList() as $child) {
95 10
            $expressionList[] = $this->dispatch($child);
96
        }
97
98 10
        switch ($expr->getType()) {
99
            case CompositeExpression::TYPE_AND:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
100 9
                return new Expr\Andx($expressionList);
101
102
            case CompositeExpression::TYPE_OR:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
103 1
                return new Expr\Orx($expressionList);
104
105
            default:
106
                throw new \RuntimeException('Unknown composite ' . $expr->getType());
107
        }
108
    }
109
110
    /**
111
     * {@inheritDoc}
112
     */
113 28
    public function walkComparison(Comparison $comparison)
114
    {
115 28
        if (! isset($this->queryAliases[0])) {
116
            throw new QueryException('No aliases are set before invoking walkComparison().');
117
        }
118
119 28
        $field = $this->queryAliases[0] . '.' . $comparison->getField();
120
121 28
        foreach ($this->queryAliases as $alias) {
122 28
            if (strpos($comparison->getField() . '.', $alias . '.') === 0) {
123 5
                $field = $comparison->getField();
124 28
                break;
125
            }
126
        }
127
128 28
        $parameterName  = str_replace('.', '_', $comparison->getField());
129 28
        $parameterCount = count($this->parameters);
130
131 28
        foreach ($this->parameters as $parameter) {
132 10
            if ($parameter->getName() === $parameterName) {
133 4
                $parameterName .= '_' . $parameterCount;
134 10
                break;
135
            }
136
        }
137
138 28
        $parameter   = new Parameter($parameterName, $this->walkValue($comparison->getValue()));
139 28
        $placeholder = ':' . $parameterName;
140
141 28
        switch ($comparison->getOperator()) {
142
            case Comparison::IN:
143 1
                $this->parameters[] = $parameter;
144
145 1
                return $this->expr->in($field, $placeholder);
146
            case Comparison::NIN:
147 1
                $this->parameters[] = $parameter;
148
149 1
                return $this->expr->notIn($field, $placeholder);
150
            case Comparison::EQ:
151
            case Comparison::IS:
152 17
                if ($this->walkValue($comparison->getValue()) === null) {
153 2
                    return $this->expr->isNull($field);
154
                }
155 15
                $this->parameters[] = $parameter;
156
157 15
                return $this->expr->eq($field, $placeholder);
158
            case Comparison::NEQ:
159 2
                if ($this->walkValue($comparison->getValue()) === null) {
160 1
                    return $this->expr->isNotNull($field);
161
                }
162 1
                $this->parameters[] = $parameter;
163
164 1
                return $this->expr->neq($field, $placeholder);
165
            case Comparison::CONTAINS:
166 1
                $parameter->setValue('%' . $parameter->getValue() . '%', $parameter->getType());
167 1
                $this->parameters[] = $parameter;
168
169 1
                return $this->expr->like($field, $placeholder);
170
            case Comparison::STARTS_WITH:
171 1
                $parameter->setValue($parameter->getValue() . '%', $parameter->getType());
172 1
                $this->parameters[] = $parameter;
173
174 1
                return $this->expr->like($field, $placeholder);
175
            case Comparison::ENDS_WITH:
176 1
                $parameter->setValue('%' . $parameter->getValue(), $parameter->getType());
177 1
                $this->parameters[] = $parameter;
178
179 1
                return $this->expr->like($field, $placeholder);
180
            default:
181 11
                $operator = self::convertComparisonOperator($comparison->getOperator());
182 11
                if ($operator) {
183 11
                    $this->parameters[] = $parameter;
184
185 11
                    return new Expr\Comparison(
186 11
                        $field,
187 11
                        $operator,
188 11
                        $placeholder
189
                    );
190
                }
191
192
                throw new \RuntimeException('Unknown comparison operator: ' . $comparison->getOperator());
193
        }
194
    }
195
196
    /**
197
     * {@inheritDoc}
198
     */
199 29
    public function walkValue(Value $value)
200
    {
201 29
        return $value->getValue();
202
    }
203
}
204