diff options
Diffstat (limited to 'vendor/doctrine/orm/src/Query/QueryExpressionVisitor.php')
-rw-r--r-- | vendor/doctrine/orm/src/Query/QueryExpressionVisitor.php | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/vendor/doctrine/orm/src/Query/QueryExpressionVisitor.php b/vendor/doctrine/orm/src/Query/QueryExpressionVisitor.php new file mode 100644 index 0000000..3e0ec65 --- /dev/null +++ b/vendor/doctrine/orm/src/Query/QueryExpressionVisitor.php | |||
@@ -0,0 +1,180 @@ | |||
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\Expr\Comparison; | ||
9 | use Doctrine\Common\Collections\Expr\CompositeExpression; | ||
10 | use Doctrine\Common\Collections\Expr\ExpressionVisitor; | ||
11 | use Doctrine\Common\Collections\Expr\Value; | ||
12 | use RuntimeException; | ||
13 | |||
14 | use function count; | ||
15 | use function str_replace; | ||
16 | use function str_starts_with; | ||
17 | |||
18 | /** | ||
19 | * Converts Collection expressions to Query expressions. | ||
20 | */ | ||
21 | class QueryExpressionVisitor extends ExpressionVisitor | ||
22 | { | ||
23 | private const OPERATOR_MAP = [ | ||
24 | Comparison::GT => Expr\Comparison::GT, | ||
25 | Comparison::GTE => Expr\Comparison::GTE, | ||
26 | Comparison::LT => Expr\Comparison::LT, | ||
27 | Comparison::LTE => Expr\Comparison::LTE, | ||
28 | ]; | ||
29 | |||
30 | private readonly Expr $expr; | ||
31 | |||
32 | /** @var list<mixed> */ | ||
33 | private array $parameters = []; | ||
34 | |||
35 | /** @param mixed[] $queryAliases */ | ||
36 | public function __construct( | ||
37 | private readonly array $queryAliases, | ||
38 | ) { | ||
39 | $this->expr = new Expr(); | ||
40 | } | ||
41 | |||
42 | /** | ||
43 | * Gets bound parameters. | ||
44 | * Filled after {@link dispach()}. | ||
45 | * | ||
46 | * @return ArrayCollection<int, mixed> | ||
47 | */ | ||
48 | public function getParameters(): ArrayCollection | ||
49 | { | ||
50 | return new ArrayCollection($this->parameters); | ||
51 | } | ||
52 | |||
53 | public function clearParameters(): void | ||
54 | { | ||
55 | $this->parameters = []; | ||
56 | } | ||
57 | |||
58 | /** | ||
59 | * Converts Criteria expression to Query one based on static map. | ||
60 | */ | ||
61 | private static function convertComparisonOperator(string $criteriaOperator): string|null | ||
62 | { | ||
63 | return self::OPERATOR_MAP[$criteriaOperator] ?? null; | ||
64 | } | ||
65 | |||
66 | public function walkCompositeExpression(CompositeExpression $expr): mixed | ||
67 | { | ||
68 | $expressionList = []; | ||
69 | |||
70 | foreach ($expr->getExpressionList() as $child) { | ||
71 | $expressionList[] = $this->dispatch($child); | ||
72 | } | ||
73 | |||
74 | return match ($expr->getType()) { | ||
75 | CompositeExpression::TYPE_AND => new Expr\Andx($expressionList), | ||
76 | CompositeExpression::TYPE_OR => new Expr\Orx($expressionList), | ||
77 | CompositeExpression::TYPE_NOT => $this->expr->not($expressionList[0]), | ||
78 | default => throw new RuntimeException('Unknown composite ' . $expr->getType()), | ||
79 | }; | ||
80 | } | ||
81 | |||
82 | public function walkComparison(Comparison $comparison): mixed | ||
83 | { | ||
84 | if (! isset($this->queryAliases[0])) { | ||
85 | throw new QueryException('No aliases are set before invoking walkComparison().'); | ||
86 | } | ||
87 | |||
88 | $field = $this->queryAliases[0] . '.' . $comparison->getField(); | ||
89 | |||
90 | foreach ($this->queryAliases as $alias) { | ||
91 | if (str_starts_with($comparison->getField() . '.', $alias . '.')) { | ||
92 | $field = $comparison->getField(); | ||
93 | break; | ||
94 | } | ||
95 | } | ||
96 | |||
97 | $parameterName = str_replace('.', '_', $comparison->getField()); | ||
98 | |||
99 | foreach ($this->parameters as $parameter) { | ||
100 | if ($parameter->getName() === $parameterName) { | ||
101 | $parameterName .= '_' . count($this->parameters); | ||
102 | break; | ||
103 | } | ||
104 | } | ||
105 | |||
106 | $parameter = new Parameter($parameterName, $this->walkValue($comparison->getValue())); | ||
107 | $placeholder = ':' . $parameterName; | ||
108 | |||
109 | switch ($comparison->getOperator()) { | ||
110 | case Comparison::IN: | ||
111 | $this->parameters[] = $parameter; | ||
112 | |||
113 | return $this->expr->in($field, $placeholder); | ||
114 | |||
115 | case Comparison::NIN: | ||
116 | $this->parameters[] = $parameter; | ||
117 | |||
118 | return $this->expr->notIn($field, $placeholder); | ||
119 | |||
120 | case Comparison::EQ: | ||
121 | case Comparison::IS: | ||
122 | if ($this->walkValue($comparison->getValue()) === null) { | ||
123 | return $this->expr->isNull($field); | ||
124 | } | ||
125 | |||
126 | $this->parameters[] = $parameter; | ||
127 | |||
128 | return $this->expr->eq($field, $placeholder); | ||
129 | |||
130 | case Comparison::NEQ: | ||
131 | if ($this->walkValue($comparison->getValue()) === null) { | ||
132 | return $this->expr->isNotNull($field); | ||
133 | } | ||
134 | |||
135 | $this->parameters[] = $parameter; | ||
136 | |||
137 | return $this->expr->neq($field, $placeholder); | ||
138 | |||
139 | case Comparison::CONTAINS: | ||
140 | $parameter->setValue('%' . $parameter->getValue() . '%', $parameter->getType()); | ||
141 | $this->parameters[] = $parameter; | ||
142 | |||
143 | return $this->expr->like($field, $placeholder); | ||
144 | |||
145 | case Comparison::MEMBER_OF: | ||
146 | return $this->expr->isMemberOf($comparison->getField(), $comparison->getValue()->getValue()); | ||
147 | |||
148 | case Comparison::STARTS_WITH: | ||
149 | $parameter->setValue($parameter->getValue() . '%', $parameter->getType()); | ||
150 | $this->parameters[] = $parameter; | ||
151 | |||
152 | return $this->expr->like($field, $placeholder); | ||
153 | |||
154 | case Comparison::ENDS_WITH: | ||
155 | $parameter->setValue('%' . $parameter->getValue(), $parameter->getType()); | ||
156 | $this->parameters[] = $parameter; | ||
157 | |||
158 | return $this->expr->like($field, $placeholder); | ||
159 | |||
160 | default: | ||
161 | $operator = self::convertComparisonOperator($comparison->getOperator()); | ||
162 | if ($operator) { | ||
163 | $this->parameters[] = $parameter; | ||
164 | |||
165 | return new Expr\Comparison( | ||
166 | $field, | ||
167 | $operator, | ||
168 | $placeholder, | ||
169 | ); | ||
170 | } | ||
171 | |||
172 | throw new RuntimeException('Unknown comparison operator: ' . $comparison->getOperator()); | ||
173 | } | ||
174 | } | ||
175 | |||
176 | public function walkValue(Value $value): mixed | ||
177 | { | ||
178 | return $value->getValue(); | ||
179 | } | ||
180 | } | ||