Total Complexity | 54 |
Total Lines | 318 |
Duplicated Lines | 0 % |
Changes | 2 | ||
Bugs | 0 | Features | 0 |
Complex classes like CompilesColumns often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use CompilesColumns, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
12 | trait CompilesColumns |
||
13 | { |
||
14 | /** |
||
15 | * @param mixed[] $returnAttributes |
||
16 | * @param mixed[] $returnDocs |
||
17 | * @param Builder $query |
||
18 | * @return mixed[] |
||
19 | */ |
||
20 | public function processEmptyReturnValues(array $returnAttributes, array $returnDocs, Builder $query): array |
||
21 | { |
||
22 | if (empty($returnAttributes) && empty($returnDocs)) { |
||
23 | $returnDocs[] = (string) $query->getTableAlias($query->from); |
||
24 | |||
25 | if ($query->joins !== null) { |
||
26 | $returnDocs = $this->mergeJoinResults($query, $returnDocs); |
||
27 | } |
||
28 | } |
||
29 | return $returnDocs; |
||
30 | } |
||
31 | |||
32 | /** |
||
33 | * @param Builder $query |
||
34 | * @param mixed[] $returnDocs |
||
35 | * @param mixed[] $returnAttributes |
||
36 | * @return mixed[] |
||
37 | */ |
||
38 | public function processAggregateReturnValues(Builder $query, array $returnDocs, array $returnAttributes): array |
||
39 | { |
||
40 | if ($query->aggregate !== null && $query->unions === null) { |
||
41 | $returnDocs = []; |
||
42 | $returnAttributes = ['aggregate' => 'aggregateResult']; |
||
43 | } |
||
44 | return [$returnDocs, $returnAttributes]; |
||
45 | } |
||
46 | |||
47 | /** |
||
48 | * Compile the "select *" portion of the query. |
||
49 | * |
||
50 | * @param IlluminateQueryBuilder $query |
||
51 | * @param array<mixed> $columns |
||
52 | * @return string|null |
||
53 | * @throws Exception |
||
54 | */ |
||
55 | protected function compileColumns(IlluminateQueryBuilder $query, $columns) |
||
56 | { |
||
57 | assert($query instanceof Builder); |
||
58 | |||
59 | $columns = $this->convertJsonFields($columns); |
||
|
|||
60 | |||
61 | [$returnAttributes, $returnDocs] = $this->prepareColumns($query, $columns); |
||
62 | |||
63 | $returnValues = $this->determineReturnValues($query, $returnAttributes, $returnDocs); |
||
64 | |||
65 | $return = 'RETURN '; |
||
66 | if ($query->distinct) { |
||
67 | $return .= 'DISTINCT '; |
||
68 | } |
||
69 | |||
70 | return $return . $returnValues; |
||
71 | } |
||
72 | |||
73 | /** |
||
74 | * @param IlluminateQueryBuilder $query |
||
75 | * @param array<mixed> $columns |
||
76 | * @return array<mixed> |
||
77 | * @throws Exception |
||
78 | * |
||
79 | * @SuppressWarnings("PHPMD.CyclomaticComplexity") |
||
80 | */ |
||
81 | protected function prepareColumns(IlluminateQueryBuilder $query, array $columns) |
||
82 | { |
||
83 | assert($query instanceof Builder); |
||
84 | |||
85 | $returnDocs = []; |
||
86 | $returnAttributes = []; |
||
87 | |||
88 | foreach ($columns as $key => $column) { |
||
89 | // Extract complete documents |
||
90 | if (is_string($column) && substr($column, strlen($column) - 2) === '.*') { |
||
91 | $table = substr($column, 0, strlen($column) - 2); |
||
92 | $returnDocs[] = $query->getTableAlias($table); |
||
93 | |||
94 | continue; |
||
95 | } |
||
96 | |||
97 | // Extract groups |
||
98 | if (is_array($query->groups) && in_array($column, $query->groups)) { |
||
99 | $returnAttributes[$column] = $this->normalizeColumn($query, $column); |
||
100 | |||
101 | continue; |
||
102 | } |
||
103 | |||
104 | if (is_string($column) && $column != null && $column != '*') { |
||
105 | [$column, $alias] = $this->normalizeStringColumn($query, $key, $column); |
||
106 | |||
107 | if (isset($returnAttributes[$alias]) && is_array($column)) { |
||
108 | $returnAttributes[$alias] = array_merge_recursive( |
||
109 | $returnAttributes[$alias], |
||
110 | $this->normalizeColumn($query, $column), |
||
111 | ); |
||
112 | continue; |
||
113 | } |
||
114 | $returnAttributes[$alias] = $column; |
||
115 | } |
||
116 | } |
||
117 | |||
118 | return [ |
||
119 | $returnAttributes, |
||
120 | $returnDocs, |
||
121 | ]; |
||
122 | } |
||
123 | |||
124 | /** |
||
125 | * @throws Exception |
||
126 | */ |
||
127 | protected function normalizeColumn(IlluminateQueryBuilder $query, mixed $column, ?string $table = null): mixed |
||
163 | } |
||
164 | |||
165 | /** |
||
166 | * @param Builder $query |
||
167 | * @param int|string $key |
||
168 | * @param string $column |
||
169 | * @param string|null $table |
||
170 | * @return array<mixed> |
||
171 | * @throws Exception |
||
172 | */ |
||
173 | protected function normalizeStringColumn(Builder $query, int|string $key, string $column, ?string $table = null): array |
||
174 | { |
||
175 | [$column, $alias] = $query->extractAlias($column, $key); |
||
176 | |||
177 | $column = $query->convertIdToKey($column); |
||
178 | |||
179 | $column = $this->wrap($this->normalizeColumnReferences($query, $column, $table)); |
||
180 | |||
181 | /** @phpstan-ignore-next-line */ |
||
182 | $alias = $this->cleanAlias($query, $alias); |
||
183 | |||
184 | return [$column, $alias]; |
||
185 | } |
||
186 | |||
187 | |||
188 | /** |
||
189 | * @param IlluminateQueryBuilder $query |
||
190 | * @param string $column |
||
191 | * @param string|null $table |
||
192 | * @return string |
||
193 | */ |
||
194 | protected function normalizeColumnReferences(IlluminateQueryBuilder $query, string $column, ?string $table = null): string |
||
195 | { |
||
196 | assert($query instanceof Builder); |
||
197 | |||
198 | if ($query->isReference($column)) { |
||
199 | return $column; |
||
200 | } |
||
201 | |||
202 | if ($table == null) { |
||
203 | $table = (string) $this->getValue($query->from); |
||
204 | } |
||
205 | |||
206 | $references = explode('.', $column); |
||
207 | |||
208 | $tableAlias = $query->getTableAlias($references[0]); |
||
209 | |||
210 | if (isset($tableAlias)) { |
||
211 | $references[0] = $tableAlias; |
||
212 | } |
||
213 | |||
214 | if (array_key_exists('groupsVariable', $query->tableAliases)) { |
||
215 | $tableAlias = 'groupsVariable'; |
||
216 | array_unshift($references, $tableAlias); |
||
217 | } |
||
218 | |||
219 | // geen tableAlias, table is parent...waarom geen tableAlias? |
||
220 | if ($tableAlias === null && array_key_exists($table, $query->tableAliases)) { |
||
221 | array_unshift($references, $query->tableAliases[$table]); |
||
222 | } |
||
223 | |||
224 | if ($tableAlias === null && !$query->isReference($references[0])) { |
||
225 | $tableAlias = $query->generateTableAlias($table); |
||
226 | array_unshift($references, $tableAlias); |
||
227 | } |
||
228 | |||
229 | /** @phpstan-ignore-next-line */ |
||
230 | return implode('.', $references); |
||
231 | } |
||
232 | |||
233 | protected function cleanAlias(IlluminateQueryBuilder $query, int|null|string $alias): int|string|null |
||
234 | { |
||
235 | assert($query instanceof Builder); |
||
236 | |||
237 | if (!is_string($alias)) { |
||
238 | return $alias; |
||
239 | } |
||
240 | |||
241 | if (!str_contains($alias, '.')) { |
||
242 | return $alias; |
||
243 | } |
||
244 | |||
245 | $elements = explode('.', $alias); |
||
246 | |||
247 | if ( |
||
248 | !$query->isTable($elements[0]) |
||
249 | && !$query->isVariable($elements[0]) |
||
250 | ) { |
||
251 | return $alias; |
||
252 | } |
||
253 | |||
254 | array_shift($elements); |
||
255 | |||
256 | return implode($elements); |
||
257 | } |
||
258 | |||
259 | |||
260 | /** |
||
261 | * @param IlluminateQueryBuilder $query |
||
262 | * @param array<string> $returnAttributes |
||
263 | * @param array<string> $returnDocs |
||
264 | * @return string |
||
265 | */ |
||
266 | protected function determineReturnValues(IlluminateQueryBuilder $query, $returnAttributes = [], $returnDocs = []): string |
||
267 | { |
||
268 | assert($query instanceof Builder); |
||
269 | |||
270 | // If nothing was specifically requested, we return everything. |
||
271 | $returnDocs = $this->processEmptyReturnValues($returnAttributes, $returnDocs, $query); |
||
272 | |||
273 | // Aggregate functions only return the aggregate, so we can clear out everything else. |
||
274 | list($returnDocs, $returnAttributes) = $this->processAggregateReturnValues($query, $returnDocs, $returnAttributes); |
||
275 | |||
276 | // Return a single value for certain subqueries |
||
277 | if ( |
||
278 | $query->returnSingleValue === true |
||
279 | && count($returnAttributes) === 1 |
||
280 | && empty($returnDocs) |
||
281 | ) { |
||
282 | return reset($returnAttributes); |
||
283 | } |
||
284 | |||
285 | if (!empty($returnAttributes)) { |
||
286 | $returnDocs[] = $this->generateAqlObject($returnAttributes); |
||
287 | } |
||
288 | |||
289 | $values = $this->mergeReturnDocs($returnDocs); |
||
290 | |||
291 | return $values; |
||
292 | } |
||
293 | |||
294 | /** |
||
295 | * @param array<string> $returnDocs |
||
296 | * @return string |
||
297 | */ |
||
298 | protected function mergeReturnDocs($returnDocs) |
||
305 | } |
||
306 | |||
307 | /** |
||
308 | * @param IlluminateQueryBuilder $query |
||
309 | * @param array<string> $returnDocs |
||
310 | * @return array<string> |
||
311 | */ |
||
312 | protected function mergeJoinResults(IlluminateQueryBuilder $query, $returnDocs = []): array |
||
330 | } |
||
331 | } |
||
332 |