Completed
Pull Request — master (#1292)
by
unknown
02:18
created

MysqlAdapter::queryTableExists()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 9
cts 9
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 2
crap 1
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
36
/**
37
 * Phinx MySQL Adapter.
38
 *
39
 * @author Rob Morgan <[email protected]>
40
 */
41
class MysqlAdapter extends PdoAdapter implements AdapterInterface
42
{
43
44
    protected $signedColumnTypes = ['integer' => true, 'biginteger' => true, 'float' => true, 'decimal' => true, 'boolean' => true];
45
46
    const TEXT_TINY = 255;
47
    const TEXT_SMALL = 255; /* deprecated, alias of TEXT_TINY */
48
    const TEXT_REGULAR = 65535;
49
    const TEXT_MEDIUM = 16777215;
50
    const TEXT_LONG = 4294967295;
51
52
    // According to https://dev.mysql.com/doc/refman/5.0/en/blob.html BLOB sizes are the same as TEXT
53
    const BLOB_TINY = 255;
54
    const BLOB_SMALL = 255; /* deprecated, alias of BLOB_TINY */
55
    const BLOB_REGULAR = 65535;
56
    const BLOB_MEDIUM = 16777215;
57
    const BLOB_LONG = 4294967295;
58
59
    const INT_TINY = 255;
60
    const INT_SMALL = 65535;
61
    const INT_MEDIUM = 16777215;
62
    const INT_REGULAR = 4294967295;
63
    const INT_BIG = 18446744073709551615;
64
65
    const BIT = 64;
66
67
    const TYPE_YEAR = 'year';
68
69
    /**
70 80
     * {@inheritdoc}
71
     */
72 80
    public function connect()
73 80
    {
74
        if ($this->connection === null) {
75
            if (!class_exists('PDO') || !in_array('mysql', \PDO::getAvailableDrivers(), true)) {
76
                // @codeCoverageIgnoreStart
77
                throw new \RuntimeException('You need to enable the PDO_Mysql extension for Phinx to run properly.');
78
                // @codeCoverageIgnoreEnd
79 80
            }
80 80
81
            $db = null;
82 80
            $options = $this->getOptions();
83
84 80
            $dsn = 'mysql:';
85
86
            if (!empty($options['unix_socket'])) {
87
                // use socket connection
88
                $dsn .= 'unix_socket=' . $options['unix_socket'];
89 80
            } else {
90 80
                // use network connection
91 80
                $dsn .= 'host=' . $options['host'];
92 80
                if (!empty($options['port'])) {
93
                    $dsn .= ';port=' . $options['port'];
94
                }
95 80
            }
96
97
            $dsn .= ';dbname=' . $options['name'];
98 80
99
            // charset support
100
            if (!empty($options['charset'])) {
101
                $dsn .= ';charset=' . $options['charset'];
102 80
            }
103
104
            $driverOptions = [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION];
105
106 80
            // support arbitrary \PDO::MYSQL_ATTR_* driver options and pass them to PDO
107 80
            // http://php.net/manual/en/ref.pdo-mysql.php#pdo-mysql.constants
108 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...
109
                if (strpos($key, 'mysql_attr_') === 0) {
110 80
                    $driverOptions[constant('\PDO::' . strtoupper($key))] = $option;
111
                }
112
            }
113 80
114 80
            try {
115 1
                $db = new \PDO($dsn, $options['user'], $options['pass'], $driverOptions);
116 1
            } catch (\PDOException $exception) {
117 1
                throw new \InvalidArgumentException(sprintf(
118 1
                    'There was a problem connecting to the database: %s',
119
                    $exception->getMessage()
120
                ));
121 80
            }
122 80
123 80
            $this->setConnection($db);
124
        }
125
    }
126
127
    /**
128 81
     * {@inheritdoc}
129
     */
130 81
    public function disconnect()
131 81
    {
132
        $this->connection = null;
133
    }
134
135
    /**
136 6
     * {@inheritdoc}
137
     */
138 6
    public function hasTransactions()
139
    {
140
        return true;
141
    }
142
143
    /**
144 6
     * {@inheritdoc}
145
     */
146 6
    public function beginTransaction()
147 6
    {
148
        $this->execute('START TRANSACTION');
149
    }
150
151
    /**
152 6
     * {@inheritdoc}
153
     */
154 6
    public function commitTransaction()
155 6
    {
156
        $this->execute('COMMIT');
157
    }
158
159
    /**
160 1
     * {@inheritdoc}
161
     */
162 1
    public function rollbackTransaction()
163 1
    {
164
        $this->execute('ROLLBACK');
165
    }
166
167
    /**
168 112
     * {@inheritdoc}
169
     */
170 112
    public function quoteTableName($tableName)
171
    {
172
        return str_replace('.', '`.`', $this->quoteColumnName($tableName));
173
    }
174
175
    /**
176 112
     * {@inheritdoc}
177
     */
178 112
    public function quoteColumnName($columnName)
179
    {
180
        return '`' . str_replace('`', '``', $columnName) . '`';
181
    }
182
183
    /**
184 82
     * {@inheritdoc}
185
     */
186 82
    public function hasTable($tableName)
187
    {
188 82
        if (strpos($tableName, '.') !== false) {
189
            list($schema, $table) = explode('.', $tableName);
190
191 82
            $exists = $this->queryTableExists($schema, $table);
192 82
193
            // Only break here on success, because it is possible for table names to contain a dot.
194 82
            if (!empty($exists)) {
195
                return true;
196 82
            }
197
        }
198
199
        $options = $this->getOptions();
200
201
        $exists = $this->queryTableExists($options['name'], $tableName);
202 82
203
        return !empty($exists);
204
    }
205
206 82
    /**
207
     * @param $schema
208 82
     * @param $tableName
209 82
     *
210
     * @return array|mixed
211
     */
212 82
    private function queryTableExists($schema, $tableName)
213 82
    {
214 68
        return $this->fetchRow(sprintf(
215 68
            "SELECT TABLE_NAME
216 68
            FROM INFORMATION_SCHEMA.TABLES
217 68
            WHERE TABLE_SCHEMA = '%s' AND TABLE_NAME = '%s'",
218 68
            $schema,
219
            $tableName
220 68
        ));
221 68
    }
222 82
223
    /**
224 2
     * {@inheritdoc}
225 2
     */
226 2
    public function createTable(Table $table)
227 2
    {
228
        // This method is based on the MySQL docs here: http://dev.mysql.com/doc/refman/5.1/en/create-index.html
229 2
        $defaultOptions = [
230 2
            'engine' => 'InnoDB',
231 2
            'collation' => 'utf8_general_ci'
232
        ];
233
234
        $options = array_merge(
235
            $defaultOptions,
236 82
            array_intersect_key($this->getOptions(), $defaultOptions),
237 82
            $table->getOptions()
238 82
        );
239 82
240
        // Add the default primary key
241
        $columns = $table->getPendingColumns();
242 82
        if (!isset($options['id']) || (isset($options['id']) && $options['id'] === true)) {
243 82
            $column = new Column();
244 82
            $column->setName('id')
245 82
                   ->setType('integer')
246 82
                   ->setSigned(isset($options['signed']) ? $options['signed'] : true)
247
                   ->setIdentity(true);
248
249 82
            array_unshift($columns, $column);
250 2
            $options['primary_key'] = 'id';
251 2
        } elseif (isset($options['id']) && is_string($options['id'])) {
252
            // Handle id => "field_name" to support AUTO_INCREMENT
253 82
            $column = new Column();
254 82
            $column->setName($options['id'])
255 82
                   ->setType('integer')
256 82
                   ->setSigned(isset($options['signed']) ? $options['signed'] : true)
257 82
                   ->setIdentity(true);
258
259
            array_unshift($columns, $column);
260 82
            $options['primary_key'] = $options['id'];
261 82
        }
262 82
263 82
        // TODO - process table options like collation etc
264 81
265 82
        // process table engine (default to InnoDB)
266
        $optionsStr = 'ENGINE = InnoDB';
267
        if (isset($options['engine'])) {
268 2
            $optionsStr = sprintf('ENGINE = %s', $options['engine']);
269 2
        }
270 2
271 2
        // process table collation
272 2
        if (isset($options['collation'])) {
273 2
            $charset = explode('_', $options['collation']);
274 2
            $optionsStr .= sprintf(' CHARACTER SET %s', $charset[0]);
275 2
            $optionsStr .= sprintf(' COLLATE %s', $options['collation']);
276 2
        }
277 2
278 82
        // set the table comment
279 82
        if (isset($options['comment'])) {
280 1
            $optionsStr .= sprintf(" COMMENT=%s ", $this->getConnection()->quote($options['comment']));
281
        }
282
283
        $sql = 'CREATE TABLE ';
284 82
        $sql .= $this->quoteTableName($table->getName()) . ' (';
285 82 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...
286 10
            $sql .= $this->quoteColumnName($column->getName()) . ' ' . $this->getColumnSqlDefinition($column) . ', ';
287 82
        }
288
289
        // set the primary key(s)
290 82 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...
291 82
            $sql = rtrim($sql);
292 2
            $sql .= ' PRIMARY KEY (';
293 82
            if (is_string($options['primary_key'])) { // handle primary_key => 'id'
294
                $sql .= $this->quoteColumnName($options['primary_key']);
295 82
            } 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...
296 82
                $sql .= implode(',', array_map([$this, 'quoteColumnName'], $options['primary_key']));
297
            }
298
            $sql .= ')';
299 82
        } else {
300 82
            $sql = substr(rtrim($sql), 0, -1); // no primary keys
301
        }
302
303
        // set the indexes
304
        $indexes = $table->getIndexes();
305 5
        foreach ($indexes as $index) {
306
            $sql .= ', ' . $this->getIndexSqlDefinition($index);
307 5
        }
308 5
309
        // set the foreign keys
310
        $foreignKeys = $table->getForeignKeys();
311
        foreach ($foreignKeys as $foreignKey) {
312
            $sql .= ', ' . $this->getForeignKeySqlDefinition($foreignKey);
313 5
        }
314
315 5
        $sql .= ') ' . $optionsStr;
316 5
        $sql = rtrim($sql) . ';';
317
318
        // execute the sql
319
        $this->execute($sql);
320
    }
321 1
322
    /**
323 1
     * {@inheritdoc}
324 1
     */
325 1
    public function renameTable($tableName, $newTableName)
326 1
    {
327
        $this->execute(sprintf('RENAME TABLE %s TO %s', $this->quoteTableName($tableName), $this->quoteTableName($newTableName)));
328 1
    }
329 1
330
    /**
331
     * {@inheritdoc}
332
     */
333
    public function dropTable($tableName)
334 12
    {
335
        $this->execute(sprintf('DROP TABLE %s', $this->quoteTableName($tableName)));
336 12
    }
337 12
338 12
    /**
339 12
     * {@inheritdoc}
340
     */
341 12
    public function truncateTable($tableName)
342 12
    {
343 12
        $sql = sprintf(
344 12
            'TRUNCATE TABLE %s',
345 12
            $this->quoteTableName($tableName)
346 12
        );
347
348 12
        $this->execute($sql);
349 12
    }
350 12
351
    /**
352 12
     * {@inheritdoc}
353 3
     */
354 3 View Code Duplication
    public function getColumns($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...
355
    {
356 12
        $columns = [];
357 12
        $rows = $this->fetchAll(sprintf('SHOW COLUMNS FROM %s', $this->quoteTableName($tableName)));
358
        foreach ($rows as $columnInfo) {
359 12
            $phinxType = $this->getPhinxType($columnInfo['Type']);
360
361
            $column = new Column();
362
            $column->setName($columnInfo['Field'])
363
                   ->setNull($columnInfo['Null'] !== 'NO')
364
                   ->setDefault($columnInfo['Default'])
365 79
                   ->setType($phinxType['name'])
366
                   ->setSigned(strpos($columnInfo['Type'], 'unsigned') === false)
367 79
                   ->setLimit($phinxType['limit']);
368 79
369 79
            if ($columnInfo['Extra'] === 'auto_increment') {
370 77
                $column->setIdentity(true);
371
            }
372 77
373
            if (isset($phinxType['values'])) {
374 21
                $column->setValues($phinxType['values']);
375
            }
376
377
            $columns[] = $column;
378
        }
379
380
        return $columns;
381
    }
382
383 95
    /**
384
     * {@inheritdoc}
385 95
     */
386 10 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...
387 95
    {
388 79
        $rows = $this->fetchAll(sprintf('SHOW COLUMNS FROM %s', $this->quoteTableName($tableName)));
389 79
        foreach ($rows as $column) {
390 95
            if (strcasecmp($column['Field'], $columnName) === 0) {
391
                return true;
392
            }
393
        }
394
395
        return false;
396 18
    }
397
398 18
    /**
399 18
     * Get the defintion for a `DEFAULT` statement.
400 18
     *
401 18
     * @param  mixed $default
402 18
     * @return string
403 18
     */
404 View Code Duplication
    protected function getDefaultValueDefinition($default)
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...
405 18
    {
406 2
        if (is_string($default) && 'CURRENT_TIMESTAMP' !== $default) {
407 2
            $default = $this->getConnection()->quote($default);
408
        } elseif (is_bool($default)) {
409 18
            $default = $this->castToBool($default);
410 18
        }
411
412
        return isset($default) ? ' DEFAULT ' . $default : '';
413
    }
414
415 7
    /**
416
     * {@inheritdoc}
417 7
     */
418 7 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...
419 7
    {
420 5
        $sql = sprintf(
421 5
            'ALTER TABLE %s ADD %s %s',
422 5
            $this->quoteTableName($table->getName()),
423 1
            $this->quoteColumnName($column->getName()),
424 1
            $this->getColumnSqlDefinition($column)
425 5
        );
426
427 5
        if ($column->getAfter()) {
428 5
            $sql .= ' AFTER ' . $this->quoteColumnName($column->getAfter());
429 5
        }
430 5
431 5
        $this->execute($sql);
432 5
    }
433
434 5
    /**
435 5
     * {@inheritdoc}
436 5
     */
437
    public function renameColumn($tableName, $columnName, $newColumnName)
438 6
    {
439
        $rows = $this->fetchAll(sprintf('DESCRIBE %s', $this->quoteTableName($tableName)));
440 2
        foreach ($rows as $row) {
441
            if (strcasecmp($row['Field'], $columnName) === 0) {
442
                $null = ($row['Null'] == 'NO') ? 'NOT NULL' : 'NULL';
443 2
                $extra = ' ' . strtoupper($row['Extra']);
444
                if (!is_null($row['Default'])) {
445
                    $extra .= $this->getDefaultValueDefinition($row['Default']);
446
                }
447
                $definition = $row['Type'] . ' ' . $null . $extra;
448
449 5
                $this->execute(
450
                    sprintf(
451 5
                        'ALTER TABLE %s CHANGE COLUMN %s %s %s',
452 5
                        $this->quoteTableName($tableName),
453 5
                        $this->quoteColumnName($columnName),
454 5
                        $this->quoteColumnName($newColumnName),
455 5
                        $definition
456 5
                    )
457 5
                );
458 5
459
                return;
460 5
            }
461 5
        }
462 5
463
        throw new \InvalidArgumentException(sprintf(
464
            'The specified column doesn\'t exist: ' .
465
            $columnName
466
        ));
467 5
    }
468
469 5
    /**
470 5
     * {@inheritdoc}
471 5
     */
472 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...
473 5
    {
474 5
        $after = $newColumn->getAfter() ? ' AFTER ' . $this->quoteColumnName($newColumn->getAfter()) : '';
475 5
        $this->execute(
476 5
            sprintf(
477
                'ALTER TABLE %s CHANGE %s %s %s%s',
478
                $this->quoteTableName($tableName),
479
                $this->quoteColumnName($columnName),
480
                $this->quoteColumnName($newColumn->getName()),
481
                $this->getColumnSqlDefinition($newColumn),
482
                $after
483
            )
484 19
        );
485
    }
486 19
487 19
    /**
488 19
     * {@inheritdoc}
489 18
     */
490 18
    public function dropColumn($tableName, $columnName)
491 18
    {
492 18
        $this->execute(
493 19
            sprintf(
494 19
                'ALTER TABLE %s DROP COLUMN %s',
495
                $this->quoteTableName($tableName),
496
                $this->quoteColumnName($columnName)
497
            )
498
        );
499
    }
500 14
501
    /**
502 14
     * Get an array of indexes from a particular table.
503 6
     *
504 6
     * @param string $tableName Table Name
505
     * @return array
506 14
     */
507 14 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...
508
    {
509 14
        $indexes = [];
510 14
        $rows = $this->fetchAll(sprintf('SHOW INDEXES FROM %s', $this->quoteTableName($tableName)));
511 12
        foreach ($rows as $row) {
512
            if (!isset($indexes[$row['Key_name']])) {
513 13
                $indexes[$row['Key_name']] = ['columns' => []];
514
            }
515 11
            $indexes[$row['Key_name']]['columns'][] = strtolower($row['Column_name']);
516
        }
517
518
        return $indexes;
519
    }
520
521 1
    /**
522
     * {@inheritdoc}
523 1
     */
524
    public function hasIndex($tableName, $columns)
525 1
    {
526 1
        if (is_string($columns)) {
527 1
            $columns = [$columns]; // str to array
528
        }
529 1
530
        $columns = array_map('strtolower', $columns);
531
        $indexes = $this->getIndexes($tableName);
532
533
        foreach ($indexes as $index) {
534
            if ($columns == $index['columns']) {
535
                return true;
536
            }
537 4
        }
538
539 4
        return false;
540 4
    }
541 4
542 4
    /**
543 4
     * {@inheritdoc}
544 4
     */
545 4 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...
546 4
    {
547
        $indexes = $this->getIndexes($tableName);
548
549
        foreach ($indexes as $name => $index) {
550
            if ($name === $indexName) {
551 3
                 return true;
552
            }
553 3
        }
554 2
555 2
        return false;
556
    }
557 3
558 3
    /**
559
     * {@inheritdoc}
560 3
     */
561 3
    public function addIndex(Table $table, Index $index)
562 3
    {
563 3
        $this->execute(
564 3
            sprintf(
565 3
                'ALTER TABLE %s ADD %s',
566 3
                $this->quoteTableName($table->getName()),
567 3
                $this->getIndexSqlDefinition($index)
568 3
            )
569 3
        );
570
    }
571 3
572 1
    /**
573
     * {@inheritdoc}
574
     */
575
    public function dropIndex($tableName, $columns)
576
    {
577 2
        if (is_string($columns)) {
578
            $columns = [$columns]; // str to array
579 2
        }
580
581 2
        $indexes = $this->getIndexes($tableName);
582
        $columns = array_map('strtolower', $columns);
583 2
584 2
        foreach ($indexes as $indexName => $index) {
585 2
            if ($columns == $index['columns']) {
586 2
                $this->execute(
587 2
                    sprintf(
588 2
                        'ALTER TABLE %s DROP INDEX %s',
589 2
                        $this->quoteTableName($tableName),
590 2
                        $this->quoteColumnName($indexName)
591 2
                    )
592
                );
593 2
594
                return;
595
            }
596
        }
597
    }
598
599 21
    /**
600
     * {@inheritdoc}
601 21
     */
602 5 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...
603 5
    {
604 21
        $indexes = $this->getIndexes($tableName);
605 21
606 6
        foreach ($indexes as $name => $index) {
607 4
            //$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...
608
            if ($name === $indexName) {
609 4
                $this->execute(
610
                    sprintf(
611 15
                        'ALTER TABLE %s DROP INDEX %s',
612 12
                        $this->quoteTableName($tableName),
613 10
                        $this->quoteColumnName($indexName)
614
                    )
615 11
                );
616 11
617
                return;
618
            }
619
        }
620
    }
621
622
    /**
623
     * {@inheritdoc}
624
     */
625 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...
626 22
    {
627
        if (is_string($columns)) {
628 22
            $columns = [$columns]; // str to array
629 22
        }
630
        $foreignKeys = $this->getForeignKeys($tableName);
631
        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...
632
            if (isset($foreignKeys[$constraint])) {
633
                return !empty($foreignKeys[$constraint]);
634
            }
635
636
            return false;
637
        } else {
638
            foreach ($foreignKeys as $key) {
639
                if ($columns == $key['columns']) {
640 22
                    return true;
641
                }
642 22
            }
643 22
644 19
            return false;
645 19
        }
646 19
    }
647 19
648 22
    /**
649 22
     * Get an array of foreign keys from a particular table.
650
     *
651
     * @param string $tableName Table Name
652
     * @return array
653
     */
654 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...
655 15
    {
656
        $foreignKeys = [];
657 15
        $rows = $this->fetchAll(sprintf(
658 15
            "SELECT
659 15
              CONSTRAINT_NAME,
660 15
              TABLE_NAME,
661 15
              COLUMN_NAME,
662 15
              REFERENCED_TABLE_NAME,
663 15
              REFERENCED_COLUMN_NAME
664 15
            FROM information_schema.KEY_COLUMN_USAGE
665
            WHERE REFERENCED_TABLE_SCHEMA = DATABASE()
666
              AND REFERENCED_TABLE_NAME IS NOT NULL
667
              AND TABLE_NAME = '%s'
668
            ORDER BY POSITION_IN_UNIQUE_CONSTRAINT",
669 8
            $tableName
670
        ));
671 8
        foreach ($rows as $row) {
672 3
            $foreignKeys[$row['CONSTRAINT_NAME']]['table'] = $row['TABLE_NAME'];
673 3
            $foreignKeys[$row['CONSTRAINT_NAME']]['columns'][] = $row['COLUMN_NAME'];
674
            $foreignKeys[$row['CONSTRAINT_NAME']]['referenced_table'] = $row['REFERENCED_TABLE_NAME'];
675
            $foreignKeys[$row['CONSTRAINT_NAME']]['referenced_columns'][] = $row['REFERENCED_COLUMN_NAME'];
676 8
        }
677 8
678 8
        return $foreignKeys;
679 8
    }
680 8
681
    /**
682 8
     * {@inheritdoc}
683 8
     */
684 8
    public function addForeignKey(Table $table, ForeignKey $foreignKey)
685
    {
686 7
        $this->execute(
687 7
            sprintf(
688
                'ALTER TABLE %s ADD %s',
689
                $this->quoteTableName($table->getName()),
690
                $this->getForeignKeySqlDefinition($foreignKey)
691
            )
692
        );
693
    }
694
695 7
    /**
696 7
     * {@inheritdoc}
697
     */
698 7 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...
699 7
    {
700 7
        if (is_string($columns)) {
701 7
            $columns = [$columns]; // str to array
702 7
        }
703
704 7
        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...
705
            $this->execute(
706
                sprintf(
707
                    'ALTER TABLE %s DROP FOREIGN KEY %s',
708
                    $this->quoteTableName($tableName),
709 96
                    $constraint
710
                )
711
            );
712 96
713 87
            return;
714
        } else {
715 96
            foreach ($columns as $column) {
716 4
                $rows = $this->fetchAll(sprintf(
717
                    "SELECT
718 96
                        CONSTRAINT_NAME
719 9
                      FROM information_schema.KEY_COLUMN_USAGE
720
                      WHERE REFERENCED_TABLE_SCHEMA = DATABASE()
721
                        AND REFERENCED_TABLE_NAME IS NOT NULL
722 6
                        AND TABLE_NAME = '%s'
723 6
                        AND COLUMN_NAME = '%s'
724 6
                      ORDER BY POSITION_IN_UNIQUE_CONSTRAINT",
725 6
                    $tableName,
726 6
                    $column
727 6
                ));
728 6
                foreach ($rows as $row) {
729 6
                    $this->dropForeignKey($tableName, $columns, $row['CONSTRAINT_NAME']);
730
                }
731 5
            }
732
        }
733 5
    }
734
735 95
    /**
736 5
     * {@inheritdoc}
737
     */
738 95
    public function getSqlType($type, $limit = null)
739 3
    {
740
        switch ($type) {
741 95
            case static::PHINX_TYPE_FLOAT:
742 1
            case static::PHINX_TYPE_DECIMAL:
743
            case static::PHINX_TYPE_DATETIME:
744
            case static::PHINX_TYPE_TIMESTAMP:
745 1
            case static::PHINX_TYPE_TIME:
746 1
            case static::PHINX_TYPE_DATE:
747 1
            case static::PHINX_TYPE_ENUM:
748 1
            case static::PHINX_TYPE_SET:
749 1
            case static::PHINX_TYPE_JSON:
750 1
            // Geospatial database types
751 1
            case static::PHINX_TYPE_GEOMETRY:
752 1
            case static::PHINX_TYPE_POINT:
753
            case static::PHINX_TYPE_LINESTRING:
754 1
            case static::PHINX_TYPE_POLYGON:
755
                return ['name' => $type];
756 1
            case static::PHINX_TYPE_STRING:
757
                return ['name' => 'varchar', 'limit' => $limit ?: 255];
758 95
            case static::PHINX_TYPE_CHAR:
759 82
                return ['name' => 'char', 'limit' => $limit ?: 255];
760 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...
761
                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...
762 6
                    $sizes = [
763 6
                        // Order matters! Size must always be tested from longest to shortest!
764 6
                        'longtext' => static::TEXT_LONG,
765 6
                        'mediumtext' => static::TEXT_MEDIUM,
766 6
                        'text' => static::TEXT_REGULAR,
767 6
                        'tinytext' => static::TEXT_SMALL,
768
                    ];
769 6
                    foreach ($sizes as $name => $length) {
770 6
                        if ($limit >= $length) {
771 6
                            return ['name' => $name];
772 6
                        }
773 6
                    }
774 6
                }
775 6
776 2
                return ['name' => 'text'];
777 2
            case static::PHINX_TYPE_BINARY:
778 6
                return ['name' => 'binary', 'limit' => $limit ?: 255];
779
            case static::PHINX_TYPE_VARBINARY:
780 5
                return ['name' => 'varbinary', 'limit' => $limit ?: 255];
781 82 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...
782 76
                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...
783 76
                    $sizes = [
784 82
                        // Order matters! Size must always be tested from longest to shortest!
785
                        'longblob' => static::BLOB_LONG,
786 86
                        'mediumblob' => static::BLOB_MEDIUM,
787 82
                        'blob' => static::BLOB_REGULAR,
788
                        'tinyblob' => static::BLOB_SMALL,
789 86
                    ];
790 7
                    foreach ($sizes as $name => $length) {
791
                        if ($limit >= $length) {
792 84
                            return ['name' => $name];
793 5
                        }
794
                    }
795 83
                }
796 7
797
                return ['name' => 'blob'];
798 83
            case static::PHINX_TYPE_BIT:
799 80
                return ['name' => 'bit', 'limit' => $limit ?: 64];
800
            case static::PHINX_TYPE_INTEGER:
801 83
                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...
802 4
                    $sizes = [
803
                        // Order matters! Size must always be tested from longest to shortest!
804 83
                        'bigint' => static::INT_BIG,
805 4
                        'int' => static::INT_REGULAR,
806
                        'mediumint' => static::INT_MEDIUM,
807 83
                        'smallint' => static::INT_SMALL,
808 80
                        'tinyint' => static::INT_TINY,
809
                    ];
810 10
                    $limits = [
811 2
                        'int' => 11,
812
                        'bigint' => 20,
813 10
                    ];
814 10
                    foreach ($sizes as $name => $length) {
815 10
                        if ($limit >= $length) {
816 10
                            $def = ['name' => $name];
817 5
                            if (isset($limits[$name])) {
818 8
                                $def['limit'] = $limits[$name];
819 5
                            }
820
821 6
                            return $def;
822 4
                        }
823
                    }
824 2
                } 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...
825
                    $limit = 11;
826
                }
827
828
                return ['name' => 'int', 'limit' => $limit];
829
            case static::PHINX_TYPE_BIG_INTEGER:
830 2
                return ['name' => 'bigint', 'limit' => 20];
831
            case static::PHINX_TYPE_BOOLEAN:
832
                return ['name' => 'tinyint', 'limit' => 1];
833 2
            case static::PHINX_TYPE_UUID:
834 2
                return ['name' => 'char', 'limit' => 36];
835 2
            case static::TYPE_YEAR:
836
                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...
837
                    $limit = 4;
838
                }
839
840
                return ['name' => 'year', 'limit' => $limit];
841
            default:
842
                throw new \RuntimeException('The type: "' . $type . '" is not supported.');
843
        }
844
    }
845
846 17
    /**
847
     * Returns Phinx type by SQL type
848 17
     *
849 17
     * @param string $sqlTypeDef
850 1
     * @throws \RuntimeException
851
     * @internal param string $sqlType SQL type
852 16
     * @returns string Phinx type
853 16
     */
854 16
    public function getPhinxType($sqlTypeDef)
855 16
    {
856 14
        $matches = [];
857 14
        if (!preg_match('/^([\w]+)(\(([\d]+)*(,([\d]+))*\))*(.+)*$/', $sqlTypeDef, $matches)) {
858 16
            throw new \RuntimeException('Column type ' . $sqlTypeDef . ' is not supported');
859 4
        } else {
860 4
            $limit = null;
861 16
            $precision = null;
862 3
            $type = $matches[1];
863 3
            if (count($matches) > 2) {
864 3
                $limit = $matches[3] ? (int)$matches[3] : null;
865
            }
866 16
            if (count($matches) > 4) {
867 6
                $precision = (int)$matches[5];
868 6
            }
869 3 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...
870 3
                $type = static::PHINX_TYPE_BOOLEAN;
871 6
                $limit = null;
872 16
            }
873 5
            switch ($type) {
874 5
                case 'varchar':
875 1
                    $type = static::PHINX_TYPE_STRING;
876 1
                    if ($limit === 255) {
877 5
                        $limit = null;
878 2
                    }
879 2
                    break;
880 5 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...
881 16
                    $type = static::PHINX_TYPE_CHAR;
882 2
                    if ($limit === 255) {
883 2
                        $limit = null;
884 2
                    }
885 16
                    if ($limit === 36) {
886 2
                        $type = static::PHINX_TYPE_UUID;
887 2
                    }
888 2
                    break;
889 16
                case 'tinyint':
890 2
                    $type = static::PHINX_TYPE_INTEGER;
891 2
                    $limit = static::INT_TINY;
892 2
                    break;
893 16
                case 'smallint':
894 15
                    $type = static::PHINX_TYPE_INTEGER;
895 15
                    $limit = static::INT_SMALL;
896 12
                    break;
897 12
                case 'mediumint':
898 15
                    $type = static::PHINX_TYPE_INTEGER;
899 11
                    $limit = static::INT_MEDIUM;
900 6
                    break;
901 4
                case 'int':
902 4
                    $type = static::PHINX_TYPE_INTEGER;
903 6
                    if ($limit === 11) {
904 6
                        $limit = null;
905 10
                    }
906 2
                    break;
907 2
                case 'bigint':
908 10
                    if ($limit === 20) {
909 1
                        $limit = null;
910 1
                    }
911 1
                    $type = static::PHINX_TYPE_BIG_INTEGER;
912 10
                    break;
913 1
                case 'bit':
914 1
                    $type = static::PHINX_TYPE_BIT;
915 1
                    if ($limit === 64) {
916 10
                        $limit = null;
917 1
                    }
918 1
                    break;
919 1
                case 'blob':
920 10
                    $type = static::PHINX_TYPE_BINARY;
921 2
                    break;
922 2
                case 'tinyblob':
923 2
                    $type = static::PHINX_TYPE_BINARY;
924 9
                    $limit = static::BLOB_TINY;
925 2
                    break;
926 2
                case 'mediumblob':
927 2
                    $type = static::PHINX_TYPE_BINARY;
928 8
                    $limit = static::BLOB_MEDIUM;
929 2
                    break;
930 2
                case 'longblob':
931 2
                    $type = static::PHINX_TYPE_BINARY;
932
                    $limit = static::BLOB_LONG;
933
                    break;
934
                case 'tinytext':
935 16
                    $type = static::PHINX_TYPE_TEXT;
936
                    $limit = static::TEXT_TINY;
937
                    break;
938 15
                case 'mediumtext':
939 15
                    $type = static::PHINX_TYPE_TEXT;
940
                    $limit = static::TEXT_MEDIUM;
941 15
                    break;
942
                case 'longtext':
943 15
                    $type = static::PHINX_TYPE_TEXT;
944 3
                    $limit = static::TEXT_LONG;
945 3
                    break;
946
            }
947 15
948
            // Call this to check if parsed type is supported.
949
            $this->getSqlType($type, $limit);
950
951
            $phinxType = [
952
                'name' => $type,
953
                'limit' => $limit,
954 83
                'precision' => $precision
955
            ];
956 83
957
            if (static::PHINX_TYPE_ENUM == $type) {
958 83
                $phinxType['values'] = explode("','", trim($matches[6], "()'"));
959 1
            }
960 1
961 82
            return $phinxType;
962
        }
963 83
    }
964
965
    /**
966
     * {@inheritdoc}
967
     */
968 4
    public function createDatabase($name, $options = [])
969
    {
970 4
        $charset = isset($options['charset']) ? $options['charset'] : 'utf8';
971 4
972 4 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...
973
            $this->execute(sprintf('CREATE DATABASE `%s` DEFAULT CHARACTER SET `%s` COLLATE `%s`', $name, $charset, $options['collation']));
974 4
        } else {
975 4
            $this->execute(sprintf('CREATE DATABASE `%s` DEFAULT CHARACTER SET `%s`', $name, $charset));
976
        }
977 4
    }
978 3
979 3
    /**
980
     * {@inheritdoc}
981 3
     */
982
    public function hasDatabase($name)
983 3
    {
984
        $rows = $this->fetchAll(
985
            sprintf(
986
                'SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = \'%s\'',
987
                $name
988
            )
989 81
        );
990
991 81
        foreach ($rows as $row) {
992 81
            if (!empty($row)) {
993
                return true;
994
            }
995
        }
996
997
        return false;
998
    }
999
1000 89
    /**
1001
     * {@inheritdoc}
1002 89
     */
1003
    public function dropDatabase($name)
1004 89
    {
1005 89
        $this->execute(sprintf('DROP DATABASE IF EXISTS `%s`', $name));
1006 89
    }
1007 2
1008 89
    /**
1009 86
     * Gets the MySQL Column Definition for a Column object.
1010 86
     *
1011 89
     * @param \Phinx\Db\Table\Column $column Column
1012 5
     * @return string
1013 5
     */
1014 89
    protected function getColumnSqlDefinition(Column $column)
1015 89
    {
1016 89
        $sqlType = $this->getSqlType($column->getType(), $column->getLimit());
1017 89
1018 89
        $def = '';
1019 89
        $def .= strtoupper($sqlType['name']);
1020
        if ($column->getPrecision() && $column->getScale()) {
1021 89
            $def .= '(' . $column->getPrecision() . ',' . $column->getScale() . ')';
1022 2
        } elseif (isset($sqlType['limit'])) {
1023 2
            $def .= '(' . $sqlType['limit'] . ')';
1024
        }
1025 89 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...
1026 1
            $def .= "('" . implode("', '", $values) . "')";
1027 1
        }
1028
        $def .= $column->getEncoding() ? ' CHARACTER SET ' . $column->getEncoding() : '';
1029 89
        $def .= $column->getCollation() ? ' COLLATE ' . $column->getCollation() : '';
1030
        $def .= (!$column->isSigned() && isset($this->signedColumnTypes[$column->getType()])) ? ' unsigned' : '';
1031
        $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...
1032
        $def .= ($column->isIdentity()) ? ' AUTO_INCREMENT' : '';
1033
        $def .= $this->getDefaultValueDefinition($column->getDefault());
1034
1035
        if ($column->getComment()) {
1036
            $def .= ' COMMENT ' . $this->getConnection()->quote($column->getComment());
1037
        }
1038 16
1039
        if ($column->getUpdate()) {
1040 16
            $def .= ' ON UPDATE ' . $column->getUpdate();
1041 16
        }
1042 16
1043 2
        return $def;
1044 2
    }
1045
1046 16
    /**
1047 5
     * Gets the MySQL Index Definition for an Index object.
1048 5
     *
1049
     * @param \Phinx\Db\Table\Index $index Index
1050 16
     * @return string
1051 1
     */
1052 1
    protected function getIndexSqlDefinition(Index $index)
1053
    {
1054 16
        $def = '';
1055
        $limit = '';
1056 16
        if ($index->getLimit()) {
1057 5
            $limit = '(' . $index->getLimit() . ')';
1058 5
        }
1059
1060 16
        if ($index->getType() == Index::UNIQUE) {
1061
            $def .= ' UNIQUE';
1062 16
        }
1063
1064
        if ($index->getType() == Index::FULLTEXT) {
1065
            $def .= ' FULLTEXT';
1066
        }
1067
1068
        $def .= ' KEY';
1069
1070
        if (is_string($index->getName())) {
1071 17
            $def .= ' `' . $index->getName() . '`';
1072
        }
1073 17
1074 17
        $def .= ' (`' . implode('`,`', $index->getColumns()) . '`' . $limit . ')';
1075 5
1076 5
        return $def;
1077 17
    }
1078 17
1079 17
    /**
1080 17
     * Gets the MySQL Foreign Key Definition for an ForeignKey object.
1081 17
     *
1082 17
     * @param \Phinx\Db\Table\ForeignKey $foreignKey
1083 17
     * @return string
1084 17
     */
1085 17 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...
1086 17
    {
1087 17
        $def = '';
1088 2
        if ($foreignKey->getConstraint()) {
1089 2
            $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...
1090 17
        }
1091 2
        $columnNames = [];
1092 2
        foreach ($foreignKey->getColumns() as $column) {
1093 17
            $columnNames[] = $this->quoteColumnName($column);
1094
        }
1095
        $def .= ' FOREIGN KEY (' . implode(',', $columnNames) . ')';
1096
        $refColumnNames = [];
1097
        foreach ($foreignKey->getReferencedColumns() as $column) {
1098
            $refColumnNames[] = $this->quoteColumnName($column);
1099
        }
1100
        $def .= ' REFERENCES ' . $this->quoteTableName($foreignKey->getReferencedTable()->getName()) . ' (' . implode(',', $refColumnNames) . ')';
1101
        if ($foreignKey->getOnDelete()) {
1102 2
            $def .= ' ON DELETE ' . $foreignKey->getOnDelete();
1103
        }
1104 2
        if ($foreignKey->getOnUpdate()) {
1105
            $def .= ' ON UPDATE ' . $foreignKey->getOnUpdate();
1106
        }
1107 2
1108
        return $def;
1109
    }
1110
1111 2
    /**
1112 2
     * Describes a database table. This is a MySQL adapter specific method.
1113
     *
1114 2
     * @param string $tableName Table name
1115
     * @return array
1116 2
     */
1117
    public function describeTable($tableName)
1118
    {
1119
        $options = $this->getOptions();
1120
1121
        // mysql specific
1122
        $sql = sprintf(
1123 85
            "SELECT *
1124
             FROM information_schema.tables
1125 85
             WHERE table_schema = '%s'
1126
             AND table_name = '%s'",
1127
            $options['name'],
1128
            $tableName
1129
        );
1130
1131
        return $this->fetchRow($sql);
1132
    }
1133
1134
    /**
1135
     * Returns MySQL column types (inherited and MySQL specified).
1136
     * @return array
1137
     */
1138
    public function getColumnTypes()
1139
    {
1140
        return array_merge(parent::getColumnTypes(), ['enum', 'set', 'year', 'json']);
1141
    }
1142
}
1143