Completed
Push — master ( da6087...8e2986 )
by José
03:06 queued 01:21
created

MysqlAdapter::addColumn()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 9

Duplication

Lines 15
Ratio 100 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 0
Metric Value
dl 15
loc 15
ccs 7
cts 7
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 9
nc 2
nop 2
crap 2
1
<?php
2
/**
3
 * Phinx
4
 *
5
 * (The MIT license)
6
 * Copyright (c) 2015 Rob Morgan
7
 *
8
 * Permission is hereby granted, free of charge, to any person obtaining a copy
9
 * of this software and associated * documentation files (the "Software"), to
10
 * deal in the Software without restriction, including without limitation the
11
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12
 * sell copies of the Software, and to permit persons to whom the Software is
13
 * furnished to do so, subject to the following conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be included in
16
 * all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24
 * IN THE SOFTWARE.
25
 *
26
 * @package    Phinx
27
 * @subpackage Phinx\Db\Adapter
28
 */
29
namespace Phinx\Db\Adapter;
30
31
use Phinx\Db\Table;
32
use Phinx\Db\Table\Column;
33
use Phinx\Db\Table\ForeignKey;
34
use Phinx\Db\Table\Index;
35
use Phinx\Util\Literal;
36
37
/**
38
 * Phinx MySQL Adapter.
39
 *
40
 * @author Rob Morgan <[email protected]>
41
 */
42
class MysqlAdapter extends PdoAdapter implements AdapterInterface
43
{
44
45
    protected $signedColumnTypes = ['integer' => true, 'biginteger' => true, 'float' => true, 'decimal' => true, 'boolean' => true];
46
47
    const TEXT_TINY = 255;
48
    const TEXT_SMALL = 255; /* deprecated, alias of TEXT_TINY */
49
    const TEXT_REGULAR = 65535;
50
    const TEXT_MEDIUM = 16777215;
51
    const TEXT_LONG = 4294967295;
52
53
    // According to https://dev.mysql.com/doc/refman/5.0/en/blob.html BLOB sizes are the same as TEXT
54
    const BLOB_TINY = 255;
55
    const BLOB_SMALL = 255; /* deprecated, alias of BLOB_TINY */
56
    const BLOB_REGULAR = 65535;
57
    const BLOB_MEDIUM = 16777215;
58
    const BLOB_LONG = 4294967295;
59
60
    const INT_TINY = 255;
61
    const INT_SMALL = 65535;
62
    const INT_MEDIUM = 16777215;
63
    const INT_REGULAR = 4294967295;
64
    const INT_BIG = 18446744073709551615;
65
66
    const BIT = 64;
67
68
    const TYPE_YEAR = 'year';
69
70 80
    /**
71
     * {@inheritdoc}
72 80
     */
73 80
    public function connect()
74
    {
75
        if ($this->connection === null) {
76
            if (!class_exists('PDO') || !in_array('mysql', \PDO::getAvailableDrivers(), true)) {
77
                // @codeCoverageIgnoreStart
78
                throw new \RuntimeException('You need to enable the PDO_Mysql extension for Phinx to run properly.');
79 80
                // @codeCoverageIgnoreEnd
80 80
            }
81
82 80
            $db = null;
83
            $options = $this->getOptions();
84 80
85
            $dsn = 'mysql:';
86
87
            if (!empty($options['unix_socket'])) {
88
                // use socket connection
89 80
                $dsn .= 'unix_socket=' . $options['unix_socket'];
90 80
            } else {
91 80
                // use network connection
92 80
                $dsn .= 'host=' . $options['host'];
93
                if (!empty($options['port'])) {
94
                    $dsn .= ';port=' . $options['port'];
95 80
                }
96
            }
97
98 80
            $dsn .= ';dbname=' . $options['name'];
99
100
            // charset support
101
            if (!empty($options['charset'])) {
102 80
                $dsn .= ';charset=' . $options['charset'];
103
            }
104
105
            $driverOptions = [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION];
106 80
107 80
            // support arbitrary \PDO::MYSQL_ATTR_* driver options and pass them to PDO
108
            // http://php.net/manual/en/ref.pdo-mysql.php#pdo-mysql.constants
109 View Code Duplication
            foreach ($options as $key => $option) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
110 80
                if (strpos($key, 'mysql_attr_') === 0) {
111
                    $driverOptions[constant('\PDO::' . strtoupper($key))] = $option;
112
                }
113 80
            }
114 80
115 1
            try {
116 1
                $db = new \PDO($dsn, $options['user'], $options['pass'], $driverOptions);
117 1
            } catch (\PDOException $exception) {
118 1
                throw new \InvalidArgumentException(sprintf(
119
                    'There was a problem connecting to the database: %s',
120
                    $exception->getMessage()
121 80
                ));
122 80
            }
123 80
124
            $this->setConnection($db);
125
        }
126
    }
127
128 81
    /**
129
     * {@inheritdoc}
130 81
     */
131 81
    public function disconnect()
132
    {
133
        $this->connection = null;
134
    }
135
136 6
    /**
137
     * {@inheritdoc}
138 6
     */
139
    public function hasTransactions()
140
    {
141
        return true;
142
    }
143
144 6
    /**
145
     * {@inheritdoc}
146 6
     */
147 6
    public function beginTransaction()
148
    {
149
        $this->execute('START TRANSACTION');
150
    }
151
152 6
    /**
153
     * {@inheritdoc}
154 6
     */
155 6
    public function commitTransaction()
156
    {
157
        $this->execute('COMMIT');
158
    }
159
160 1
    /**
161
     * {@inheritdoc}
162 1
     */
163 1
    public function rollbackTransaction()
164
    {
165
        $this->execute('ROLLBACK');
166
    }
167
168 112
    /**
169
     * {@inheritdoc}
170 112
     */
171
    public function quoteTableName($tableName)
172
    {
173
        return str_replace('.', '`.`', $this->quoteColumnName($tableName));
174
    }
175
176 112
    /**
177
     * {@inheritdoc}
178 112
     */
179
    public function quoteColumnName($columnName)
180
    {
181
        return '`' . str_replace('`', '``', $columnName) . '`';
182
    }
183
184 82
    /**
185
     * {@inheritdoc}
186 82
     */
187 View Code Duplication
    public function hasTable($tableName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
188 82
    {
189
        $options = $this->getOptions();
190
191 82
        $exists = $this->fetchRow(sprintf(
192 82
            "SELECT TABLE_NAME
193
            FROM INFORMATION_SCHEMA.TABLES
194 82
            WHERE TABLE_SCHEMA = '%s' AND TABLE_NAME = '%s'",
195
            $options['name'],
196 82
            $tableName
197
        ));
198
199
        return !empty($exists);
200
    }
201
202 82
    /**
203
     * {@inheritdoc}
204
     */
205
    public function createTable(Table $table)
206 82
    {
207
        // This method is based on the MySQL docs here: http://dev.mysql.com/doc/refman/5.1/en/create-index.html
208 82
        $defaultOptions = [
209 82
            'engine' => 'InnoDB',
210
            'collation' => 'utf8_general_ci'
211
        ];
212 82
213 82
        $options = array_merge(
214 68
            $defaultOptions,
215 68
            array_intersect_key($this->getOptions(), $defaultOptions),
216 68
            $table->getOptions()
217 68
        );
218 68
219
        // Add the default primary key
220 68
        $columns = $table->getPendingColumns();
221 68
        if (!isset($options['id']) || (isset($options['id']) && $options['id'] === true)) {
222 82
            $column = new Column();
223
            $column->setName('id')
224 2
                   ->setType('integer')
225 2
                   ->setSigned(isset($options['signed']) ? $options['signed'] : true)
226 2
                   ->setIdentity(true);
227 2
228
            array_unshift($columns, $column);
229 2
            $options['primary_key'] = 'id';
230 2
        } elseif (isset($options['id']) && is_string($options['id'])) {
231 2
            // Handle id => "field_name" to support AUTO_INCREMENT
232
            $column = new Column();
233
            $column->setName($options['id'])
234
                   ->setType('integer')
235
                   ->setSigned(isset($options['signed']) ? $options['signed'] : true)
236 82
                   ->setIdentity(true);
237 82
238 82
            array_unshift($columns, $column);
239 82
            $options['primary_key'] = $options['id'];
240
        }
241
242 82
        // TODO - process table options like collation etc
243 82
244 82
        // process table engine (default to InnoDB)
245 82
        $optionsStr = 'ENGINE = InnoDB';
246 82
        if (isset($options['engine'])) {
247
            $optionsStr = sprintf('ENGINE = %s', $options['engine']);
248
        }
249 82
250 2
        // process table collation
251 2
        if (isset($options['collation'])) {
252
            $charset = explode('_', $options['collation']);
253 82
            $optionsStr .= sprintf(' CHARACTER SET %s', $charset[0]);
254 82
            $optionsStr .= sprintf(' COLLATE %s', $options['collation']);
255 82
        }
256 82
257 82
        // set the table comment
258
        if (isset($options['comment'])) {
259
            $optionsStr .= sprintf(" COMMENT=%s ", $this->getConnection()->quote($options['comment']));
260 82
        }
261 82
262 82
        $sql = 'CREATE TABLE ';
263 82
        $sql .= $this->quoteTableName($table->getName()) . ' (';
264 81 View Code Duplication
        foreach ($columns as $column) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
265 82
            $sql .= $this->quoteColumnName($column->getName()) . ' ' . $this->getColumnSqlDefinition($column) . ', ';
266
        }
267
268 2
        // set the primary key(s)
269 2 View Code Duplication
        if (isset($options['primary_key'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
270 2
            $sql = rtrim($sql);
271 2
            $sql .= ' PRIMARY KEY (';
272 2
            if (is_string($options['primary_key'])) { // handle primary_key => 'id'
273 2
                $sql .= $this->quoteColumnName($options['primary_key']);
274 2
            } elseif (is_array($options['primary_key'])) { // handle primary_key => array('tag_id', 'resource_id')
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
275 2
                $sql .= implode(',', array_map([$this, 'quoteColumnName'], $options['primary_key']));
276 2
            }
277 2
            $sql .= ')';
278 82
        } else {
279 82
            $sql = substr(rtrim($sql), 0, -1); // no primary keys
280 1
        }
281
282
        // set the indexes
283
        $indexes = $table->getIndexes();
284 82
        foreach ($indexes as $index) {
285 82
            $sql .= ', ' . $this->getIndexSqlDefinition($index);
286 10
        }
287 82
288
        // set the foreign keys
289
        $foreignKeys = $table->getForeignKeys();
290 82
        foreach ($foreignKeys as $foreignKey) {
291 82
            $sql .= ', ' . $this->getForeignKeySqlDefinition($foreignKey);
292 2
        }
293 82
294
        $sql .= ') ' . $optionsStr;
295 82
        $sql = rtrim($sql) . ';';
296 82
297
        // execute the sql
298
        $this->execute($sql);
299 82
    }
300 82
301
    /**
302
     * {@inheritdoc}
303
     */
304
    public function renameTable($tableName, $newTableName)
305 5
    {
306
        $this->execute(sprintf('RENAME TABLE %s TO %s', $this->quoteTableName($tableName), $this->quoteTableName($newTableName)));
307 5
    }
308 5
309
    /**
310
     * {@inheritdoc}
311
     */
312
    public function dropTable($tableName)
313 5
    {
314
        $this->execute(sprintf('DROP TABLE %s', $this->quoteTableName($tableName)));
315 5
    }
316 5
317
    /**
318
     * {@inheritdoc}
319
     */
320
    public function truncateTable($tableName)
321 1
    {
322
        $sql = sprintf(
323 1
            'TRUNCATE TABLE %s',
324 1
            $this->quoteTableName($tableName)
325 1
        );
326 1
327
        $this->execute($sql);
328 1
    }
329 1
330
    /**
331
     * {@inheritdoc}
332
     */
333
    public function getColumns($tableName)
334 12
    {
335
        $columns = [];
336 12
        $rows = $this->fetchAll(sprintf('SHOW COLUMNS FROM %s', $this->quoteTableName($tableName)));
337 12
        foreach ($rows as $columnInfo) {
338 12
            $phinxType = $this->getPhinxType($columnInfo['Type']);
339 12
340
            $column = new Column();
341 12
            $column->setName($columnInfo['Field'])
342 12
                   ->setNull($columnInfo['Null'] !== 'NO')
343 12
                   ->setDefault($columnInfo['Default'])
344 12
                   ->setType($phinxType['name'])
345 12
                   ->setSigned(strpos($columnInfo['Type'], 'unsigned') === false)
346 12
                   ->setLimit($phinxType['limit']);
347
348 12
            if ($columnInfo['Extra'] === 'auto_increment') {
349 12
                $column->setIdentity(true);
350 12
            }
351
352 12
            if (isset($phinxType['values'])) {
353 3
                $column->setValues($phinxType['values']);
354 3
            }
355
356 12
            $columns[] = $column;
357 12
        }
358
359 12
        return $columns;
360
    }
361
362
    /**
363
     * {@inheritdoc}
364
     */
365 79 View Code Duplication
    public function hasColumn($tableName, $columnName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
366
    {
367 79
        $rows = $this->fetchAll(sprintf('SHOW COLUMNS FROM %s', $this->quoteTableName($tableName)));
368 79
        foreach ($rows as $column) {
369 79
            if (strcasecmp($column['Field'], $columnName) === 0) {
370 77
                return true;
371
            }
372 77
        }
373
374 21
        return false;
375
    }
376
377
    /**
378
     * {@inheritdoc}
379
     */
380 View Code Duplication
    public function addColumn(Table $table, Column $column)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
381
    {
382
        $sql = sprintf(
383 95
            'ALTER TABLE %s ADD %s %s',
384
            $this->quoteTableName($table->getName()),
385 95
            $this->quoteColumnName($column->getName()),
386 10
            $this->getColumnSqlDefinition($column)
387 95
        );
388 79
389 79
        if ($column->getAfter()) {
390 95
            $sql .= ' AFTER ' . $this->quoteColumnName($column->getAfter());
391
        }
392
393
        $this->execute($sql);
394
    }
395
396 18
    /**
397
     * {@inheritdoc}
398 18
     */
399 18
    public function renameColumn($tableName, $columnName, $newColumnName)
400 18
    {
401 18
        $rows = $this->fetchAll(sprintf('DESCRIBE %s', $this->quoteTableName($tableName)));
402 18
        foreach ($rows as $row) {
403 18
            if (strcasecmp($row['Field'], $columnName) === 0) {
404
                $null = ($row['Null'] == 'NO') ? 'NOT NULL' : 'NULL';
405 18
                $extra = ' ' . strtoupper($row['Extra']);
406 2
                if (!is_null($row['Default'])) {
407 2
                    $extra .= $this->getDefaultValueDefinition($row['Default']);
408
                }
409 18
                $definition = $row['Type'] . ' ' . $null . $extra;
410 18
411
                $this->execute(
412
                    sprintf(
413
                        'ALTER TABLE %s CHANGE COLUMN %s %s %s',
414
                        $this->quoteTableName($tableName),
415 7
                        $this->quoteColumnName($columnName),
416
                        $this->quoteColumnName($newColumnName),
417 7
                        $definition
418 7
                    )
419 7
                );
420 5
421 5
                return;
422 5
            }
423 1
        }
424 1
425 5
        throw new \InvalidArgumentException(sprintf(
426
            'The specified column doesn\'t exist: ' .
427 5
            $columnName
428 5
        ));
429 5
    }
430 5
431 5
    /**
432 5
     * {@inheritdoc}
433
     */
434 5 View Code Duplication
    public function changeColumn($tableName, $columnName, Column $newColumn)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
435 5
    {
436 5
        $after = $newColumn->getAfter() ? ' AFTER ' . $this->quoteColumnName($newColumn->getAfter()) : '';
437
        $this->execute(
438 6
            sprintf(
439
                'ALTER TABLE %s CHANGE %s %s %s%s',
440 2
                $this->quoteTableName($tableName),
441
                $this->quoteColumnName($columnName),
442
                $this->quoteColumnName($newColumn->getName()),
443 2
                $this->getColumnSqlDefinition($newColumn),
444
                $after
445
            )
446
        );
447
    }
448
449 5
    /**
450
     * {@inheritdoc}
451 5
     */
452 5
    public function dropColumn($tableName, $columnName)
453 5
    {
454 5
        $this->execute(
455 5
            sprintf(
456 5
                'ALTER TABLE %s DROP COLUMN %s',
457 5
                $this->quoteTableName($tableName),
458 5
                $this->quoteColumnName($columnName)
459
            )
460 5
        );
461 5
    }
462 5
463
    /**
464
     * Get an array of indexes from a particular table.
465
     *
466
     * @param string $tableName Table Name
467 5
     * @return array
468
     */
469 5 View Code Duplication
    protected function getIndexes($tableName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
470 5
    {
471 5
        $indexes = [];
472 5
        $rows = $this->fetchAll(sprintf('SHOW INDEXES FROM %s', $this->quoteTableName($tableName)));
473 5
        foreach ($rows as $row) {
474 5
            if (!isset($indexes[$row['Key_name']])) {
475 5
                $indexes[$row['Key_name']] = ['columns' => []];
476 5
            }
477
            $indexes[$row['Key_name']]['columns'][] = strtolower($row['Column_name']);
478
        }
479
480
        return $indexes;
481
    }
482
483
    /**
484 19
     * {@inheritdoc}
485
     */
486 19
    public function hasIndex($tableName, $columns)
487 19
    {
488 19
        if (is_string($columns)) {
489 18
            $columns = [$columns]; // str to array
490 18
        }
491 18
492 18
        $columns = array_map('strtolower', $columns);
493 19
        $indexes = $this->getIndexes($tableName);
494 19
495
        foreach ($indexes as $index) {
496
            if ($columns == $index['columns']) {
497
                return true;
498
            }
499
        }
500 14
501
        return false;
502 14
    }
503 6
504 6
    /**
505
     * {@inheritdoc}
506 14
     */
507 14 View Code Duplication
    public function hasIndexByName($tableName, $indexName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
508
    {
509 14
        $indexes = $this->getIndexes($tableName);
510 14
511 12
        foreach ($indexes as $name => $index) {
512
            if ($name === $indexName) {
513 13
                return true;
514
            }
515 11
        }
516
517
        return false;
518
    }
519
520
    /**
521 1
     * {@inheritdoc}
522
     */
523 1
    public function addIndex(Table $table, Index $index)
524
    {
525 1
        $this->execute(
526 1
            sprintf(
527 1
                'ALTER TABLE %s ADD %s',
528
                $this->quoteTableName($table->getName()),
529 1
                $this->getIndexSqlDefinition($index)
530
            )
531
        );
532
    }
533
534
    /**
535
     * {@inheritdoc}
536
     */
537 4
    public function dropIndex($tableName, $columns)
538
    {
539 4
        if (is_string($columns)) {
540 4
            $columns = [$columns]; // str to array
541 4
        }
542 4
543 4
        $indexes = $this->getIndexes($tableName);
544 4
        $columns = array_map('strtolower', $columns);
545 4
546 4
        foreach ($indexes as $indexName => $index) {
547
            if ($columns == $index['columns']) {
548
                $this->execute(
549
                    sprintf(
550
                        'ALTER TABLE %s DROP INDEX %s',
551 3
                        $this->quoteTableName($tableName),
552
                        $this->quoteColumnName($indexName)
553 3
                    )
554 2
                );
555 2
556
                return;
557 3
            }
558 3
        }
559
    }
560 3
561 3
    /**
562 3
     * {@inheritdoc}
563 3
     */
564 3 View Code Duplication
    public function dropIndexByName($tableName, $indexName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
565 3
    {
566 3
        $indexes = $this->getIndexes($tableName);
567 3
568 3
        foreach ($indexes as $name => $index) {
569 3
            //$a = array_diff($columns, $index['columns']);
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
570
            if ($name === $indexName) {
571 3
                $this->execute(
572 1
                    sprintf(
573
                        'ALTER TABLE %s DROP INDEX %s',
574
                        $this->quoteTableName($tableName),
575
                        $this->quoteColumnName($indexName)
576
                    )
577 2
                );
578
579 2
                return;
580
            }
581 2
        }
582
    }
583 2
584 2
    /**
585 2
     * {@inheritdoc}
586 2
     */
587 2 View Code Duplication
    public function hasForeignKey($tableName, $columns, $constraint = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
588 2
    {
589 2
        if (is_string($columns)) {
590 2
            $columns = [$columns]; // str to array
591 2
        }
592
        $foreignKeys = $this->getForeignKeys($tableName);
593 2
        if ($constraint) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $constraint of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
594
            if (isset($foreignKeys[$constraint])) {
595
                return !empty($foreignKeys[$constraint]);
596
            }
597
598
            return false;
599 21
        } else {
600
            foreach ($foreignKeys as $key) {
601 21
                if ($columns == $key['columns']) {
602 5
                    return true;
603 5
                }
604 21
            }
605 21
606 6
            return false;
607 4
        }
608
    }
609 4
610
    /**
611 15
     * Get an array of foreign keys from a particular table.
612 12
     *
613 10
     * @param string $tableName Table Name
614
     * @return array
615 11
     */
616 11 View Code Duplication
    protected function getForeignKeys($tableName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
617
    {
618
        $foreignKeys = [];
619
        $rows = $this->fetchAll(sprintf(
620
            "SELECT
621
              CONSTRAINT_NAME,
622
              TABLE_NAME,
623
              COLUMN_NAME,
624
              REFERENCED_TABLE_NAME,
625
              REFERENCED_COLUMN_NAME
626 22
            FROM information_schema.KEY_COLUMN_USAGE
627
            WHERE REFERENCED_TABLE_SCHEMA = DATABASE()
628 22
              AND REFERENCED_TABLE_NAME IS NOT NULL
629 22
              AND TABLE_NAME = '%s'
630
            ORDER BY POSITION_IN_UNIQUE_CONSTRAINT",
631
            $tableName
632
        ));
633
        foreach ($rows as $row) {
634
            $foreignKeys[$row['CONSTRAINT_NAME']]['table'] = $row['TABLE_NAME'];
635
            $foreignKeys[$row['CONSTRAINT_NAME']]['columns'][] = $row['COLUMN_NAME'];
636
            $foreignKeys[$row['CONSTRAINT_NAME']]['referenced_table'] = $row['REFERENCED_TABLE_NAME'];
637
            $foreignKeys[$row['CONSTRAINT_NAME']]['referenced_columns'][] = $row['REFERENCED_COLUMN_NAME'];
638
        }
639
640 22
        return $foreignKeys;
641
    }
642 22
643 22
    /**
644 19
     * {@inheritdoc}
645 19
     */
646 19
    public function addForeignKey(Table $table, ForeignKey $foreignKey)
647 19
    {
648 22
        $this->execute(
649 22
            sprintf(
650
                'ALTER TABLE %s ADD %s',
651
                $this->quoteTableName($table->getName()),
652
                $this->getForeignKeySqlDefinition($foreignKey)
653
            )
654
        );
655 15
    }
656
657 15
    /**
658 15
     * {@inheritdoc}
659 15
     */
660 15 View Code Duplication
    public function dropForeignKey($tableName, $columns, $constraint = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
661 15
    {
662 15
        if (is_string($columns)) {
663 15
            $columns = [$columns]; // str to array
664 15
        }
665
666
        if ($constraint) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $constraint of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
667
            $this->execute(
668
                sprintf(
669 8
                    'ALTER TABLE %s DROP FOREIGN KEY %s',
670
                    $this->quoteTableName($tableName),
671 8
                    $constraint
672 3
                )
673 3
            );
674
675
            return;
676 8
        } else {
677 8
            foreach ($columns as $column) {
678 8
                $rows = $this->fetchAll(sprintf(
679 8
                    "SELECT
680 8
                        CONSTRAINT_NAME
681
                      FROM information_schema.KEY_COLUMN_USAGE
682 8
                      WHERE REFERENCED_TABLE_SCHEMA = DATABASE()
683 8
                        AND REFERENCED_TABLE_NAME IS NOT NULL
684 8
                        AND TABLE_NAME = '%s'
685
                        AND COLUMN_NAME = '%s'
686 7
                      ORDER BY POSITION_IN_UNIQUE_CONSTRAINT",
687 7
                    $tableName,
688
                    $column
689
                ));
690
                foreach ($rows as $row) {
691
                    $this->dropForeignKey($tableName, $columns, $row['CONSTRAINT_NAME']);
692
                }
693
            }
694
        }
695 7
    }
696 7
697
    /**
698 7
     * {@inheritdoc}
699 7
     */
700 7
    public function getSqlType($type, $limit = null)
701 7
    {
702 7
        switch ($type) {
703
            case static::PHINX_TYPE_FLOAT:
704 7
            case static::PHINX_TYPE_DECIMAL:
705
            case static::PHINX_TYPE_DATETIME:
706
            case static::PHINX_TYPE_TIMESTAMP:
707
            case static::PHINX_TYPE_TIME:
708
            case static::PHINX_TYPE_DATE:
709 96
            case static::PHINX_TYPE_ENUM:
710
            case static::PHINX_TYPE_SET:
711
            case static::PHINX_TYPE_JSON:
712 96
            // Geospatial database types
713 87
            case static::PHINX_TYPE_GEOMETRY:
714
            case static::PHINX_TYPE_POINT:
715 96
            case static::PHINX_TYPE_LINESTRING:
716 4
            case static::PHINX_TYPE_POLYGON:
717
                return ['name' => $type];
718 96
            case static::PHINX_TYPE_STRING:
719 9
                return ['name' => 'varchar', 'limit' => $limit ?: 255];
720
            case static::PHINX_TYPE_CHAR:
721
                return ['name' => 'char', 'limit' => $limit ?: 255];
722 6 View Code Duplication
            case static::PHINX_TYPE_TEXT:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
723 6
                if ($limit) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $limit of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
724 6
                    $sizes = [
725 6
                        // Order matters! Size must always be tested from longest to shortest!
726 6
                        'longtext' => static::TEXT_LONG,
727 6
                        'mediumtext' => static::TEXT_MEDIUM,
728 6
                        'text' => static::TEXT_REGULAR,
729 6
                        'tinytext' => static::TEXT_SMALL,
730
                    ];
731 5
                    foreach ($sizes as $name => $length) {
732
                        if ($limit >= $length) {
733 5
                            return ['name' => $name];
734
                        }
735 95
                    }
736 5
                }
737
738 95
                return ['name' => 'text'];
739 3
            case static::PHINX_TYPE_BINARY:
740
                return ['name' => 'binary', 'limit' => $limit ?: 255];
741 95
            case static::PHINX_TYPE_VARBINARY:
742 1
                return ['name' => 'varbinary', 'limit' => $limit ?: 255];
743 View Code Duplication
            case static::PHINX_TYPE_BLOB:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
744
                if ($limit) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $limit of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
745 1
                    $sizes = [
746 1
                        // Order matters! Size must always be tested from longest to shortest!
747 1
                        'longblob' => static::BLOB_LONG,
748 1
                        'mediumblob' => static::BLOB_MEDIUM,
749 1
                        'blob' => static::BLOB_REGULAR,
750 1
                        'tinyblob' => static::BLOB_SMALL,
751 1
                    ];
752 1
                    foreach ($sizes as $name => $length) {
753
                        if ($limit >= $length) {
754 1
                            return ['name' => $name];
755
                        }
756 1
                    }
757
                }
758 95
759 82
                return ['name' => 'blob'];
760
            case static::PHINX_TYPE_BIT:
761
                return ['name' => 'bit', 'limit' => $limit ?: 64];
762 6
            case static::PHINX_TYPE_INTEGER:
763 6
                if ($limit && $limit >= static::INT_TINY) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $limit of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
764 6
                    $sizes = [
765 6
                        // Order matters! Size must always be tested from longest to shortest!
766 6
                        'bigint' => static::INT_BIG,
767 6
                        'int' => static::INT_REGULAR,
768
                        'mediumint' => static::INT_MEDIUM,
769 6
                        'smallint' => static::INT_SMALL,
770 6
                        'tinyint' => static::INT_TINY,
771 6
                    ];
772 6
                    $limits = [
773 6
                        'int' => 11,
774 6
                        'bigint' => 20,
775 6
                    ];
776 2
                    foreach ($sizes as $name => $length) {
777 2
                        if ($limit >= $length) {
778 6
                            $def = ['name' => $name];
779
                            if (isset($limits[$name])) {
780 5
                                $def['limit'] = $limits[$name];
781 82
                            }
782 76
783 76
                            return $def;
784 82
                        }
785
                    }
786 86
                } elseif (!$limit) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $limit of type integer|null is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
787 82
                    $limit = 11;
788
                }
789 86
790 7
                return ['name' => 'int', 'limit' => $limit];
791
            case static::PHINX_TYPE_BIG_INTEGER:
792 84
                return ['name' => 'bigint', 'limit' => 20];
793 5
            case static::PHINX_TYPE_BOOLEAN:
794
                return ['name' => 'tinyint', 'limit' => 1];
795 83
            case static::PHINX_TYPE_UUID:
796 7
                return ['name' => 'char', 'limit' => 36];
797
            case static::TYPE_YEAR:
798 83
                if (!$limit || in_array($limit, [2, 4])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $limit of type integer|null is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
799 80
                    $limit = 4;
800
                }
801 83
802 4
                return ['name' => 'year', 'limit' => $limit];
803
            default:
804 83
                throw new \RuntimeException('The type: "' . $type . '" is not supported.');
805 4
        }
806
    }
807 83
808 80
    /**
809
     * Returns Phinx type by SQL type
810 10
     *
811 2
     * @param string $sqlTypeDef
812
     * @throws \RuntimeException
813 10
     * @internal param string $sqlType SQL type
814 10
     * @returns string Phinx type
815 10
     */
816 10
    public function getPhinxType($sqlTypeDef)
817 5
    {
818 8
        $matches = [];
819 5
        if (!preg_match('/^([\w]+)(\(([\d]+)*(,([\d]+))*\))*(.+)*$/', $sqlTypeDef, $matches)) {
820
            throw new \RuntimeException('Column type ' . $sqlTypeDef . ' is not supported');
821 6
        } else {
822 4
            $limit = null;
823
            $precision = null;
824 2
            $type = $matches[1];
825
            if (count($matches) > 2) {
826
                $limit = $matches[3] ? (int)$matches[3] : null;
827
            }
828
            if (count($matches) > 4) {
829
                $precision = (int)$matches[5];
830 2
            }
831 View Code Duplication
            if ($type === 'tinyint' && $limit === 1) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
832
                $type = static::PHINX_TYPE_BOOLEAN;
833 2
                $limit = null;
834 2
            }
835 2
            switch ($type) {
836
                case 'varchar':
837
                    $type = static::PHINX_TYPE_STRING;
838
                    if ($limit === 255) {
839
                        $limit = null;
840
                    }
841
                    break;
842 View Code Duplication
                case 'char':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
843
                    $type = static::PHINX_TYPE_CHAR;
844
                    if ($limit === 255) {
845
                        $limit = null;
846 17
                    }
847
                    if ($limit === 36) {
848 17
                        $type = static::PHINX_TYPE_UUID;
849 17
                    }
850 1
                    break;
851
                case 'tinyint':
852 16
                    $type = static::PHINX_TYPE_INTEGER;
853 16
                    $limit = static::INT_TINY;
854 16
                    break;
855 16
                case 'smallint':
856 14
                    $type = static::PHINX_TYPE_INTEGER;
857 14
                    $limit = static::INT_SMALL;
858 16
                    break;
859 4
                case 'mediumint':
860 4
                    $type = static::PHINX_TYPE_INTEGER;
861 16
                    $limit = static::INT_MEDIUM;
862 3
                    break;
863 3
                case 'int':
864 3
                    $type = static::PHINX_TYPE_INTEGER;
865
                    if ($limit === 11) {
866 16
                        $limit = null;
867 6
                    }
868 6
                    break;
869 3
                case 'bigint':
870 3
                    if ($limit === 20) {
871 6
                        $limit = null;
872 16
                    }
873 5
                    $type = static::PHINX_TYPE_BIG_INTEGER;
874 5
                    break;
875 1
                case 'bit':
876 1
                    $type = static::PHINX_TYPE_BIT;
877 5
                    if ($limit === 64) {
878 2
                        $limit = null;
879 2
                    }
880 5
                    break;
881 16
                case 'blob':
882 2
                    $type = static::PHINX_TYPE_BINARY;
883 2
                    break;
884 2
                case 'tinyblob':
885 16
                    $type = static::PHINX_TYPE_BINARY;
886 2
                    $limit = static::BLOB_TINY;
887 2
                    break;
888 2
                case 'mediumblob':
889 16
                    $type = static::PHINX_TYPE_BINARY;
890 2
                    $limit = static::BLOB_MEDIUM;
891 2
                    break;
892 2
                case 'longblob':
893 16
                    $type = static::PHINX_TYPE_BINARY;
894 15
                    $limit = static::BLOB_LONG;
895 15
                    break;
896 12
                case 'tinytext':
897 12
                    $type = static::PHINX_TYPE_TEXT;
898 15
                    $limit = static::TEXT_TINY;
899 11
                    break;
900 6
                case 'mediumtext':
901 4
                    $type = static::PHINX_TYPE_TEXT;
902 4
                    $limit = static::TEXT_MEDIUM;
903 6
                    break;
904 6
                case 'longtext':
905 10
                    $type = static::PHINX_TYPE_TEXT;
906 2
                    $limit = static::TEXT_LONG;
907 2
                    break;
908 10
            }
909 1
910 1
            // Call this to check if parsed type is supported.
911 1
            $this->getSqlType($type, $limit);
912 10
913 1
            $phinxType = [
914 1
                'name' => $type,
915 1
                'limit' => $limit,
916 10
                'precision' => $precision
917 1
            ];
918 1
919 1
            if (static::PHINX_TYPE_ENUM == $type) {
920 10
                $phinxType['values'] = explode("','", trim($matches[6], "()'"));
921 2
            }
922 2
923 2
            return $phinxType;
924 9
        }
925 2
    }
926 2
927 2
    /**
928 8
     * {@inheritdoc}
929 2
     */
930 2
    public function createDatabase($name, $options = [])
931 2
    {
932
        $charset = isset($options['charset']) ? $options['charset'] : 'utf8';
933
934 View Code Duplication
        if (isset($options['collation'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
935 16
            $this->execute(sprintf('CREATE DATABASE `%s` DEFAULT CHARACTER SET `%s` COLLATE `%s`', $name, $charset, $options['collation']));
936
        } else {
937
            $this->execute(sprintf('CREATE DATABASE `%s` DEFAULT CHARACTER SET `%s`', $name, $charset));
938 15
        }
939 15
    }
940
941 15
    /**
942
     * {@inheritdoc}
943 15
     */
944 3
    public function hasDatabase($name)
945 3
    {
946
        $rows = $this->fetchAll(
947 15
            sprintf(
948
                'SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = \'%s\'',
949
                $name
950
            )
951
        );
952
953
        foreach ($rows as $row) {
954 83
            if (!empty($row)) {
955
                return true;
956 83
            }
957
        }
958 83
959 1
        return false;
960 1
    }
961 82
962
    /**
963 83
     * {@inheritdoc}
964
     */
965
    public function dropDatabase($name)
966
    {
967
        $this->execute(sprintf('DROP DATABASE IF EXISTS `%s`', $name));
968 4
    }
969
970 4
    /**
971 4
     * Gets the MySQL Column Definition for a Column object.
972 4
     *
973
     * @param \Phinx\Db\Table\Column $column Column
974 4
     * @return string
975 4
     */
976
    protected function getColumnSqlDefinition(Column $column)
977 4
    {
978 3
        if ($column->getType() instanceof Literal) {
979 3
            $def = (string)$column->getType();
980
        } else {
981 3
            $sqlType = $this->getSqlType($column->getType(), $column->getLimit());
982
            $def = strtoupper($sqlType['name']);
983 3
        }
984
        if ($column->getPrecision() && $column->getScale()) {
985
            $def .= '(' . $column->getPrecision() . ',' . $column->getScale() . ')';
986
        } elseif (isset($sqlType['limit'])) {
987
            $def .= '(' . $sqlType['limit'] . ')';
988
        }
989 81 View Code Duplication
        if (($values = $column->getValues()) && is_array($values)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
990
            $def .= "('" . implode("', '", $values) . "')";
991 81
        }
992 81
        $def .= $column->getEncoding() ? ' CHARACTER SET ' . $column->getEncoding() : '';
993
        $def .= $column->getCollation() ? ' COLLATE ' . $column->getCollation() : '';
994
        $def .= (!$column->isSigned() && isset($this->signedColumnTypes[$column->getType()])) ? ' unsigned' : '';
995
        $def .= ($column->isNull() == false) ? ' NOT NULL' : ' NULL';
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
996
        $def .= $column->isIdentity() ? ' AUTO_INCREMENT' : '';
997
        $def .= $this->getDefaultValueDefinition($column->getDefault());
998
999
        if ($column->getComment()) {
1000 89
            $def .= ' COMMENT ' . $this->getConnection()->quote($column->getComment());
1001
        }
1002 89
1003
        if ($column->getUpdate()) {
1004 89
            $def .= ' ON UPDATE ' . $column->getUpdate();
1005 89
        }
1006 89
1007 2
        return $def;
1008 89
    }
1009 86
1010 86
    /**
1011 89
     * Gets the MySQL Index Definition for an Index object.
1012 5
     *
1013 5
     * @param \Phinx\Db\Table\Index $index Index
1014 89
     * @return string
1015 89
     */
1016 89
    protected function getIndexSqlDefinition(Index $index)
1017 89
    {
1018 89
        $def = '';
1019 89
        $limit = '';
1020
        if ($index->getLimit()) {
1021 89
            $limit = '(' . $index->getLimit() . ')';
1022 2
        }
1023 2
1024
        if ($index->getType() == Index::UNIQUE) {
1025 89
            $def .= ' UNIQUE';
1026 1
        }
1027 1
1028
        if ($index->getType() == Index::FULLTEXT) {
1029 89
            $def .= ' FULLTEXT';
1030
        }
1031
1032
        $def .= ' KEY';
1033
1034
        if (is_string($index->getName())) {
1035
            $def .= ' `' . $index->getName() . '`';
1036
        }
1037
1038 16
        $def .= ' (`' . implode('`,`', $index->getColumns()) . '`' . $limit . ')';
1039
1040 16
        return $def;
1041 16
    }
1042 16
1043 2
    /**
1044 2
     * Gets the MySQL Foreign Key Definition for an ForeignKey object.
1045
     *
1046 16
     * @param \Phinx\Db\Table\ForeignKey $foreignKey
1047 5
     * @return string
1048 5
     */
1049 View Code Duplication
    protected function getForeignKeySqlDefinition(ForeignKey $foreignKey)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
1050 16
    {
1051 1
        $def = '';
1052 1
        if ($foreignKey->getConstraint()) {
1053
            $def .= ' CONSTRAINT ' . $this->quoteColumnName($foreignKey->getConstraint());
0 ignored issues
show
Bug introduced by
It seems like $foreignKey->getConstraint() targeting Phinx\Db\Table\ForeignKey::getConstraint() can also be of type boolean; however, Phinx\Db\Adapter\MysqlAdapter::quoteColumnName() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
1054 16
        }
1055
        $columnNames = [];
1056 16
        foreach ($foreignKey->getColumns() as $column) {
1057 5
            $columnNames[] = $this->quoteColumnName($column);
1058 5
        }
1059
        $def .= ' FOREIGN KEY (' . implode(',', $columnNames) . ')';
1060 16
        $refColumnNames = [];
1061
        foreach ($foreignKey->getReferencedColumns() as $column) {
1062 16
            $refColumnNames[] = $this->quoteColumnName($column);
1063
        }
1064
        $def .= ' REFERENCES ' . $this->quoteTableName($foreignKey->getReferencedTable()->getName()) . ' (' . implode(',', $refColumnNames) . ')';
1065
        if ($foreignKey->getOnDelete()) {
1066
            $def .= ' ON DELETE ' . $foreignKey->getOnDelete();
1067
        }
1068
        if ($foreignKey->getOnUpdate()) {
1069
            $def .= ' ON UPDATE ' . $foreignKey->getOnUpdate();
1070
        }
1071 17
1072
        return $def;
1073 17
    }
1074 17
1075 5
    /**
1076 5
     * Describes a database table. This is a MySQL adapter specific method.
1077 17
     *
1078 17
     * @param string $tableName Table name
1079 17
     * @return array
1080 17
     */
1081 17 View Code Duplication
    public function describeTable($tableName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
1082 17
    {
1083 17
        $options = $this->getOptions();
1084 17
1085 17
        // mysql specific
1086 17
        $sql = sprintf(
1087 17
            "SELECT *
1088 2
             FROM information_schema.tables
1089 2
             WHERE table_schema = '%s'
1090 17
             AND table_name = '%s'",
1091 2
            $options['name'],
1092 2
            $tableName
1093 17
        );
1094
1095
        return $this->fetchRow($sql);
1096
    }
1097
1098
    /**
1099
     * Returns MySQL column types (inherited and MySQL specified).
1100
     * @return array
1101
     */
1102 2
    public function getColumnTypes()
1103
    {
1104 2
        return array_merge(parent::getColumnTypes(), ['enum', 'set', 'year', 'json']);
1105
    }
1106
}
1107