Completed
Pull Request — master (#1175)
by
unknown
01:55
created

MysqlAdapter::getDefaultValueDefinition()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 9
Code Lines 6

Duplication

Lines 9
Ratio 100 %

Code Coverage

Tests 7
CRAP Score 5

Importance

Changes 0
Metric Value
dl 9
loc 9
ccs 7
cts 7
cp 1
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 6
nc 6
nop 1
crap 5
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\Index;
34
use Phinx\Db\Table\ForeignKey;
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 TYPE_YEAR   = 'year';
66
67
    /**
68
     * {@inheritdoc}
69
     */
70 80
    public function connect()
71
    {
72 80
        if ($this->connection === null) {
73 80
            if (!class_exists('PDO') || !in_array('mysql', \PDO::getAvailableDrivers(), true)) {
74
                // @codeCoverageIgnoreStart
75
                throw new \RuntimeException('You need to enable the PDO_Mysql extension for Phinx to run properly.');
76
                // @codeCoverageIgnoreEnd
77
            }
78
79 80
            $db = null;
80 80
            $options = $this->getOptions();
81
82 80
            $dsn = 'mysql:';
83
84 80
            if (!empty($options['unix_socket'])) {
85
                // use socket connection
86
                $dsn .= 'unix_socket=' . $options['unix_socket'];
87
            } else {
88
                // use network connection
89 80
                $dsn .= 'host=' . $options['host'];
90 80
                if (!empty($options['port'])) {
91 80
                    $dsn .= ';port=' . $options['port'];
92 80
                }
93
            }
94
95 80
            $dsn .= ';dbname=' . $options['name'];
96
97
            // charset support
98 80
            if (!empty($options['charset'])) {
99
                $dsn .= ';charset=' . $options['charset'];
100
            }
101
102 80
            $driverOptions = [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION];
103
104
            // support arbitrary \PDO::MYSQL_ATTR_* driver options and pass them to PDO
105
            // http://php.net/manual/en/ref.pdo-mysql.php#pdo-mysql.constants
106 80 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...
107 80
                if (strpos($key, 'mysql_attr_') === 0) {
108
                    $driverOptions[constant('\PDO::' . strtoupper($key))] = $option;
109
                }
110 80
            }
111
112
            try {
113 80
                $db = new \PDO($dsn, $options['user'], $options['pass'], $driverOptions);
114 80
            } catch (\PDOException $exception) {
115 1
                throw new \InvalidArgumentException(sprintf(
116 1
                    'There was a problem connecting to the database: %s',
117 1
                    $exception->getMessage()
118 1
                ));
119
            }
120
121 80
            $this->setConnection($db);
122 80
        }
123 80
    }
124
125
    /**
126
     * {@inheritdoc}
127
     */
128 81
    public function disconnect()
129
    {
130 81
        $this->connection = null;
131 81
    }
132
133
    /**
134
     * {@inheritdoc}
135
     */
136 6
    public function hasTransactions()
137
    {
138 6
        return true;
139
    }
140
141
    /**
142
     * {@inheritdoc}
143
     */
144 6
    public function beginTransaction()
145
    {
146 6
        $this->execute('START TRANSACTION');
147 6
    }
148
149
    /**
150
     * {@inheritdoc}
151
     */
152 6
    public function commitTransaction()
153
    {
154 6
        $this->execute('COMMIT');
155 6
    }
156
157
    /**
158
     * {@inheritdoc}
159
     */
160 1
    public function rollbackTransaction()
161
    {
162 1
        $this->execute('ROLLBACK');
163 1
    }
164
165
    /**
166
     * {@inheritdoc}
167
     */
168 112
    public function quoteTableName($tableName)
169
    {
170 112
        return str_replace('.', '`.`', $this->quoteColumnName($tableName));
171
    }
172
173
    /**
174
     * {@inheritdoc}
175
     */
176 112
    public function quoteColumnName($columnName)
177
    {
178 112
        return '`' . str_replace('`', '``', $columnName) . '`';
179
    }
180
181
    /**
182
     * {@inheritdoc}
183
     */
184 82 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...
185
    {
186 82
        $options = $this->getOptions();
187
188 82
        $exists = $this->fetchRow(sprintf(
189
            "SELECT TABLE_NAME
190
            FROM INFORMATION_SCHEMA.TABLES
191 82
            WHERE TABLE_SCHEMA = '%s' AND TABLE_NAME = '%s'",
192 82
            $options['name'],
193
            $tableName
194 82
        ));
195
196 82
        return !empty($exists);
197
    }
198
199
    /**
200
     * {@inheritdoc}
201
     */
202 82
    public function createTable(Table $table)
203
    {
204
        // This method is based on the MySQL docs here: http://dev.mysql.com/doc/refman/5.1/en/create-index.html
205
        $defaultOptions = [
206 82
            'engine' => 'InnoDB',
207
            'collation' => 'utf8_general_ci'
208 82
        ];
209 82
        $options = array_merge($defaultOptions, $table->getOptions());
210
211
        // Add the default primary key
212 82
        $columns = $table->getPendingColumns();
213 82
        if (!isset($options['id']) || (isset($options['id']) && $options['id'] === true)) {
214 68
            $column = new Column();
215 68
            $column->setName('id')
216 68
                   ->setType('integer')
217 68
                   ->setSigned(isset($options['signed']) ? $options['signed'] : true)
218 68
                   ->setIdentity(true);
219
220 68
            array_unshift($columns, $column);
221 68
            $options['primary_key'] = 'id';
222 82
        } elseif (isset($options['id']) && is_string($options['id'])) {
223
            // Handle id => "field_name" to support AUTO_INCREMENT
224 2
            $column = new Column();
225 2
            $column->setName($options['id'])
226 2
                   ->setType('integer')
227 2
                   ->setIdentity(true);
228
229 2
            array_unshift($columns, $column);
230 2
            $options['primary_key'] = $options['id'];
231 2
        }
232
233
        // TODO - process table options like collation etc
234
235
        // process table engine (default to InnoDB)
236 82
        $optionsStr = 'ENGINE = InnoDB';
237 82
        if (isset($options['engine'])) {
238 82
            $optionsStr = sprintf('ENGINE = %s', $options['engine']);
239 82
        }
240
241
        // process table collation
242 82
        if (isset($options['collation'])) {
243 82
            $charset = explode('_', $options['collation']);
244 82
            $optionsStr .= sprintf(' CHARACTER SET %s', $charset[0]);
245 82
            $optionsStr .= sprintf(' COLLATE %s', $options['collation']);
246 82
        }
247
248
        // set the table comment
249 82
        if (isset($options['comment'])) {
250 2
            $optionsStr .= sprintf(" COMMENT=%s ", $this->getConnection()->quote($options['comment']));
251 2
        }
252
253 82
        $sql = 'CREATE TABLE ';
254 82
        $sql .= $this->quoteTableName($table->getName()) . ' (';
255 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...
256 82
            $sql .= $this->quoteColumnName($column->getName()) . ' ' . $this->getColumnSqlDefinition($column) . ', ';
257 82
        }
258
259
        // set the primary key(s)
260 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...
261 82
            $sql = rtrim($sql);
262 82
            $sql .= ' PRIMARY KEY (';
263 82
            if (is_string($options['primary_key'])) {       // handle primary_key => 'id'
264 81
                $sql .= $this->quoteColumnName($options['primary_key']);
265 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...
266
                // PHP 5.4 will allow access of $this, so we can call quoteColumnName() directly in the
267
                // anonymous function, but for now just hard-code the adapter quotes
268 2
                $sql .= implode(
269 2
                    ',',
270 2
                    array_map(
271 2
                        function ($v) {
272 2
                            return '`' . $v . '`';
273 2
                        },
274 2
                        $options['primary_key']
275 2
                    )
276 2
                );
277 2
            }
278 82
            $sql .= ')';
279 82
        } else {
280 1
            $sql = substr(rtrim($sql), 0, -1);              // no primary keys
281
        }
282
283
        // set the indexes
284 82
        $indexes = $table->getIndexes();
285 82
        foreach ($indexes as $index) {
286 10
            $sql .= ', ' . $this->getIndexSqlDefinition($index);
287 82
        }
288
289
        // set the foreign keys
290 82
        $foreignKeys = $table->getForeignKeys();
291 82
        foreach ($foreignKeys as $foreignKey) {
292 2
            $sql .= ', ' . $this->getForeignKeySqlDefinition($foreignKey);
293 82
        }
294
295 82
        $sql .= ') ' . $optionsStr;
296 82
        $sql = rtrim($sql) . ';';
297
298
        // execute the sql
299 82
        $this->execute($sql);
300 82
    }
301
302
    /**
303
     * {@inheritdoc}
304
     */
305 5
    public function renameTable($tableName, $newTableName)
306
    {
307 5
        $this->execute(sprintf('RENAME TABLE %s TO %s', $this->quoteTableName($tableName), $this->quoteTableName($newTableName)));
308 5
    }
309
310
    /**
311
     * {@inheritdoc}
312
     */
313 5
    public function dropTable($tableName)
314
    {
315 5
        $this->execute(sprintf('DROP TABLE %s', $this->quoteTableName($tableName)));
316 5
    }
317
318
    /**
319
     * {@inheritdoc}
320
     */
321 1
    public function truncateTable($tableName)
322
    {
323 1
        $sql = sprintf(
324 1
            'TRUNCATE TABLE %s',
325 1
            $this->quoteTableName($tableName)
326 1
        );
327
328 1
        $this->execute($sql);
329 1
    }
330
331
    /**
332
     * {@inheritdoc}
333
     */
334 12
    public function getColumns($tableName)
335
    {
336 12
        $columns = [];
337 12
        $rows = $this->fetchAll(sprintf('SHOW COLUMNS FROM %s', $this->quoteTableName($tableName)));
338 12
        foreach ($rows as $columnInfo) {
339 12
            $phinxType = $this->getPhinxType($columnInfo['Type']);
340
341 12
            $column = new Column();
342 12
            $column->setName($columnInfo['Field'])
343 12
                   ->setNull($columnInfo['Null'] !== 'NO')
344 12
                   ->setDefault($columnInfo['Default'])
345 12
                   ->setType($phinxType['name'])
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
                return;
421 5
            }
422 5
        }
423 1
424 1
        throw new \InvalidArgumentException(sprintf(
425 5
            'The specified column doesn\'t exist: '
426
            . $columnName
427 5
        ));
428 5
    }
429 5
430 5
    /**
431 5
     * {@inheritdoc}
432 5
     */
433 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...
434 5
    {
435 5
        $after = $newColumn->getAfter() ? ' AFTER ' . $this->quoteColumnName($newColumn->getAfter()) : '';
436 5
        $this->execute(
437
            sprintf(
438 6
                'ALTER TABLE %s CHANGE %s %s %s%s',
439
                $this->quoteTableName($tableName),
440 2
                $this->quoteColumnName($columnName),
441
                $this->quoteColumnName($newColumn->getName()),
442
                $this->getColumnSqlDefinition($newColumn),
443 2
                $after
444
            )
445
        );
446
    }
447
448
    /**
449 5
     * {@inheritdoc}
450
     */
451 5
    public function dropColumn($tableName, $columnName)
452 5
    {
453 5
        $this->execute(
454 5
            sprintf(
455 5
                'ALTER TABLE %s DROP COLUMN %s',
456 5
                $this->quoteTableName($tableName),
457 5
                $this->quoteColumnName($columnName)
458 5
            )
459
        );
460 5
    }
461 5
462 5
    /**
463
     * Get an array of indexes from a particular table.
464
     *
465
     * @param string $tableName Table Name
466
     * @return array
467 5
     */
468 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...
469 5
    {
470 5
        $indexes = [];
471 5
        $rows = $this->fetchAll(sprintf('SHOW INDEXES FROM %s', $this->quoteTableName($tableName)));
472 5
        foreach ($rows as $row) {
473 5
            if (!isset($indexes[$row['Key_name']])) {
474 5
                $indexes[$row['Key_name']] = ['columns' => []];
475 5
            }
476 5
            $indexes[$row['Key_name']]['columns'][] = strtolower($row['Column_name']);
477
        }
478
        return $indexes;
479
    }
480
481
    /**
482
     * {@inheritdoc}
483
     */
484 19
    public function hasIndex($tableName, $columns)
485
    {
486 19
        if (is_string($columns)) {
487 19
            $columns = [$columns]; // str to array
488 19
        }
489 18
490 18
        $columns = array_map('strtolower', $columns);
491 18
        $indexes = $this->getIndexes($tableName);
492 18
493 19
        foreach ($indexes as $index) {
494 19
            if ($columns == $index['columns']) {
495
                return true;
496
            }
497
        }
498
499
        return false;
500 14
    }
501
502 14
    /**
503 6
     * {@inheritdoc}
504 6
     */
505 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...
506 14
    {
507 14
        $indexes = $this->getIndexes($tableName);
508
509 14
        foreach ($indexes as $name => $index) {
510 14
            if ($name === $indexName) {
511 12
                return true;
512
            }
513 13
        }
514
515 11
        return false;
516
    }
517
518
    /**
519
     * {@inheritdoc}
520
     */
521 1
    public function addIndex(Table $table, Index $index)
522
    {
523 1
        $this->execute(
524
            sprintf(
525 1
                'ALTER TABLE %s ADD %s',
526 1
                $this->quoteTableName($table->getName()),
527 1
                $this->getIndexSqlDefinition($index)
528
            )
529 1
        );
530
    }
531
532
    /**
533
     * {@inheritdoc}
534
     */
535
    public function dropIndex($tableName, $columns)
536
    {
537 4
        if (is_string($columns)) {
538
            $columns = [$columns]; // str to array
539 4
        }
540 4
541 4
        $indexes = $this->getIndexes($tableName);
542 4
        $columns = array_map('strtolower', $columns);
543 4
544 4
        foreach ($indexes as $indexName => $index) {
545 4
            if ($columns == $index['columns']) {
546 4
                $this->execute(
547
                    sprintf(
548
                        'ALTER TABLE %s DROP INDEX %s',
549
                        $this->quoteTableName($tableName),
550
                        $this->quoteColumnName($indexName)
551 3
                    )
552
                );
553 3
                return;
554 2
            }
555 2
        }
556
    }
557 3
558 3
    /**
559
     * {@inheritdoc}
560 3
     */
561 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...
562 3
    {
563 3
        $indexes = $this->getIndexes($tableName);
564 3
565 3
        foreach ($indexes as $name => $index) {
566 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...
567 3
            if ($name === $indexName) {
568 3
                $this->execute(
569 3
                    sprintf(
570
                        'ALTER TABLE %s DROP INDEX %s',
571 3
                        $this->quoteTableName($tableName),
572 1
                        $this->quoteColumnName($indexName)
573
                    )
574
                );
575
                return;
576
            }
577 2
        }
578
    }
579 2
580
    /**
581 2
     * {@inheritdoc}
582
     */
583 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...
584 2
    {
585 2
        if (is_string($columns)) {
586 2
            $columns = [$columns]; // str to array
587 2
        }
588 2
        $foreignKeys = $this->getForeignKeys($tableName);
589 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...
590 2
            if (isset($foreignKeys[$constraint])) {
591 2
                return !empty($foreignKeys[$constraint]);
592
            }
593 2
            return false;
594
        } else {
595
            foreach ($foreignKeys as $key) {
596
                if ($columns == $key['columns']) {
597
                    return true;
598
                }
599 21
            }
600
            return false;
601 21
        }
602 5
    }
603 5
604 21
    /**
605 21
     * Get an array of foreign keys from a particular table.
606 6
     *
607 4
     * @param string $tableName Table Name
608
     * @return array
609 4
     */
610 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...
611 15
    {
612 12
        $foreignKeys = [];
613 10
        $rows = $this->fetchAll(sprintf(
614
            "SELECT
615 11
              CONSTRAINT_NAME,
616 11
              TABLE_NAME,
617
              COLUMN_NAME,
618
              REFERENCED_TABLE_NAME,
619
              REFERENCED_COLUMN_NAME
620
            FROM information_schema.KEY_COLUMN_USAGE
621
            WHERE REFERENCED_TABLE_SCHEMA = DATABASE()
622
              AND REFERENCED_TABLE_NAME IS NOT NULL
623
              AND TABLE_NAME = '%s'
624
            ORDER BY POSITION_IN_UNIQUE_CONSTRAINT",
625
            $tableName
626 22
        ));
627
        foreach ($rows as $row) {
628 22
            $foreignKeys[$row['CONSTRAINT_NAME']]['table'] = $row['TABLE_NAME'];
629 22
            $foreignKeys[$row['CONSTRAINT_NAME']]['columns'][] = $row['COLUMN_NAME'];
630
            $foreignKeys[$row['CONSTRAINT_NAME']]['referenced_table'] = $row['REFERENCED_TABLE_NAME'];
631
            $foreignKeys[$row['CONSTRAINT_NAME']]['referenced_columns'][] = $row['REFERENCED_COLUMN_NAME'];
632
        }
633
        return $foreignKeys;
634
    }
635
636
    /**
637
     * {@inheritdoc}
638
     */
639
    public function addForeignKey(Table $table, ForeignKey $foreignKey)
640 22
    {
641
        $this->execute(
642 22
            sprintf(
643 22
                'ALTER TABLE %s ADD %s',
644 19
                $this->quoteTableName($table->getName()),
645 19
                $this->getForeignKeySqlDefinition($foreignKey)
646 19
            )
647 19
        );
648 22
    }
649 22
650
    /**
651
     * {@inheritdoc}
652
     */
653 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...
654
    {
655 15
        if (is_string($columns)) {
656
            $columns = [$columns]; // str to array
657 15
        }
658 15
659 15
660 15
        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...
661 15
            $this->execute(
662 15
                sprintf(
663 15
                    'ALTER TABLE %s DROP FOREIGN KEY %s',
664 15
                    $this->quoteTableName($tableName),
665
                    $constraint
666
                )
667
            );
668
            return;
669 8
        } else {
670
            foreach ($columns as $column) {
671 8
                $rows = $this->fetchAll(sprintf(
672 3
                    "SELECT
673 3
                        CONSTRAINT_NAME
674
                      FROM information_schema.KEY_COLUMN_USAGE
675
                      WHERE REFERENCED_TABLE_SCHEMA = DATABASE()
676 8
                        AND REFERENCED_TABLE_NAME IS NOT NULL
677 8
                        AND TABLE_NAME = '%s'
678 8
                        AND COLUMN_NAME = '%s'
679 8
                      ORDER BY POSITION_IN_UNIQUE_CONSTRAINT",
680 8
                    $tableName,
681
                    $column
682 8
                ));
683 8
                foreach ($rows as $row) {
684 8
                    $this->dropForeignKey($tableName, $columns, $row['CONSTRAINT_NAME']);
685
                }
686 7
            }
687 7
        }
688
    }
689
690
    /**
691
     * {@inheritdoc}
692
     */
693
    public function getSqlType($type, $limit = null)
694
    {
695 7
        switch ($type) {
696 7
            case static::PHINX_TYPE_STRING:
697
                return ['name' => 'varchar', 'limit' => $limit ? $limit : 255];
698 7
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
699 7
            case static::PHINX_TYPE_CHAR:
700 7
                return ['name' => 'char', 'limit' => $limit ? $limit : 255];
701 7
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
702 7 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...
703
                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...
704 7
                    $sizes = [
705
                        // Order matters! Size must always be tested from longest to shortest!
706
                        'longtext'   => static::TEXT_LONG,
707
                        'mediumtext' => static::TEXT_MEDIUM,
708
                        'text'       => static::TEXT_REGULAR,
709 96
                        'tinytext'   => static::TEXT_SMALL,
710
                    ];
711
                    foreach ($sizes as $name => $length) {
712 96
                        if ($limit >= $length) {
713 87
                            return ['name' => $name];
714
                        }
715 96
                    }
716 4
                }
717
                return ['name' => 'text'];
718 96
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
719 9
            case static::PHINX_TYPE_BINARY:
720
                return ['name' => 'binary', 'limit' => $limit ? $limit : 255];
721
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
722 6
            case static::PHINX_TYPE_VARBINARY:
723 6
                return ['name' => 'varbinary', 'limit' => $limit ? $limit : 255];
724 6
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
725 6 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...
726 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...
727 6
                    $sizes = [
728 6
                        // Order matters! Size must always be tested from longest to shortest!
729 6
                        'longblob'   => static::BLOB_LONG,
730
                        'mediumblob' => static::BLOB_MEDIUM,
731 5
                        'blob'       => static::BLOB_REGULAR,
732
                        'tinyblob'   => static::BLOB_SMALL,
733 5
                    ];
734
                    foreach ($sizes as $name => $length) {
735 95
                        if ($limit >= $length) {
736 5
                            return ['name' => $name];
737
                        }
738 95
                    }
739 3
                }
740
                return ['name' => 'blob'];
741 95
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
742 1
            case static::PHINX_TYPE_INTEGER:
743
                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...
744
                    $sizes = [
745 1
                        // Order matters! Size must always be tested from longest to shortest!
746 1
                        'bigint'    => static::INT_BIG,
747 1
                        'int'       => static::INT_REGULAR,
748 1
                        'mediumint' => static::INT_MEDIUM,
749 1
                        'smallint'  => static::INT_SMALL,
750 1
                        'tinyint'   => static::INT_TINY,
751 1
                    ];
752 1
                    $limits = [
753
                        'int'    => 11,
754 1
                        'bigint' => 20,
755
                    ];
756 1
                    foreach ($sizes as $name => $length) {
757
                        if ($limit >= $length) {
758 95
                            $def = ['name' => $name];
759 82
                            if (isset($limits[$name])) {
760
                                $def['limit'] = $limits[$name];
761
                            }
762 6
                            return $def;
763 6
                        }
764 6
                    }
765 6
                } 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...
766 6
                    $limit = 11;
767 6
                }
768
                return ['name' => 'int', 'limit' => $limit];
769 6
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
770 6
            case static::PHINX_TYPE_BIG_INTEGER:
771 6
                return ['name' => 'bigint', 'limit' => 20];
772 6
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
773 6
            case static::PHINX_TYPE_FLOAT:
774 6
                return ['name' => 'float'];
775 6
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
776 2
            case static::PHINX_TYPE_DECIMAL:
777 2
                return ['name' => 'decimal'];
778 6
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
779
            case static::PHINX_TYPE_DATETIME:
780 5
                return ['name' => 'datetime'];
781 82
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
782 76
            case static::PHINX_TYPE_TIMESTAMP:
783 76
                return ['name' => 'timestamp'];
784 82
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
785
            case static::PHINX_TYPE_TIME:
786 86
                return ['name' => 'time'];
787 82
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
788
            case static::PHINX_TYPE_DATE:
789 86
                return ['name' => 'date'];
790 7
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
791
            case static::PHINX_TYPE_BOOLEAN:
792 84
                return ['name' => 'tinyint', 'limit' => 1];
793 5
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
794
            case static::PHINX_TYPE_UUID:
795 83
                return ['name' => 'char', 'limit' => 36];
796 7
            // Geospatial database types
797
            case static::PHINX_TYPE_GEOMETRY:
798 83
            case static::PHINX_TYPE_POINT:
799 80
            case static::PHINX_TYPE_LINESTRING:
800
            case static::PHINX_TYPE_POLYGON:
801 83
                return ['name' => $type];
802 4
            case static::PHINX_TYPE_ENUM:
803
                return ['name' => 'enum'];
804 83
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
805 4
            case static::PHINX_TYPE_SET:
806
                return ['name' => 'set'];
807 83
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
808 80
            case static::TYPE_YEAR:
809
                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...
810 10
                    $limit = 4;
811 2
                }
812
                return ['name' => 'year', 'limit' => $limit];
813 10
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
814 10
            case static::PHINX_TYPE_JSON:
815 10
                return ['name' => 'json'];
816 10
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
817 5
            default:
818 8
                throw new \RuntimeException('The type: "' . $type . '" is not supported.');
819 5
        }
820
    }
821 6
822 4
    /**
823
     * Returns Phinx type by SQL type
824 2
     *
825
     * @param string $sqlTypeDef
826
     * @throws \RuntimeException
827
     * @internal param string $sqlType SQL type
828
     * @returns string Phinx type
829
     */
830 2
    public function getPhinxType($sqlTypeDef)
831
    {
832
        $matches = [];
833 2
        if (!preg_match('/^([\w]+)(\(([\d]+)*(,([\d]+))*\))*(.+)*$/', $sqlTypeDef, $matches)) {
834 2
            throw new \RuntimeException('Column type ' . $sqlTypeDef . ' is not supported');
835 2
        } else {
836
            $limit = null;
837
            $precision = null;
838
            $type = $matches[1];
839 View Code Duplication
            if (count($matches) > 2) {
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...
840
                $limit = $matches[3] ? (int) $matches[3] : null;
841
            }
842
            if (count($matches) > 4) {
843
                $precision = (int) $matches[5];
844
            }
845 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...
846 17
                $type = static::PHINX_TYPE_BOOLEAN;
847
                $limit = null;
848 17
            }
849 17
            switch ($type) {
850 1
                case 'varchar':
851
                    $type = static::PHINX_TYPE_STRING;
852 16
                    if ($limit === 255) {
853 16
                        $limit = null;
854 16
                    }
855 16
                    break;
856 14 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...
857 14
                    $type = static::PHINX_TYPE_CHAR;
858 16
                    if ($limit === 255) {
859 4
                        $limit = null;
860 4
                    }
861 16
                    if ($limit === 36) {
862 3
                        $type = static::PHINX_TYPE_UUID;
863 3
                    }
864 3
                    break;
865
                case 'tinyint':
866 16
                    $type  = static::PHINX_TYPE_INTEGER;
867 6
                    $limit = static::INT_TINY;
868 6
                    break;
869 3
                case 'smallint':
870 3
                    $type  = static::PHINX_TYPE_INTEGER;
871 6
                    $limit = static::INT_SMALL;
872 16
                    break;
873 5
                case 'mediumint':
874 5
                    $type  = static::PHINX_TYPE_INTEGER;
875 1
                    $limit = static::INT_MEDIUM;
876 1
                    break;
877 5
                case 'int':
878 2
                    $type = static::PHINX_TYPE_INTEGER;
879 2
                    if ($limit === 11) {
880 5
                        $limit = null;
881 16
                    }
882 2
                    break;
883 2
                case 'bigint':
884 2
                    if ($limit === 20) {
885 16
                        $limit = null;
886 2
                    }
887 2
                    $type = static::PHINX_TYPE_BIG_INTEGER;
888 2
                    break;
889 16
                case 'blob':
890 2
                    $type = static::PHINX_TYPE_BINARY;
891 2
                    break;
892 2
                case 'tinyblob':
893 16
                    $type  = static::PHINX_TYPE_BINARY;
894 15
                    $limit = static::BLOB_TINY;
895 15
                    break;
896 12
                case 'mediumblob':
897 12
                    $type  = static::PHINX_TYPE_BINARY;
898 15
                    $limit = static::BLOB_MEDIUM;
899 11
                    break;
900 6
                case 'longblob':
901 4
                    $type  = static::PHINX_TYPE_BINARY;
902 4
                    $limit = static::BLOB_LONG;
903 6
                    break;
904 6
                case 'tinytext':
905 10
                    $type  = static::PHINX_TYPE_TEXT;
906 2
                    $limit = static::TEXT_TINY;
907 2
                    break;
908 10
                case 'mediumtext':
909 1
                    $type  = static::PHINX_TYPE_TEXT;
910 1
                    $limit = static::TEXT_MEDIUM;
911 1
                    break;
912 10
                case 'longtext':
913 1
                    $type  = static::PHINX_TYPE_TEXT;
914 1
                    $limit = static::TEXT_LONG;
915 1
                    break;
916 10
            }
917 1
918 1
            // Call this to check if parsed type is supported.
919 1
            $this->getSqlType($type, $limit);
920 10
921 2
            $phinxType = [
922 2
                'name' => $type,
923 2
                'limit' => $limit,
924 9
                'precision' => $precision
925 2
            ];
926 2
927 2
            if (static::PHINX_TYPE_ENUM == $type) {
928 8
                $phinxType['values'] = explode("','", trim($matches[6], "()'"));
929 2
            }
930 2
931 2
            return $phinxType;
932
        }
933
    }
934
935 16
    /**
936
     * {@inheritdoc}
937
     */
938 15
    public function createDatabase($name, $options = [])
939 15
    {
940
        $charset = isset($options['charset']) ? $options['charset'] : 'utf8';
941 15
942 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...
943 15
            $this->execute(sprintf('CREATE DATABASE `%s` DEFAULT CHARACTER SET `%s` COLLATE `%s`', $name, $charset, $options['collation']));
944 3
        } else {
945 3
            $this->execute(sprintf('CREATE DATABASE `%s` DEFAULT CHARACTER SET `%s`', $name, $charset));
946
        }
947 15
    }
948
949
    /**
950
     * {@inheritdoc}
951
     */
952
    public function hasDatabase($name)
953
    {
954 83
        $rows = $this->fetchAll(
955
            sprintf(
956 83
                'SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = \'%s\'',
957
                $name
958 83
            )
959 1
        );
960 1
961 82
        foreach ($rows as $row) {
962
            if (!empty($row)) {
963 83
                return true;
964
            }
965
        }
966
967
        return false;
968 4
    }
969
970 4
    /**
971 4
     * {@inheritdoc}
972 4
     */
973
    public function dropDatabase($name)
974 4
    {
975 4
        $this->execute(sprintf('DROP DATABASE IF EXISTS `%s`', $name));
976
    }
977 4
978 3
    /**
979 3
     * Gets the MySQL Column Definition for a Column object.
980
     *
981 3
     * @param Column $column Column
982
     * @return string
983 3
     */
984
    protected function getColumnSqlDefinition(Column $column)
985
    {
986
        $isCustomColumn = $column instanceof Table\CustomColumn;
987
        if ($isCustomColumn) {
988
            $def = $column->getType();
989 81
        } else {
990
            $def = '';
991 81
            $sqlType = $this->getSqlType($column->getType(), $column->getLimit());
992 81
            $def .= strtoupper($sqlType['name']);
993
            if ($column->getPrecision() && $column->getScale()) {
994
                $def .= '(' . $column->getPrecision() . ',' . $column->getScale() . ')';
995
            } elseif (isset($sqlType['limit'])) {
996
                $def .= '(' . $sqlType['limit'] . ')';
997
            }
998 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...
999
                $def .= "('" . implode("', '", $values) . "')";
1000 89
            }
1001
            $def .= $column->getEncoding() ? ' CHARACTER SET ' . $column->getEncoding() : '';
1002 89
            $def .= $column->getCollation() ? ' COLLATE ' . $column->getCollation() : '';
1003
            $def .= (!$column->isSigned() && isset($this->signedColumnTypes[$column->getType()])) ? ' unsigned' : '';
1004 89
        }
1005 89
        $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...
1006 89
        if (!$isCustomColumn) {
1007 2
            $def .= $column->isIdentity() ? ' AUTO_INCREMENT' : '';
1008 89
        }
1009 86
        $def .= $this->getDefaultValueDefinition($column->getDefault());
1010 86
1011 89
        if ($column->getComment()) {
1012 5
            $def .= ' COMMENT ' . $this->getConnection()->quote($column->getComment());
1013 5
        }
1014 89
1015 89
        if ($column->getUpdate()) {
1016 89
            $def .= ' ON UPDATE ' . $column->getUpdate();
1017 89
        }
1018 89
1019 89
        return $def;
1020
    }
1021 89
1022 2
    /**
1023 2
     * Gets the MySQL Index Definition for an Index object.
1024
     *
1025 89
     * @param Index $index Index
1026 1
     * @return string
1027 1
     */
1028
    protected function getIndexSqlDefinition(Index $index)
1029 89
    {
1030
        $def = '';
1031
        $limit = '';
1032
        if ($index->getLimit()) {
1033
            $limit = '(' . $index->getLimit() . ')';
1034
        }
1035
1036
        if ($index->getType() == Index::UNIQUE) {
1037
            $def .= ' UNIQUE';
1038 16
        }
1039
1040 16
        if ($index->getType() == Index::FULLTEXT) {
1041 16
            $def .= ' FULLTEXT';
1042 16
        }
1043 2
1044 2
        $def .= ' KEY';
1045
1046 16
        if (is_string($index->getName())) {
1047 5
            $def .= ' `' . $index->getName() . '`';
1048 5
        }
1049
1050 16
        $def .= ' (`' . implode('`,`', $index->getColumns()) . '`' . $limit . ')';
1051 1
1052 1
        return $def;
1053
    }
1054 16
1055
    /**
1056 16
     * Gets the MySQL Foreign Key Definition for an ForeignKey object.
1057 5
     *
1058 5
     * @param ForeignKey $foreignKey
1059
     * @return string
1060 16
     */
1061 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...
1062 16
    {
1063
        $def = '';
1064
        if ($foreignKey->getConstraint()) {
1065
            $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...
1066
        }
1067
        $columnNames = [];
1068
        foreach ($foreignKey->getColumns() as $column) {
1069
            $columnNames[] = $this->quoteColumnName($column);
1070
        }
1071 17
        $def .= ' FOREIGN KEY (' . implode(',', $columnNames) . ')';
1072
        $refColumnNames = [];
1073 17
        foreach ($foreignKey->getReferencedColumns() as $column) {
1074 17
            $refColumnNames[] = $this->quoteColumnName($column);
1075 5
        }
1076 5
        $def .= ' REFERENCES ' . $this->quoteTableName($foreignKey->getReferencedTable()->getName()) . ' (' . implode(',', $refColumnNames) . ')';
1077 17
        if ($foreignKey->getOnDelete()) {
1078 17
            $def .= ' ON DELETE ' . $foreignKey->getOnDelete();
1079 17
        }
1080 17
        if ($foreignKey->getOnUpdate()) {
1081 17
            $def .= ' ON UPDATE ' . $foreignKey->getOnUpdate();
1082 17
        }
1083 17
        return $def;
1084 17
    }
1085 17
1086 17
    /**
1087 17
     * Describes a database table. This is a MySQL adapter specific method.
1088 2
     *
1089 2
     * @param string $tableName Table name
1090 17
     * @return array
1091 2
     */
1092 2 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...
1093 17
    {
1094
        $options = $this->getOptions();
1095
1096
        // mysql specific
1097
        $sql = sprintf(
1098
            "SELECT *
1099
             FROM information_schema.tables
1100
             WHERE table_schema = '%s'
1101
             AND table_name = '%s'",
1102 2
            $options['name'],
1103
            $tableName
1104 2
        );
1105
1106
        return $this->fetchRow($sql);
1107 2
    }
1108
1109
    /**
1110
     * Returns MySQL column types (inherited and MySQL specified).
1111 2
     * @return array
1112 2
     */
1113
    public function getColumnTypes()
1114 2
    {
1115
        return array_merge(parent::getColumnTypes(), ['enum', 'set', 'year', 'json']);
1116 2
    }
1117
}
1118