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

QueryExpressionVisitor::walkCompositeExpression()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 15
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 15
ccs 7
cts 8
cp 0.875
crap 4.0312
rs 9.9332
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 RuntimeException;
14
use function count;
15
use function str_replace;
16
use function strpos;
17
18
/**
19
 * Converts Collection expressions to Query expressions.
20
 */
21
class QueryExpressionVisitor extends ExpressionVisitor
22
{
23
    /** @var string[] */
24
    private static $operatorMap = [
25
        Comparison::GT => Expr\Comparison::GT,
26
        Comparison::GTE => Expr\Comparison::GTE,
27
        Comparison::LT  => Expr\Comparison::LT,
28
        Comparison::LTE => Expr\Comparison::LTE,
29
    ];
30
31
    /** @var string[] */
32
    private $queryAliases;
33
34
    /** @var Expr */
35
    private $expr;
36
37
    /** @var mixed[] */
38
    private $parameters = [];
39
40
    /**
41
     * @param string[] $queryAliases
42
     */
43 34
    public function __construct($queryAliases)
44
    {
45 34
        $this->queryAliases = $queryAliases;
46 34
        $this->expr         = new Expr();
47 34
    }
48
49
    /**
50
     * Gets bound parameters.
51
     * Filled after {@link dispach()}.
52
     *
53
     * @return Collection|mixed[]
54
     */
55 24
    public function getParameters()
56
    {
57 24
        return new ArrayCollection($this->parameters);
58
    }
59
60
    /**
61
     * Clears parameters.
62
     */
63 1
    public function clearParameters()
64
    {
65 1
        $this->parameters = [];
66 1
    }
67
68
    /**
69
     * Converts Criteria expression to Query one based on static map.
70
     *
71
     * @param string $criteriaOperator
72
     *
73
     * @return string|null
74
     */
75 11
    private static function convertComparisonOperator($criteriaOperator)
76
    {
77 11
        return self::$operatorMap[$criteriaOperator] ?? null;
78
    }
79
80
    /**
81
     * {@inheritDoc}
82
     */
83 10
    public function walkCompositeExpression(CompositeExpression $expr)
84
    {
85 10
        $expressionList = [];
86
87 10
        foreach ($expr->getExpressionList() as $child) {
88 10
            $expressionList[] = $this->dispatch($child);
89
        }
90
91 10
        switch ($expr->getType()) {
92
            case CompositeExpression::TYPE_AND:
93 9
                return new Expr\Andx($expressionList);
94
            case CompositeExpression::TYPE_OR:
95 1
                return new Expr\Orx($expressionList);
96
            default:
97
                throw new RuntimeException('Unknown composite ' . $expr->getType());
98
        }
99
    }
100
101
    /**
102
     * {@inheritDoc}
103
     */
104 28
    public function walkComparison(Comparison $comparison)
105
    {
106 28
        if (! isset($this->queryAliases[0])) {
107
            throw new QueryException('No aliases are set before invoking walkComparison().');
108
        }
109
110 28
        $field = $this->queryAliases[0] . '.' . $comparison->getField();
111
112 28
        foreach ($this->queryAliases as $alias) {
113 28
            if (strpos($comparison->getField() . '.', $alias . '.') === 0) {
114 5
                $field = $comparison->getField();
115 5
                break;
116
            }
117
        }
118
119 28
        $parameterName  = str_replace('.', '_', $comparison->getField());
120 28
        $parameterCount = count($this->parameters);
121
122 28
        foreach ($this->parameters as $parameter) {
123 10
            if ($parameter->getName() === $parameterName) {
124 4
                $parameterName .= '_' . $parameterCount;
125 4
                break;
126
            }
127
        }
128
129 28
        $parameter   = new Parameter($parameterName, $this->walkValue($comparison->getValue()));
130 28
        $placeholder = ':' . $parameterName;
131
132 28
        switch ($comparison->getOperator()) {
133
            case Comparison::IN:
134 1
                $this->parameters[] = $parameter;
135
136 1
                return $this->expr->in($field, $placeholder);
137
            case Comparison::NIN:
138 1
                $this->parameters[] = $parameter;
139
140 1
                return $this->expr->notIn($field, $placeholder);
141
            case Comparison::EQ:
142
            case Comparison::IS:
143 17
                if ($this->walkValue($comparison->getValue()) === null) {
144 2
                    return $this->expr->isNull($field);
145
                }
146 15
                $this->parameters[] = $parameter;
147
148 15
                return $this->expr->eq($field, $placeholder);
149
            case Comparison::NEQ:
150 2
                if ($this->walkValue($comparison->getValue()) === null) {
151 1
                    return $this->expr->isNotNull($field);
152
                }
153 1
                $this->parameters[] = $parameter;
154
155 1
                return $this->expr->neq($field, $placeholder);
156
            case Comparison::CONTAINS:
157 1
                $parameter->setValue('%' . $parameter->getValue() . '%', $parameter->getType());
158 1
                $this->parameters[] = $parameter;
159
160 1
                return $this->expr->like($field, $placeholder);
161
            case Comparison::STARTS_WITH:
162 1
                $parameter->setValue($parameter->getValue() . '%', $parameter->getType());
163 1
                $this->parameters[] = $parameter;
164
165 1
                return $this->expr->like($field, $placeholder);
166
            case Comparison::ENDS_WITH:
167 1
                $parameter->setValue('%' . $parameter->getValue(), $parameter->getType());
168 1
                $this->parameters[] = $parameter;
169
170 1
                return $this->expr->like($field, $placeholder);
171
            default:
172 11
                $operator = self::convertComparisonOperator($comparison->getOperator());
173 11
                if ($operator) {
174 11
                    $this->parameters[] = $parameter;
175
176 11
                    return new Expr\Comparison(
177 11
                        $field,
178
                        $operator,
179
                        $placeholder
180
                    );
181
                }
182
183
                throw new RuntimeException('Unknown comparison operator: ' . $comparison->getOperator());
184
        }
185
    }
186
187
    /**
188
     * {@inheritDoc}
189
     */
190 29
    public function walkValue(Value $value)
191
    {
192 29
        return $value->getValue();
193
    }
194
}
195