Total Complexity | 42 |
Total Lines | 358 |
Duplicated Lines | 0 % |
Changes | 1 | ||
Bugs | 0 | Features | 0 |
Complex classes like Oracle 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 Oracle, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
58 | class Oracle extends Driver |
||
59 | { |
||
60 | /** |
||
61 | * @inheritDoc |
||
62 | */ |
||
63 | protected array $modifiers = [ |
||
64 | 'nullable', |
||
65 | 'default', |
||
66 | 'autoincrement', |
||
67 | 'description' |
||
68 | ]; |
||
69 | |||
70 | /** |
||
71 | * @inheritDoc |
||
72 | */ |
||
73 | protected string $autoincrement = 'GENERATED BY DEFAULT ON NULL AS IDENTITY'; |
||
74 | |||
75 | /** |
||
76 | * @inheritDoc |
||
77 | */ |
||
78 | public function select(QueryStatement $select): string |
||
79 | { |
||
80 | $limit = $select->getLimit(); |
||
81 | if ($limit <= 0) { |
||
82 | return parent::select($select); |
||
83 | } |
||
84 | |||
85 | $sql = $select->hasDistinct() ? 'SELECT DISTINCT ' : 'SELECT '; |
||
86 | $sql .= $this->getColumnList($select->getColumns()); |
||
87 | $sql .= ' FROM '; |
||
88 | $sql .= $this->getTableList($select->getTables()); |
||
89 | $sql .= $this->getJoins($select->getJoins()); |
||
90 | $sql .= $this->getWheres($select->getWheres()); |
||
91 | $sql .= $this->getGroupBy($select->getGroupBy()); |
||
92 | $sql .= $this->getHaving($select->getHaving()); |
||
93 | $sql .= $this->getOrders($select->getOrder()); |
||
94 | |||
95 | $offset = $select->getOffset(); |
||
96 | if ($offset < 0) { |
||
97 | return sprintf( |
||
98 | 'SELECT * FROM (%s) A1 WHERE ROWNUM <= %s', |
||
99 | $sql, |
||
100 | $limit |
||
101 | ); |
||
102 | } |
||
103 | $limit += $offset; |
||
104 | $offset++; |
||
105 | return sprintf( |
||
106 | 'SELECT * FROM (SELECT A1.*, ROWNUM AS P_ROWNUM FROM (%s) A1 ' |
||
107 | . 'WHERE ROWNUM <= %d) WHERE P_ROWNUM >= %d', |
||
108 | $sql, |
||
109 | $limit, |
||
110 | $offset |
||
111 | ); |
||
112 | } |
||
113 | |||
114 | /** |
||
115 | * @inheritDoc |
||
116 | */ |
||
117 | public function getDatabaseName(): array |
||
118 | { |
||
119 | return [ |
||
120 | 'sql' => 'SELECT user FROM dual', |
||
121 | 'params' => [] |
||
122 | ]; |
||
123 | } |
||
124 | |||
125 | /** |
||
126 | * @inheritDoc |
||
127 | */ |
||
128 | public function getTables(string $database): array |
||
141 | ]; |
||
142 | } |
||
143 | |||
144 | /** |
||
145 | * @inheritDoc |
||
146 | */ |
||
147 | public function getViews(string $database): array |
||
148 | { |
||
149 | $sql = sprintf( |
||
150 | 'SELECT %s FROM %s WHERE owner = ? ' |
||
151 | . ' ORDER BY %s ASC', |
||
152 | $this->quoteIdentifier('view_name'), |
||
153 | $this->quoteIdentifier('all_views'), |
||
154 | $this->quoteIdentifier('view_name'), |
||
155 | ); |
||
156 | |||
157 | return [ |
||
158 | 'sql' => $sql, |
||
159 | 'params' => [$database] |
||
160 | ]; |
||
161 | } |
||
162 | |||
163 | /** |
||
164 | * @inheritDoc |
||
165 | */ |
||
166 | public function getColumns(string $database, string $table): array |
||
167 | { |
||
168 | $sql = sprintf( |
||
169 | 'SELECT %s AS %s, %s AS %s FROM %s WHERE LOWER(%s) = ? ' |
||
170 | . 'AND LOWER(%s) = ? ORDER BY %s ASC', |
||
171 | $this->quoteIdentifier('column_name'), |
||
172 | $this->quoteIdentifier('name'), |
||
173 | $this->quoteIdentifier('data_type'), |
||
174 | $this->quoteIdentifier('type'), |
||
175 | $this->quoteIdentifier('all_tab_columns'), |
||
176 | $this->quoteIdentifier('owner'), |
||
177 | $this->quoteIdentifier('table_name'), |
||
178 | $this->quoteIdentifier('column_id'), |
||
179 | ); |
||
180 | |||
181 | return [ |
||
182 | 'sql' => $sql, |
||
183 | 'params' => [$database, $table] |
||
184 | ]; |
||
185 | } |
||
186 | |||
187 | /** |
||
188 | * @inheritDoc |
||
189 | */ |
||
190 | public function getViewColumns(string $database, string $view): array |
||
191 | { |
||
192 | $sql = sprintf( |
||
193 | 'SELECT %s AS %s, %s AS %s FROM %s WHERE LOWER(%s) = ? ' |
||
194 | . 'AND LOWER(%s) = ? ORDER BY %s ASC', |
||
195 | $this->quoteIdentifier('column_name'), |
||
196 | $this->quoteIdentifier('name'), |
||
197 | $this->quoteIdentifier('data_type'), |
||
198 | $this->quoteIdentifier('type'), |
||
199 | $this->quoteIdentifier('all_tab_columns'), |
||
200 | $this->quoteIdentifier('owner'), |
||
201 | $this->quoteIdentifier('table_name'), |
||
202 | $this->quoteIdentifier('column_id'), |
||
203 | ); |
||
204 | |||
205 | return [ |
||
206 | 'sql' => $sql, |
||
207 | 'params' => [$database, $view] |
||
208 | ]; |
||
209 | } |
||
210 | |||
211 | /** |
||
212 | * @inheritDoc |
||
213 | */ |
||
214 | protected function quoteIdentifier(string|Expression $value): string |
||
215 | { |
||
216 | if ($value instanceof Expression) { |
||
217 | return $this->getExpressions($value->getExpressions()); |
||
218 | } |
||
219 | |||
220 | $identifiers = []; |
||
221 | |||
222 | foreach (explode('.', $value) as $segment) { |
||
223 | if ($segment === '*') { |
||
224 | $identifiers[] = $segment; |
||
225 | } else { |
||
226 | $identifiers[] = sprintf($this->identifier, strtoupper($segment)); |
||
227 | } |
||
228 | } |
||
229 | |||
230 | return implode('.', $identifiers); |
||
231 | } |
||
232 | |||
233 | /** |
||
234 | * @inheritdoc |
||
235 | */ |
||
236 | protected function getTypeInteger(BaseColumn $column): string |
||
237 | { |
||
238 | $type = 'NUMBER(10)'; |
||
239 | switch ($column->get('size', 'normal')) { |
||
240 | case 'tiny': |
||
241 | $type = 'NUMBER(3)'; |
||
242 | break; |
||
243 | case 'small': |
||
244 | $type = 'NUMBER(5)'; |
||
245 | break; |
||
246 | case 'medium': |
||
247 | $type = 'NUMBER(7)'; |
||
248 | break; |
||
249 | case 'big': |
||
250 | $type = 'NUMBER(19)'; |
||
251 | break; |
||
252 | } |
||
253 | return $type; |
||
254 | } |
||
255 | |||
256 | /** |
||
257 | * @inheritdoc |
||
258 | */ |
||
259 | protected function getTypeDouble(BaseColumn $column): string |
||
260 | { |
||
261 | return 'FLOAT(24)'; |
||
262 | } |
||
263 | |||
264 | /** |
||
265 | * @inheritdoc |
||
266 | */ |
||
267 | protected function getTypeDecimal(BaseColumn $column): string |
||
268 | { |
||
269 | $type = 'NUMBER(10)'; |
||
270 | $length = $column->get('length'); |
||
271 | $precision = $column->get('precision'); |
||
272 | if ($length !== null) { |
||
273 | if ($precision === null) { |
||
274 | $type = 'NUMBER(' . $this->value($length) . ')'; |
||
275 | } else { |
||
276 | $type = 'NUMBER(' . $this->value($length) . ', ' |
||
277 | . $this->value($precision) . ')'; |
||
278 | } |
||
279 | } |
||
280 | |||
281 | return $type; |
||
282 | } |
||
283 | |||
284 | /** |
||
285 | * @inheritdoc |
||
286 | */ |
||
287 | protected function getTypeEnum(BaseColumn $column): string |
||
288 | { |
||
289 | $type = 'ENUM'; |
||
290 | $values = $column->get('values'); |
||
291 | |||
292 | if (!empty($values)) { |
||
293 | $values = array_map([$this, 'value'], $values); |
||
294 | $type = 'ENUM(' . implode(',', $values) . ')'; |
||
295 | } |
||
296 | |||
297 | return $type; |
||
298 | } |
||
299 | |||
300 | /** |
||
301 | * @inheritdoc |
||
302 | */ |
||
303 | protected function getTypeBoolean(BaseColumn $column): string |
||
304 | { |
||
305 | return 'NUMBER(1)'; |
||
306 | } |
||
307 | |||
308 | /** |
||
309 | * @inheritdoc |
||
310 | */ |
||
311 | protected function getTypeText(BaseColumn $column): string |
||
312 | { |
||
313 | $type = 'CLOB'; |
||
314 | switch ($column->get('size', 'normal')) { |
||
315 | case 'tiny': |
||
316 | case 'small': |
||
317 | $type = 'VARCHAR2(2000)'; |
||
318 | break; |
||
319 | case 'medium': |
||
320 | case 'big': |
||
321 | $type = 'CLOB'; |
||
322 | break; |
||
323 | } |
||
324 | return $type; |
||
325 | } |
||
326 | |||
327 | /** |
||
328 | * @inheritdoc |
||
329 | */ |
||
330 | protected function getTypeString(BaseColumn $column): string |
||
331 | { |
||
332 | return 'VARCHAR2(' . $this->value($column->get('length', 255)) . ')'; |
||
333 | } |
||
334 | |||
335 | /** |
||
336 | * @inheritdoc |
||
337 | */ |
||
338 | protected function getTypeTime(BaseColumn $column): string |
||
339 | { |
||
340 | return 'DATE'; |
||
341 | } |
||
342 | |||
343 | /** |
||
344 | * @inheritdoc |
||
345 | */ |
||
346 | protected function getTypeDatetime(BaseColumn $column): string |
||
347 | { |
||
348 | return 'DATE'; |
||
349 | } |
||
350 | |||
351 | /** |
||
352 | * @inheritdoc |
||
353 | */ |
||
354 | protected function getTypeBinary(BaseColumn $column): string |
||
355 | { |
||
356 | $type = 'BLOB'; |
||
357 | switch ($column->get('size', 'normal')) { |
||
358 | case 'tiny': |
||
359 | case 'small': |
||
360 | $type = 'RAW(2000)'; |
||
361 | break; |
||
362 | case 'medium': |
||
363 | case 'big': |
||
364 | $type = 'BLOB'; |
||
365 | break; |
||
366 | } |
||
367 | return $type; |
||
368 | } |
||
369 | |||
370 | /** |
||
371 | * @inheritdoc |
||
372 | */ |
||
373 | protected function getModifyColumn(AlterTable $schema, mixed $data): string |
||
374 | { |
||
375 | return sprintf( |
||
376 | 'ALTER TABLE %s MODIFY %s', |
||
377 | $this->quoteIdentifier($schema->getTableName()), |
||
378 | $this->getSchemaColumns([$data]) |
||
379 | ); |
||
380 | } |
||
381 | |||
382 | /** |
||
383 | * @inheritdoc |
||
384 | */ |
||
385 | protected function getAddColumn(AlterTable $schema, mixed $data): string |
||
386 | { |
||
387 | return sprintf( |
||
388 | 'ALTER TABLE %s ADD %s', |
||
389 | $this->quoteIdentifier($schema->getTableName()), |
||
390 | $this->getSchemaColumns([$data]) |
||
391 | ); |
||
392 | } |
||
393 | |||
394 | /** |
||
395 | * @inheritdoc |
||
396 | */ |
||
397 | protected function getSetDefaultValue(AlterTable $schema, mixed $data): string |
||
398 | { |
||
399 | return sprintf( |
||
400 | 'ALTER TABLE %s MODIFY %s DEFAULT %s', |
||
401 | $this->quoteIdentifier($schema->getTableName()), |
||
402 | $this->quoteIdentifier($data['column']), |
||
403 | $this->value($data['value']) |
||
404 | ); |
||
405 | } |
||
406 | |||
407 | /** |
||
408 | * @inheritdoc |
||
409 | */ |
||
410 | protected function getDropDefaultValue(AlterTable $schema, mixed $data): string |
||
416 | ); |
||
417 | } |
||
418 | } |
||
419 |