Total Complexity | 175 |
Total Lines | 1101 |
Duplicated Lines | 22.62 % |
Coverage | 84.74% |
Changes | 0 |
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like MySqlPlatform 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 MySqlPlatform, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
40 | class MySqlPlatform extends AbstractPlatform |
||
41 | { |
||
42 | const LENGTH_LIMIT_TINYTEXT = 255; |
||
43 | const LENGTH_LIMIT_TEXT = 65535; |
||
44 | const LENGTH_LIMIT_MEDIUMTEXT = 16777215; |
||
45 | |||
46 | const LENGTH_LIMIT_TINYBLOB = 255; |
||
47 | const LENGTH_LIMIT_BLOB = 65535; |
||
48 | const LENGTH_LIMIT_MEDIUMBLOB = 16777215; |
||
49 | |||
50 | /** |
||
51 | * Adds MySQL-specific LIMIT clause to the query |
||
52 | * 18446744073709551615 is 2^64-1 maximum of unsigned BIGINT the biggest limit possible |
||
53 | * |
||
54 | * @param string $query |
||
55 | * @param integer $limit |
||
56 | * @param integer $offset |
||
57 | * |
||
58 | * @return string |
||
59 | */ |
||
60 | 9 | protected function doModifyLimitQuery($query, $limit, $offset) |
|
61 | { |
||
62 | 9 | if ($limit !== null) { |
|
63 | 6 | $query .= ' LIMIT ' . $limit; |
|
64 | 6 | if ($offset !== null) { |
|
65 | 6 | $query .= ' OFFSET ' . $offset; |
|
66 | } |
||
67 | 3 | } elseif ($offset !== null) { |
|
68 | 3 | $query .= ' LIMIT 18446744073709551615 OFFSET ' . $offset; |
|
69 | } |
||
70 | |||
71 | 9 | return $query; |
|
72 | } |
||
73 | |||
74 | /** |
||
75 | * {@inheritDoc} |
||
76 | */ |
||
77 | 82 | public function getIdentifierQuoteCharacter() |
|
78 | { |
||
79 | 82 | return '`'; |
|
80 | } |
||
81 | |||
82 | /** |
||
83 | * {@inheritDoc} |
||
84 | */ |
||
85 | 3 | public function getRegexpExpression() |
|
86 | { |
||
87 | 3 | return 'RLIKE'; |
|
88 | } |
||
89 | |||
90 | /** |
||
91 | * {@inheritDoc} |
||
92 | */ |
||
93 | public function getGuidExpression() |
||
94 | { |
||
95 | return 'UUID()'; |
||
96 | } |
||
97 | |||
98 | /** |
||
99 | * {@inheritDoc} |
||
100 | */ |
||
101 | View Code Duplication | public function getLocateExpression($str, $substr, $startPos = false) |
|
108 | } |
||
109 | |||
110 | /** |
||
111 | * {@inheritDoc} |
||
112 | */ |
||
113 | 3 | public function getConcatExpression() |
|
114 | { |
||
115 | 3 | $args = func_get_args(); |
|
116 | |||
117 | 3 | return 'CONCAT(' . join(', ', (array) $args) . ')'; |
|
118 | } |
||
119 | |||
120 | /** |
||
121 | * {@inheritdoc} |
||
122 | */ |
||
123 | protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) |
||
124 | { |
||
125 | $function = '+' === $operator ? 'DATE_ADD' : 'DATE_SUB'; |
||
126 | |||
127 | return $function . '(' . $date . ', INTERVAL ' . $interval . ' ' . $unit . ')'; |
||
128 | } |
||
129 | |||
130 | /** |
||
131 | * {@inheritDoc} |
||
132 | */ |
||
133 | public function getDateDiffExpression($date1, $date2) |
||
134 | { |
||
135 | return 'DATEDIFF(' . $date1 . ', ' . $date2 . ')'; |
||
136 | } |
||
137 | |||
138 | /** |
||
139 | * {@inheritDoc} |
||
140 | */ |
||
141 | 3 | public function getListDatabasesSQL() |
|
142 | { |
||
143 | 3 | return 'SHOW DATABASES'; |
|
144 | } |
||
145 | |||
146 | /** |
||
147 | * {@inheritDoc} |
||
148 | */ |
||
149 | public function getListTableConstraintsSQL($table) |
||
150 | { |
||
151 | return 'SHOW INDEX FROM ' . $table; |
||
152 | } |
||
153 | |||
154 | /** |
||
155 | * {@inheritDoc} |
||
156 | * |
||
157 | * Two approaches to listing the table indexes. The information_schema is |
||
158 | * preferred, because it doesn't cause problems with SQL keywords such as "order" or "table". |
||
159 | */ |
||
160 | 6 | View Code Duplication | public function getListTableIndexesSQL($table, $currentDatabase = null) |
161 | { |
||
162 | 6 | if ($currentDatabase) { |
|
163 | 6 | $currentDatabase = $this->quoteStringLiteral($currentDatabase); |
|
164 | 6 | $table = $this->quoteStringLiteral($table); |
|
165 | |||
166 | return "SELECT TABLE_NAME AS `Table`, NON_UNIQUE AS Non_Unique, INDEX_NAME AS Key_name, ". |
||
167 | "SEQ_IN_INDEX AS Seq_in_index, COLUMN_NAME AS Column_Name, COLLATION AS Collation, ". |
||
168 | "CARDINALITY AS Cardinality, SUB_PART AS Sub_Part, PACKED AS Packed, " . |
||
169 | "NULLABLE AS `Null`, INDEX_TYPE AS Index_Type, COMMENT AS Comment " . |
||
170 | 6 | "FROM information_schema.STATISTICS WHERE TABLE_NAME = " . $table . " AND TABLE_SCHEMA = " . $currentDatabase; |
|
171 | } |
||
172 | |||
173 | return 'SHOW INDEX FROM ' . $table; |
||
174 | } |
||
175 | |||
176 | /** |
||
177 | * {@inheritDoc} |
||
178 | */ |
||
179 | 3 | public function getListViewsSQL($database) |
|
180 | { |
||
181 | 3 | $database = $this->quoteStringLiteral($database); |
|
182 | |||
183 | 3 | return "SELECT * FROM information_schema.VIEWS WHERE TABLE_SCHEMA = " . $database; |
|
184 | } |
||
185 | |||
186 | /** |
||
187 | * {@inheritDoc} |
||
188 | */ |
||
189 | 9 | public function getListTableForeignKeysSQL($table, $database = null) |
|
190 | { |
||
191 | 9 | $table = $this->quoteStringLiteral($table); |
|
192 | |||
193 | 9 | if (null !== $database) { |
|
194 | 6 | $database = $this->quoteStringLiteral($database); |
|
195 | } |
||
196 | |||
197 | $sql = "SELECT DISTINCT k.`CONSTRAINT_NAME`, k.`COLUMN_NAME`, k.`REFERENCED_TABLE_NAME`, ". |
||
198 | "k.`REFERENCED_COLUMN_NAME` /*!50116 , c.update_rule, c.delete_rule */ ". |
||
199 | "FROM information_schema.key_column_usage k /*!50116 ". |
||
200 | "INNER JOIN information_schema.referential_constraints c ON ". |
||
201 | " c.constraint_name = k.constraint_name AND ". |
||
202 | 9 | " c.table_name = $table */ WHERE k.table_name = $table"; |
|
203 | |||
204 | 9 | $databaseNameSql = null === $database ? 'DATABASE()' : $database; |
|
205 | |||
206 | 9 | $sql .= " AND k.table_schema = $databaseNameSql /*!50116 AND c.constraint_schema = $databaseNameSql */"; |
|
207 | 9 | $sql .= " AND k.`REFERENCED_COLUMN_NAME` is not NULL"; |
|
208 | |||
209 | 9 | return $sql; |
|
210 | } |
||
211 | |||
212 | /** |
||
213 | * {@inheritDoc} |
||
214 | */ |
||
215 | public function getCreateViewSQL($name, $sql) |
||
216 | { |
||
217 | return 'CREATE VIEW ' . $name . ' AS ' . $sql; |
||
218 | } |
||
219 | |||
220 | /** |
||
221 | * {@inheritDoc} |
||
222 | */ |
||
223 | public function getDropViewSQL($name) |
||
224 | { |
||
225 | return 'DROP VIEW '. $name; |
||
226 | } |
||
227 | |||
228 | /** |
||
229 | * {@inheritDoc} |
||
230 | */ |
||
231 | 45 | protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) |
|
232 | { |
||
233 | 45 | return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)') |
|
234 | 45 | : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)'); |
|
235 | } |
||
236 | |||
237 | /** |
||
238 | * {@inheritdoc} |
||
239 | */ |
||
240 | 3 | protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) |
|
241 | { |
||
242 | 3 | return $fixed ? 'BINARY(' . ($length ?: 255) . ')' : 'VARBINARY(' . ($length ?: 255) . ')'; |
|
243 | } |
||
244 | |||
245 | /** |
||
246 | * Gets the SQL snippet used to declare a CLOB column type. |
||
247 | * TINYTEXT : 2 ^ 8 - 1 = 255 |
||
248 | * TEXT : 2 ^ 16 - 1 = 65535 |
||
249 | * MEDIUMTEXT : 2 ^ 24 - 1 = 16777215 |
||
250 | * LONGTEXT : 2 ^ 32 - 1 = 4294967295 |
||
251 | * |
||
252 | * @param array $field |
||
253 | * |
||
254 | * @return string |
||
255 | */ |
||
256 | 15 | View Code Duplication | public function getClobTypeDeclarationSQL(array $field) |
257 | { |
||
258 | 15 | if ( ! empty($field['length']) && is_numeric($field['length'])) { |
|
259 | 4 | $length = $field['length']; |
|
260 | |||
261 | 4 | if ($length <= static::LENGTH_LIMIT_TINYTEXT) { |
|
262 | 3 | return 'TINYTEXT'; |
|
263 | } |
||
264 | |||
265 | 4 | if ($length <= static::LENGTH_LIMIT_TEXT) { |
|
266 | 4 | return 'TEXT'; |
|
267 | } |
||
268 | |||
269 | 3 | if ($length <= static::LENGTH_LIMIT_MEDIUMTEXT) { |
|
270 | 3 | return 'MEDIUMTEXT'; |
|
271 | } |
||
272 | } |
||
273 | |||
274 | 14 | return 'LONGTEXT'; |
|
275 | } |
||
276 | |||
277 | /** |
||
278 | * {@inheritDoc} |
||
279 | */ |
||
280 | 3 | View Code Duplication | public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) |
281 | { |
||
282 | 3 | if (isset($fieldDeclaration['version']) && $fieldDeclaration['version'] == true) { |
|
283 | 3 | return 'TIMESTAMP'; |
|
284 | } |
||
285 | |||
286 | 3 | return 'DATETIME'; |
|
287 | } |
||
288 | |||
289 | /** |
||
290 | * {@inheritDoc} |
||
291 | */ |
||
292 | public function getDateTypeDeclarationSQL(array $fieldDeclaration) |
||
293 | { |
||
294 | return 'DATE'; |
||
295 | } |
||
296 | |||
297 | /** |
||
298 | * {@inheritDoc} |
||
299 | */ |
||
300 | public function getTimeTypeDeclarationSQL(array $fieldDeclaration) |
||
303 | } |
||
304 | |||
305 | /** |
||
306 | * {@inheritDoc} |
||
307 | */ |
||
308 | 3 | public function getBooleanTypeDeclarationSQL(array $field) |
|
309 | { |
||
310 | 3 | return 'TINYINT(1)'; |
|
311 | } |
||
312 | |||
313 | /** |
||
314 | * Obtain DBMS specific SQL code portion needed to set the COLLATION |
||
315 | * of a field declaration to be used in statements like CREATE TABLE. |
||
316 | * |
||
317 | * @deprecated Deprecated since version 2.5, Use {@link self::getColumnCollationDeclarationSQL()} instead. |
||
318 | * |
||
319 | * @param string $collation name of the collation |
||
320 | * |
||
321 | * @return string DBMS specific SQL code portion needed to set the COLLATION |
||
322 | * of a field declaration. |
||
323 | */ |
||
324 | public function getCollationFieldDeclaration($collation) |
||
325 | { |
||
326 | return $this->getColumnCollationDeclarationSQL($collation); |
||
327 | } |
||
328 | |||
329 | /** |
||
330 | * {@inheritDoc} |
||
331 | * |
||
332 | * MySql prefers "autoincrement" identity columns since sequences can only |
||
333 | * be emulated with a table. |
||
334 | */ |
||
335 | 3 | public function prefersIdentityColumns() |
|
336 | { |
||
337 | 3 | return true; |
|
338 | } |
||
339 | |||
340 | /** |
||
341 | * {@inheritDoc} |
||
342 | * |
||
343 | * MySql supports this through AUTO_INCREMENT columns. |
||
344 | */ |
||
345 | 3 | public function supportsIdentityColumns() |
|
346 | { |
||
347 | 3 | return true; |
|
348 | } |
||
349 | |||
350 | /** |
||
351 | * {@inheritDoc} |
||
352 | */ |
||
353 | 97 | public function supportsInlineColumnComments() |
|
354 | { |
||
355 | 97 | return true; |
|
356 | } |
||
357 | |||
358 | /** |
||
359 | * {@inheritDoc} |
||
360 | */ |
||
361 | public function supportsColumnCollation() |
||
362 | { |
||
363 | return true; |
||
364 | } |
||
365 | |||
366 | /** |
||
367 | * {@inheritDoc} |
||
368 | */ |
||
369 | public function getListTablesSQL() |
||
370 | { |
||
371 | return "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'"; |
||
372 | } |
||
373 | |||
374 | /** |
||
375 | * {@inheritDoc} |
||
376 | */ |
||
377 | 6 | View Code Duplication | public function getListTableColumnsSQL($table, $database = null) |
378 | { |
||
379 | 6 | $table = $this->quoteStringLiteral($table); |
|
380 | |||
381 | 6 | if ($database) { |
|
382 | 3 | $database = $this->quoteStringLiteral($database); |
|
383 | } else { |
||
384 | 3 | $database = 'DATABASE()'; |
|
385 | } |
||
386 | |||
387 | return "SELECT COLUMN_NAME AS Field, COLUMN_TYPE AS Type, IS_NULLABLE AS `Null`, ". |
||
388 | "COLUMN_KEY AS `Key`, COLUMN_DEFAULT AS `Default`, EXTRA AS Extra, COLUMN_COMMENT AS Comment, " . |
||
389 | "CHARACTER_SET_NAME AS CharacterSet, COLLATION_NAME AS Collation ". |
||
390 | 6 | "FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = " . $database . " AND TABLE_NAME = " . $table; |
|
391 | } |
||
392 | |||
393 | /** |
||
394 | * {@inheritDoc} |
||
395 | */ |
||
396 | 3 | public function getCreateDatabaseSQL($name) |
|
397 | { |
||
398 | 3 | return 'CREATE DATABASE ' . $name; |
|
399 | } |
||
400 | |||
401 | /** |
||
402 | * {@inheritDoc} |
||
403 | */ |
||
404 | 3 | public function getDropDatabaseSQL($name) |
|
405 | { |
||
406 | 3 | return 'DROP DATABASE ' . $name; |
|
407 | } |
||
408 | |||
409 | /** |
||
410 | * {@inheritDoc} |
||
411 | */ |
||
412 | 43 | protected function _getCreateTableSQL($tableName, array $columns, array $options = []) |
|
413 | { |
||
414 | 43 | $queryFields = $this->getColumnDeclarationListSQL($columns); |
|
415 | |||
416 | 43 | if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) { |
|
417 | foreach ($options['uniqueConstraints'] as $index => $definition) { |
||
418 | $queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($index, $definition); |
||
419 | } |
||
420 | } |
||
421 | |||
422 | // add all indexes |
||
423 | 43 | if (isset($options['indexes']) && ! empty($options['indexes'])) { |
|
424 | 20 | foreach ($options['indexes'] as $index => $definition) { |
|
425 | 20 | $queryFields .= ', ' . $this->getIndexDeclarationSQL($index, $definition); |
|
426 | } |
||
427 | } |
||
428 | |||
429 | // attach all primary keys |
||
430 | 43 | View Code Duplication | if (isset($options['primary']) && ! empty($options['primary'])) { |
431 | 15 | $keyColumns = array_unique(array_values($options['primary'])); |
|
432 | 15 | $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')'; |
|
433 | } |
||
434 | |||
435 | 43 | $query = 'CREATE '; |
|
436 | |||
437 | 43 | if (!empty($options['temporary'])) { |
|
438 | $query .= 'TEMPORARY '; |
||
439 | } |
||
440 | |||
441 | 43 | $query .= 'TABLE ' . $tableName . ' (' . $queryFields . ') '; |
|
442 | 43 | $query .= $this->buildTableOptions($options); |
|
443 | 43 | $query .= $this->buildPartitionOptions($options); |
|
444 | |||
445 | 43 | $sql[] = $query; |
|
446 | 43 | $engine = 'INNODB'; |
|
447 | |||
448 | 43 | if (isset($options['engine'])) { |
|
449 | 9 | $engine = strtoupper(trim($options['engine'])); |
|
450 | } |
||
451 | |||
452 | // Propagate foreign key constraints only for InnoDB. |
||
453 | 43 | View Code Duplication | if (isset($options['foreignKeys']) && $engine === 'INNODB') { |
454 | 6 | foreach ((array) $options['foreignKeys'] as $definition) { |
|
455 | 6 | $sql[] = $this->getCreateForeignKeySQL($definition, $tableName); |
|
456 | } |
||
457 | } |
||
458 | |||
459 | 43 | return $sql; |
|
460 | } |
||
461 | |||
462 | /** |
||
463 | * {@inheritdoc} |
||
464 | */ |
||
465 | 100 | public function getDefaultValueDeclarationSQL($field) |
|
473 | } |
||
474 | |||
475 | /** |
||
476 | * Build SQL for table options |
||
477 | * |
||
478 | * @param array $options |
||
479 | * |
||
480 | * @return string |
||
481 | */ |
||
482 | 43 | private function buildTableOptions(array $options) |
|
483 | { |
||
484 | 43 | if (isset($options['table_options'])) { |
|
485 | return $options['table_options']; |
||
486 | } |
||
487 | |||
488 | 43 | $tableOptions = []; |
|
489 | |||
490 | // Charset |
||
491 | 43 | if ( ! isset($options['charset'])) { |
|
492 | 43 | $options['charset'] = 'utf8'; |
|
493 | } |
||
494 | |||
495 | 43 | $tableOptions[] = sprintf('DEFAULT CHARACTER SET %s', $options['charset']); |
|
496 | |||
497 | // Collate |
||
498 | 43 | if ( ! isset($options['collate'])) { |
|
499 | 43 | $options['collate'] = 'utf8_unicode_ci'; |
|
500 | } |
||
501 | |||
502 | 43 | $tableOptions[] = sprintf('COLLATE %s', $options['collate']); |
|
503 | |||
504 | // Engine |
||
505 | 43 | if ( ! isset($options['engine'])) { |
|
506 | 34 | $options['engine'] = 'InnoDB'; |
|
507 | } |
||
508 | |||
509 | 43 | $tableOptions[] = sprintf('ENGINE = %s', $options['engine']); |
|
510 | |||
511 | // Auto increment |
||
512 | 43 | if (isset($options['auto_increment'])) { |
|
513 | $tableOptions[] = sprintf('AUTO_INCREMENT = %s', $options['auto_increment']); |
||
514 | } |
||
515 | |||
516 | // Comment |
||
517 | 43 | View Code Duplication | if (isset($options['comment'])) { |
518 | $comment = trim($options['comment'], " '"); |
||
519 | |||
520 | $tableOptions[] = sprintf("COMMENT = %s ", $this->quoteStringLiteral($comment)); |
||
521 | } |
||
522 | |||
523 | // Row format |
||
524 | 43 | if (isset($options['row_format'])) { |
|
525 | $tableOptions[] = sprintf('ROW_FORMAT = %s', $options['row_format']); |
||
526 | } |
||
527 | |||
528 | 43 | return implode(' ', $tableOptions); |
|
529 | } |
||
530 | |||
531 | /** |
||
532 | * Build SQL for partition options. |
||
533 | * |
||
534 | * @param array $options |
||
535 | * |
||
536 | * @return string |
||
537 | */ |
||
538 | 43 | private function buildPartitionOptions(array $options) |
|
539 | { |
||
540 | 43 | return (isset($options['partition_options'])) |
|
541 | ? ' ' . $options['partition_options'] |
||
542 | 43 | : ''; |
|
543 | } |
||
544 | |||
545 | /** |
||
546 | * {@inheritDoc} |
||
547 | */ |
||
548 | 79 | public function getAlterTableSQL(TableDiff $diff) |
|
549 | { |
||
550 | 79 | $columnSql = []; |
|
551 | 79 | $queryParts = []; |
|
552 | 79 | if ($diff->newName !== false) { |
|
553 | 6 | $queryParts[] = 'RENAME TO ' . $diff->getNewName()->getQuotedName($this); |
|
554 | } |
||
555 | |||
556 | 79 | View Code Duplication | foreach ($diff->addedColumns as $column) { |
557 | 18 | if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { |
|
558 | continue; |
||
559 | } |
||
560 | |||
561 | 18 | $columnArray = $column->toArray(); |
|
562 | 18 | $columnArray['comment'] = $this->getColumnComment($column); |
|
563 | 18 | $queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); |
|
564 | } |
||
565 | |||
566 | 79 | View Code Duplication | foreach ($diff->removedColumns as $column) { |
567 | 9 | if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { |
|
568 | continue; |
||
569 | } |
||
570 | |||
571 | 9 | $queryParts[] = 'DROP ' . $column->getQuotedName($this); |
|
572 | } |
||
573 | |||
574 | 79 | View Code Duplication | foreach ($diff->changedColumns as $columnDiff) { |
575 | 23 | if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { |
|
576 | continue; |
||
577 | } |
||
578 | |||
579 | /* @var $columnDiff \Doctrine\DBAL\Schema\ColumnDiff */ |
||
580 | 23 | $column = $columnDiff->column; |
|
581 | 23 | $columnArray = $column->toArray(); |
|
582 | |||
583 | // Don't propagate default value changes for unsupported column types. |
||
584 | 23 | if ($columnDiff->hasChanged('default') && |
|
585 | 23 | count($columnDiff->changedProperties) === 1 && |
|
586 | 23 | ($columnArray['type'] instanceof TextType || $columnArray['type'] instanceof BlobType) |
|
587 | ) { |
||
588 | 2 | continue; |
|
589 | } |
||
590 | |||
591 | 21 | $columnArray['comment'] = $this->getColumnComment($column); |
|
592 | 21 | $queryParts[] = 'CHANGE ' . ($columnDiff->getOldColumnName()->getQuotedName($this)) . ' ' |
|
593 | 21 | . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); |
|
594 | } |
||
595 | |||
596 | 79 | View Code Duplication | foreach ($diff->renamedColumns as $oldColumnName => $column) { |
597 | 12 | if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { |
|
598 | continue; |
||
599 | } |
||
600 | |||
601 | 12 | $oldColumnName = new Identifier($oldColumnName); |
|
602 | 12 | $columnArray = $column->toArray(); |
|
603 | 12 | $columnArray['comment'] = $this->getColumnComment($column); |
|
604 | 12 | $queryParts[] = 'CHANGE ' . $oldColumnName->getQuotedName($this) . ' ' |
|
605 | 12 | . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); |
|
606 | } |
||
607 | |||
608 | 79 | if (isset($diff->addedIndexes['primary'])) { |
|
609 | 10 | $keyColumns = array_unique(array_values($diff->addedIndexes['primary']->getColumns())); |
|
610 | 10 | $queryParts[] = 'ADD PRIMARY KEY (' . implode(', ', $keyColumns) . ')'; |
|
611 | 10 | unset($diff->addedIndexes['primary']); |
|
612 | } |
||
613 | |||
614 | 79 | $sql = []; |
|
615 | 79 | $tableSql = []; |
|
616 | |||
617 | 79 | View Code Duplication | if ( ! $this->onSchemaAlterTable($diff, $tableSql)) { |
618 | 79 | if (count($queryParts) > 0) { |
|
619 | 40 | $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . implode(", ", $queryParts); |
|
620 | } |
||
621 | 79 | $sql = array_merge( |
|
622 | 79 | $this->getPreAlterTableIndexForeignKeySQL($diff), |
|
623 | 79 | $sql, |
|
624 | 79 | $this->getPostAlterTableIndexForeignKeySQL($diff) |
|
625 | ); |
||
626 | } |
||
627 | |||
628 | 79 | return array_merge($sql, $tableSql, $columnSql); |
|
629 | } |
||
630 | |||
631 | /** |
||
632 | * {@inheritDoc} |
||
633 | */ |
||
634 | 79 | protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) |
|
635 | { |
||
636 | 79 | $sql = []; |
|
637 | 79 | $table = $diff->getName($this)->getQuotedName($this); |
|
638 | |||
639 | 79 | foreach ($diff->changedIndexes as $changedIndex) { |
|
640 | 16 | $sql = array_merge($sql, $this->getPreAlterTableAlterPrimaryKeySQL($diff, $changedIndex)); |
|
641 | } |
||
642 | |||
643 | 79 | foreach ($diff->removedIndexes as $remKey => $remIndex) { |
|
644 | 9 | $sql = array_merge($sql, $this->getPreAlterTableAlterPrimaryKeySQL($diff, $remIndex)); |
|
645 | |||
646 | 9 | foreach ($diff->addedIndexes as $addKey => $addIndex) { |
|
647 | 3 | if ($remIndex->getColumns() == $addIndex->getColumns()) { |
|
648 | |||
649 | 3 | $indexClause = 'INDEX ' . $addIndex->getName(); |
|
650 | |||
651 | 3 | if ($addIndex->isPrimary()) { |
|
652 | $indexClause = 'PRIMARY KEY'; |
||
653 | 3 | } elseif ($addIndex->isUnique()) { |
|
654 | 3 | $indexClause = 'UNIQUE INDEX ' . $addIndex->getName(); |
|
655 | } |
||
656 | |||
657 | 3 | $query = 'ALTER TABLE ' . $table . ' DROP INDEX ' . $remIndex->getName() . ', '; |
|
658 | 3 | $query .= 'ADD ' . $indexClause; |
|
659 | 3 | $query .= ' (' . $this->getIndexFieldDeclarationListSQL($addIndex->getQuotedColumns($this)) . ')'; |
|
660 | |||
661 | 3 | $sql[] = $query; |
|
662 | |||
663 | 3 | unset($diff->removedIndexes[$remKey]); |
|
664 | 3 | unset($diff->addedIndexes[$addKey]); |
|
665 | |||
666 | 9 | break; |
|
667 | } |
||
668 | } |
||
669 | } |
||
670 | |||
671 | 79 | $engine = 'INNODB'; |
|
672 | |||
673 | 79 | if ($diff->fromTable instanceof Table && $diff->fromTable->hasOption('engine')) { |
|
674 | 3 | $engine = strtoupper(trim($diff->fromTable->getOption('engine'))); |
|
675 | } |
||
676 | |||
677 | // Suppress foreign key constraint propagation on non-supporting engines. |
||
678 | 79 | if ('INNODB' !== $engine) { |
|
679 | 3 | $diff->addedForeignKeys = []; |
|
680 | 3 | $diff->changedForeignKeys = []; |
|
681 | 3 | $diff->removedForeignKeys = []; |
|
682 | } |
||
683 | |||
684 | 79 | $sql = array_merge( |
|
685 | 79 | $sql, |
|
686 | 79 | $this->getPreAlterTableAlterIndexForeignKeySQL($diff), |
|
687 | 79 | parent::getPreAlterTableIndexForeignKeySQL($diff), |
|
688 | 79 | $this->getPreAlterTableRenameIndexForeignKeySQL($diff) |
|
689 | ); |
||
690 | |||
691 | 79 | return $sql; |
|
692 | } |
||
693 | |||
694 | /** |
||
695 | * @param TableDiff $diff |
||
696 | * @param Index $index |
||
697 | * |
||
698 | * @return string[] |
||
699 | */ |
||
700 | 25 | private function getPreAlterTableAlterPrimaryKeySQL(TableDiff $diff, Index $index) |
|
701 | { |
||
702 | 25 | $sql = []; |
|
703 | |||
704 | 25 | if (! $index->isPrimary() || ! $diff->fromTable instanceof Table) { |
|
705 | 9 | return $sql; |
|
706 | } |
||
707 | |||
708 | 16 | $tableName = $diff->getName($this)->getQuotedName($this); |
|
709 | |||
710 | // Dropping primary keys requires to unset autoincrement attribute on the particular column first. |
||
711 | 16 | View Code Duplication | foreach ($index->getColumns() as $columnName) { |
712 | 16 | if (! $diff->fromTable->hasColumn($columnName)) { |
|
713 | 3 | continue; |
|
714 | } |
||
715 | |||
716 | 16 | $column = $diff->fromTable->getColumn($columnName); |
|
717 | |||
718 | 16 | if ($column->getAutoincrement() === true) { |
|
719 | 9 | $column->setAutoincrement(false); |
|
720 | |||
721 | 9 | $sql[] = 'ALTER TABLE ' . $tableName . ' MODIFY ' . |
|
722 | 9 | $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); |
|
723 | |||
724 | // original autoincrement information might be needed later on by other parts of the table alteration |
||
725 | 16 | $column->setAutoincrement(true); |
|
726 | } |
||
727 | } |
||
728 | |||
729 | 16 | return $sql; |
|
730 | } |
||
731 | |||
732 | /** |
||
733 | * @param TableDiff $diff The table diff to gather the SQL for. |
||
734 | * |
||
735 | * @return array |
||
736 | */ |
||
737 | 79 | private function getPreAlterTableAlterIndexForeignKeySQL(TableDiff $diff) |
|
738 | { |
||
739 | 79 | $sql = []; |
|
740 | 79 | $table = $diff->getName($this)->getQuotedName($this); |
|
741 | |||
742 | 79 | foreach ($diff->changedIndexes as $changedIndex) { |
|
743 | // Changed primary key |
||
744 | 16 | if ($changedIndex->isPrimary() && $diff->fromTable instanceof Table) { |
|
745 | 13 | View Code Duplication | foreach ($diff->fromTable->getPrimaryKeyColumns() as $columnName) { |
746 | 13 | $column = $diff->fromTable->getColumn($columnName); |
|
747 | |||
748 | // Check if an autoincrement column was dropped from the primary key. |
||
749 | 13 | if ($column->getAutoincrement() && ! in_array($columnName, $changedIndex->getColumns())) { |
|
750 | // The autoincrement attribute needs to be removed from the dropped column |
||
751 | // before we can drop and recreate the primary key. |
||
752 | 3 | $column->setAutoincrement(false); |
|
753 | |||
754 | 3 | $sql[] = 'ALTER TABLE ' . $table . ' MODIFY ' . |
|
755 | 3 | $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); |
|
756 | |||
757 | // Restore the autoincrement attribute as it might be needed later on |
||
758 | // by other parts of the table alteration. |
||
759 | 16 | $column->setAutoincrement(true); |
|
760 | } |
||
761 | } |
||
762 | } |
||
763 | } |
||
764 | |||
765 | 79 | return $sql; |
|
766 | } |
||
767 | |||
768 | /** |
||
769 | * @param TableDiff $diff The table diff to gather the SQL for. |
||
770 | * |
||
771 | * @return array |
||
772 | */ |
||
773 | 53 | protected function getPreAlterTableRenameIndexForeignKeySQL(TableDiff $diff) |
|
774 | { |
||
775 | 53 | $sql = []; |
|
776 | 53 | $tableName = $diff->getName($this)->getQuotedName($this); |
|
777 | |||
778 | 53 | View Code Duplication | foreach ($this->getRemainingForeignKeyConstraintsRequiringRenamedIndexes($diff) as $foreignKey) { |
779 | 2 | if (! in_array($foreignKey, $diff->changedForeignKeys, true)) { |
|
780 | 2 | $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName); |
|
781 | } |
||
782 | } |
||
783 | |||
784 | 53 | return $sql; |
|
785 | } |
||
786 | |||
787 | /** |
||
788 | * Returns the remaining foreign key constraints that require one of the renamed indexes. |
||
789 | * |
||
790 | * "Remaining" here refers to the diff between the foreign keys currently defined in the associated |
||
791 | * table and the foreign keys to be removed. |
||
792 | * |
||
793 | * @param TableDiff $diff The table diff to evaluate. |
||
794 | * |
||
795 | * @return array |
||
796 | */ |
||
797 | 53 | private function getRemainingForeignKeyConstraintsRequiringRenamedIndexes(TableDiff $diff) |
|
798 | { |
||
799 | 53 | if (empty($diff->renamedIndexes) || ! $diff->fromTable instanceof Table) { |
|
800 | 43 | return []; |
|
801 | } |
||
802 | |||
803 | 10 | $foreignKeys = []; |
|
804 | /** @var \Doctrine\DBAL\Schema\ForeignKeyConstraint[] $remainingForeignKeys */ |
||
805 | 10 | $remainingForeignKeys = array_diff_key( |
|
806 | 10 | $diff->fromTable->getForeignKeys(), |
|
807 | 10 | $diff->removedForeignKeys |
|
808 | ); |
||
809 | |||
810 | 10 | foreach ($remainingForeignKeys as $foreignKey) { |
|
811 | 2 | foreach ($diff->renamedIndexes as $index) { |
|
812 | 2 | if ($foreignKey->intersectsIndexColumns($index)) { |
|
813 | 2 | $foreignKeys[] = $foreignKey; |
|
814 | |||
815 | 2 | break; |
|
816 | } |
||
817 | } |
||
818 | } |
||
819 | |||
820 | 10 | return $foreignKeys; |
|
821 | } |
||
822 | |||
823 | /** |
||
824 | * {@inheritdoc} |
||
825 | */ |
||
826 | 79 | protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff) |
|
827 | { |
||
828 | 79 | return array_merge( |
|
829 | 79 | parent::getPostAlterTableIndexForeignKeySQL($diff), |
|
830 | 79 | $this->getPostAlterTableRenameIndexForeignKeySQL($diff) |
|
831 | ); |
||
832 | } |
||
833 | |||
834 | /** |
||
835 | * @param TableDiff $diff The table diff to gather the SQL for. |
||
836 | * |
||
837 | * @return array |
||
838 | */ |
||
839 | 53 | protected function getPostAlterTableRenameIndexForeignKeySQL(TableDiff $diff) |
|
840 | { |
||
841 | 53 | $sql = []; |
|
842 | 53 | $tableName = (false !== $diff->newName) |
|
843 | 4 | ? $diff->getNewName()->getQuotedName($this) |
|
844 | 53 | : $diff->getName($this)->getQuotedName($this); |
|
845 | |||
846 | 53 | View Code Duplication | foreach ($this->getRemainingForeignKeyConstraintsRequiringRenamedIndexes($diff) as $foreignKey) { |
847 | 2 | if (! in_array($foreignKey, $diff->changedForeignKeys, true)) { |
|
848 | 2 | $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName); |
|
849 | } |
||
850 | } |
||
851 | |||
852 | 53 | return $sql; |
|
853 | } |
||
854 | |||
855 | /** |
||
856 | * {@inheritDoc} |
||
857 | */ |
||
858 | 45 | View Code Duplication | protected function getCreateIndexSQLFlags(Index $index) |
859 | { |
||
860 | 45 | $type = ''; |
|
861 | 45 | if ($index->isUnique()) { |
|
862 | 9 | $type .= 'UNIQUE '; |
|
863 | 36 | } elseif ($index->hasFlag('fulltext')) { |
|
864 | 3 | $type .= 'FULLTEXT '; |
|
865 | 33 | } elseif ($index->hasFlag('spatial')) { |
|
866 | 3 | $type .= 'SPATIAL '; |
|
867 | } |
||
868 | |||
869 | 45 | return $type; |
|
870 | } |
||
871 | |||
872 | /** |
||
873 | * {@inheritDoc} |
||
874 | */ |
||
875 | 56 | public function getIntegerTypeDeclarationSQL(array $field) |
|
876 | { |
||
877 | 56 | return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($field); |
|
878 | } |
||
879 | |||
880 | /** |
||
881 | * {@inheritDoc} |
||
882 | */ |
||
883 | public function getBigIntTypeDeclarationSQL(array $field) |
||
884 | { |
||
885 | return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); |
||
886 | } |
||
887 | |||
888 | /** |
||
889 | * {@inheritDoc} |
||
890 | */ |
||
891 | public function getSmallIntTypeDeclarationSQL(array $field) |
||
894 | } |
||
895 | |||
896 | /** |
||
897 | * {@inheritdoc} |
||
898 | */ |
||
899 | 18 | public function getFloatDeclarationSQL(array $field) |
|
900 | { |
||
901 | 18 | return 'DOUBLE PRECISION' . $this->getUnsignedDeclaration($field); |
|
902 | } |
||
903 | |||
904 | /** |
||
905 | * {@inheritdoc} |
||
906 | */ |
||
907 | 18 | public function getDecimalTypeDeclarationSQL(array $columnDef) |
|
908 | { |
||
909 | 18 | return parent::getDecimalTypeDeclarationSQL($columnDef) . $this->getUnsignedDeclaration($columnDef); |
|
910 | } |
||
911 | |||
912 | /** |
||
913 | * Get unsigned declaration for a column. |
||
914 | * |
||
915 | * @param array $columnDef |
||
916 | * |
||
917 | * @return string |
||
918 | */ |
||
919 | 92 | private function getUnsignedDeclaration(array $columnDef) |
|
920 | { |
||
921 | 92 | return ! empty($columnDef['unsigned']) ? ' UNSIGNED' : ''; |
|
922 | } |
||
923 | |||
924 | /** |
||
925 | * {@inheritDoc} |
||
926 | */ |
||
927 | 56 | protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) |
|
928 | { |
||
929 | 56 | $autoinc = ''; |
|
930 | 56 | if ( ! empty($columnDef['autoincrement'])) { |
|
931 | 9 | $autoinc = ' AUTO_INCREMENT'; |
|
932 | } |
||
933 | |||
934 | 56 | return $this->getUnsignedDeclaration($columnDef) . $autoinc; |
|
935 | } |
||
936 | |||
937 | /** |
||
938 | * {@inheritDoc} |
||
939 | */ |
||
940 | 21 | public function getAdvancedForeignKeyOptionsSQL(\Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey) |
|
941 | { |
||
942 | 21 | $query = ''; |
|
943 | 21 | if ($foreignKey->hasOption('match')) { |
|
944 | $query .= ' MATCH ' . $foreignKey->getOption('match'); |
||
945 | } |
||
946 | 21 | $query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey); |
|
947 | |||
948 | 21 | return $query; |
|
949 | } |
||
950 | |||
951 | /** |
||
952 | * {@inheritDoc} |
||
953 | */ |
||
954 | 32 | View Code Duplication | public function getDropIndexSQL($index, $table=null) |
955 | { |
||
956 | 32 | if ($index instanceof Index) { |
|
957 | 22 | $indexName = $index->getQuotedName($this); |
|
958 | 10 | } elseif (is_string($index)) { |
|
959 | 10 | $indexName = $index; |
|
960 | } else { |
||
961 | throw new \InvalidArgumentException('MysqlPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.'); |
||
962 | } |
||
963 | |||
964 | 32 | if ($table instanceof Table) { |
|
965 | $table = $table->getQuotedName($this); |
||
966 | 32 | } elseif (!is_string($table)) { |
|
967 | throw new \InvalidArgumentException('MysqlPlatform::getDropIndexSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.'); |
||
968 | } |
||
969 | |||
970 | 32 | if ($index instanceof Index && $index->isPrimary()) { |
|
971 | // mysql primary keys are always named "PRIMARY", |
||
972 | // so we cannot use them in statements because of them being keyword. |
||
973 | 19 | return $this->getDropPrimaryKeySQL($table); |
|
974 | } |
||
975 | |||
976 | 13 | return 'DROP INDEX ' . $indexName . ' ON ' . $table; |
|
977 | } |
||
978 | |||
979 | /** |
||
980 | * @param string $table |
||
981 | * |
||
982 | * @return string |
||
983 | */ |
||
984 | 19 | protected function getDropPrimaryKeySQL($table) |
|
985 | { |
||
986 | 19 | return 'ALTER TABLE ' . $table . ' DROP PRIMARY KEY'; |
|
987 | } |
||
988 | |||
989 | /** |
||
990 | * {@inheritDoc} |
||
991 | */ |
||
992 | 3 | public function getSetTransactionIsolationSQL($level) |
|
993 | { |
||
994 | 3 | return 'SET SESSION TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level); |
|
995 | } |
||
996 | |||
997 | /** |
||
998 | * {@inheritDoc} |
||
999 | */ |
||
1000 | 6 | public function getName() |
|
1001 | { |
||
1002 | 6 | return 'mysql'; |
|
1003 | } |
||
1004 | |||
1005 | /** |
||
1006 | * {@inheritDoc} |
||
1007 | */ |
||
1008 | public function getReadLockSQL() |
||
1011 | } |
||
1012 | |||
1013 | /** |
||
1014 | * {@inheritDoc} |
||
1015 | */ |
||
1016 | 17 | protected function initializeDoctrineTypeMappings() |
|
1017 | { |
||
1018 | 17 | $this->doctrineTypeMapping = [ |
|
1019 | 'tinyint' => 'boolean', |
||
1020 | 'smallint' => 'smallint', |
||
1021 | 'mediumint' => 'integer', |
||
1022 | 'int' => 'integer', |
||
1023 | 'integer' => 'integer', |
||
1024 | 'bigint' => 'bigint', |
||
1025 | 'tinytext' => 'text', |
||
1026 | 'mediumtext' => 'text', |
||
1027 | 'longtext' => 'text', |
||
1028 | 'text' => 'text', |
||
1029 | 'varchar' => 'string', |
||
1030 | 'string' => 'string', |
||
1031 | 'char' => 'string', |
||
1032 | 'date' => 'date', |
||
1033 | 'datetime' => 'datetime', |
||
1034 | 'timestamp' => 'datetime', |
||
1035 | 'time' => 'time', |
||
1036 | 'float' => 'float', |
||
1037 | 'double' => 'float', |
||
1038 | 'real' => 'float', |
||
1039 | 'decimal' => 'decimal', |
||
1040 | 'numeric' => 'decimal', |
||
1041 | 'year' => 'date', |
||
1042 | 'longblob' => 'blob', |
||
1043 | 'blob' => 'blob', |
||
1044 | 'mediumblob' => 'blob', |
||
1045 | 'tinyblob' => 'blob', |
||
1046 | 'binary' => 'binary', |
||
1047 | 'varbinary' => 'binary', |
||
1048 | 'set' => 'simple_array', |
||
1049 | ]; |
||
1050 | 17 | } |
|
1051 | |||
1052 | /** |
||
1053 | * {@inheritDoc} |
||
1054 | */ |
||
1055 | 45 | public function getVarcharMaxLength() |
|
1056 | { |
||
1057 | 45 | return 65535; |
|
1058 | } |
||
1059 | |||
1060 | /** |
||
1061 | * {@inheritdoc} |
||
1062 | */ |
||
1063 | 6 | public function getBinaryMaxLength() |
|
1064 | { |
||
1065 | 6 | return 65535; |
|
1066 | } |
||
1067 | |||
1068 | /** |
||
1069 | * {@inheritDoc} |
||
1070 | */ |
||
1071 | 62 | protected function getReservedKeywordsClass() |
|
1072 | { |
||
1073 | 62 | return Keywords\MySQLKeywords::class; |
|
1074 | } |
||
1075 | |||
1076 | /** |
||
1077 | * {@inheritDoc} |
||
1078 | * |
||
1079 | * MySQL commits a transaction implicitly when DROP TABLE is executed, however not |
||
1080 | * if DROP TEMPORARY TABLE is executed. |
||
1081 | */ |
||
1082 | View Code Duplication | public function getDropTemporaryTableSQL($table) |
|
1083 | { |
||
1084 | if ($table instanceof Table) { |
||
1085 | $table = $table->getQuotedName($this); |
||
1086 | } elseif (!is_string($table)) { |
||
1087 | throw new \InvalidArgumentException('getDropTemporaryTableSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.'); |
||
1088 | } |
||
1089 | |||
1090 | return 'DROP TEMPORARY TABLE ' . $table; |
||
1091 | } |
||
1092 | |||
1093 | /** |
||
1094 | * Gets the SQL Snippet used to declare a BLOB column type. |
||
1095 | * TINYBLOB : 2 ^ 8 - 1 = 255 |
||
1096 | * BLOB : 2 ^ 16 - 1 = 65535 |
||
1097 | * MEDIUMBLOB : 2 ^ 24 - 1 = 16777215 |
||
1098 | * LONGBLOB : 2 ^ 32 - 1 = 4294967295 |
||
1099 | * |
||
1100 | * @param array $field |
||
1101 | * |
||
1102 | * @return string |
||
1103 | */ |
||
1104 | 8 | View Code Duplication | public function getBlobTypeDeclarationSQL(array $field) |
1105 | { |
||
1106 | 8 | if ( ! empty($field['length']) && is_numeric($field['length'])) { |
|
1107 | 6 | $length = $field['length']; |
|
1108 | |||
1109 | 6 | if ($length <= static::LENGTH_LIMIT_TINYBLOB) { |
|
1110 | 3 | return 'TINYBLOB'; |
|
1111 | } |
||
1112 | |||
1113 | 6 | if ($length <= static::LENGTH_LIMIT_BLOB) { |
|
1114 | 3 | return 'BLOB'; |
|
1115 | } |
||
1116 | |||
1117 | 6 | if ($length <= static::LENGTH_LIMIT_MEDIUMBLOB) { |
|
1118 | 6 | return 'MEDIUMBLOB'; |
|
1119 | } |
||
1120 | } |
||
1121 | |||
1122 | 8 | return 'LONGBLOB'; |
|
1123 | } |
||
1124 | |||
1125 | /** |
||
1126 | * {@inheritdoc} |
||
1127 | */ |
||
1128 | 63 | public function quoteStringLiteral($str) |
|
1129 | { |
||
1130 | 63 | $str = str_replace('\\', '\\\\', $str); // MySQL requires backslashes to be escaped aswell. |
|
1131 | |||
1132 | 63 | return parent::quoteStringLiteral($str); |
|
1133 | } |
||
1134 | |||
1135 | /** |
||
1136 | * {@inheritdoc} |
||
1137 | */ |
||
1138 | 1 | public function getDefaultTransactionIsolationLevel() |
|
1141 | } |
||
1142 | } |
||
1143 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.