Completed
Push — master ( 94018a...6a6ebc )
by AD
13s
created

MysqlAdapter::disconnect()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
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\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
     * Get the defintion for a `DEFAULT` statement.
379
     *
380
     * @param  mixed $default
381
     * @return string
382
     */
383 95 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...
384
    {
385 95
        if (is_string($default) && 'CURRENT_TIMESTAMP' !== $default) {
386 10
            $default = $this->getConnection()->quote($default);
387 95
        } elseif (is_bool($default)) {
388 79
            $default = $this->castToBool($default);
389 79
        }
390 95
        return isset($default) ? ' DEFAULT ' . $default : '';
391
    }
392
393
    /**
394
     * {@inheritdoc}
395
     */
396 18 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...
397
    {
398 18
        $sql = sprintf(
399 18
            'ALTER TABLE %s ADD %s %s',
400 18
            $this->quoteTableName($table->getName()),
401 18
            $this->quoteColumnName($column->getName()),
402 18
            $this->getColumnSqlDefinition($column)
403 18
        );
404
405 18
        if ($column->getAfter()) {
406 2
            $sql .= ' AFTER ' . $this->quoteColumnName($column->getAfter());
407 2
        }
408
409 18
        $this->execute($sql);
410 18
    }
411
412
    /**
413
     * {@inheritdoc}
414
     */
415 7
    public function renameColumn($tableName, $columnName, $newColumnName)
416
    {
417 7
        $rows = $this->fetchAll(sprintf('DESCRIBE %s', $this->quoteTableName($tableName)));
418 7
        foreach ($rows as $row) {
419 7
            if (strcasecmp($row['Field'], $columnName) === 0) {
420 5
                $null = ($row['Null'] == 'NO') ? 'NOT NULL' : 'NULL';
421 5
                $extra = ' ' . strtoupper($row['Extra']);
422 5
                if (!is_null($row['Default'])) {
423 1
                    $extra .= $this->getDefaultValueDefinition($row['Default']);
424 1
                }
425 5
                $definition = $row['Type'] . ' ' . $null . $extra;
426
427 5
                $this->execute(
428 5
                    sprintf(
429 5
                        'ALTER TABLE %s CHANGE COLUMN %s %s %s',
430 5
                        $this->quoteTableName($tableName),
431 5
                        $this->quoteColumnName($columnName),
432 5
                        $this->quoteColumnName($newColumnName),
433
                        $definition
434 5
                    )
435 5
                );
436 5
                return;
437
            }
438 6
        }
439
440 2
        throw new \InvalidArgumentException(sprintf(
441
            'The specified column doesn\'t exist: '
442
            . $columnName
443 2
        ));
444
    }
445
446
    /**
447
     * {@inheritdoc}
448
     */
449 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...
450
    {
451 5
        $after = $newColumn->getAfter() ? ' AFTER ' . $this->quoteColumnName($newColumn->getAfter()) : '';
452 5
        $this->execute(
453 5
            sprintf(
454 5
                'ALTER TABLE %s CHANGE %s %s %s%s',
455 5
                $this->quoteTableName($tableName),
456 5
                $this->quoteColumnName($columnName),
457 5
                $this->quoteColumnName($newColumn->getName()),
458 5
                $this->getColumnSqlDefinition($newColumn),
459
                $after
460 5
            )
461 5
        );
462 5
    }
463
464
    /**
465
     * {@inheritdoc}
466
     */
467 5
    public function dropColumn($tableName, $columnName)
468
    {
469 5
        $this->execute(
470 5
            sprintf(
471 5
                'ALTER TABLE %s DROP COLUMN %s',
472 5
                $this->quoteTableName($tableName),
473 5
                $this->quoteColumnName($columnName)
474 5
            )
475 5
        );
476 5
    }
477
478
    /**
479
     * Get an array of indexes from a particular table.
480
     *
481
     * @param string $tableName Table Name
482
     * @return array
483
     */
484 19 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...
485
    {
486 19
        $indexes = [];
487 19
        $rows = $this->fetchAll(sprintf('SHOW INDEXES FROM %s', $this->quoteTableName($tableName)));
488 19
        foreach ($rows as $row) {
489 18
            if (!isset($indexes[$row['Key_name']])) {
490 18
                $indexes[$row['Key_name']] = ['columns' => []];
491 18
            }
492 18
            $indexes[$row['Key_name']]['columns'][] = strtolower($row['Column_name']);
493 19
        }
494 19
        return $indexes;
495
    }
496
497
    /**
498
     * {@inheritdoc}
499
     */
500 14
    public function hasIndex($tableName, $columns)
501
    {
502 14
        if (is_string($columns)) {
503 6
            $columns = [$columns]; // str to array
504 6
        }
505
506 14
        $columns = array_map('strtolower', $columns);
507 14
        $indexes = $this->getIndexes($tableName);
508
509 14
        foreach ($indexes as $index) {
510 14
            if ($columns == $index['columns']) {
511 12
                return true;
512
            }
513 13
        }
514
515 11
        return false;
516
    }
517
518
    /**
519
     * {@inheritdoc}
520
     */
521 1 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...
522
    {
523 1
        $indexes = $this->getIndexes($tableName);
524
525 1
        foreach ($indexes as $name => $index) {
526 1
            if ($name === $indexName) {
527 1
                 return true;
528
            }
529 1
        }
530
531
        return false;
532
    }
533
534
    /**
535
     * {@inheritdoc}
536
     */
537 4
    public function addIndex(Table $table, Index $index)
538
    {
539 4
        $this->execute(
540 4
            sprintf(
541 4
                'ALTER TABLE %s ADD %s',
542 4
                $this->quoteTableName($table->getName()),
543 4
                $this->getIndexSqlDefinition($index)
544 4
            )
545 4
        );
546 4
    }
547
548
    /**
549
     * {@inheritdoc}
550
     */
551 3
    public function dropIndex($tableName, $columns)
552
    {
553 3
        if (is_string($columns)) {
554 2
            $columns = [$columns]; // str to array
555 2
        }
556
557 3
        $indexes = $this->getIndexes($tableName);
558 3
        $columns = array_map('strtolower', $columns);
559
560 3
        foreach ($indexes as $indexName => $index) {
561 3
            if ($columns == $index['columns']) {
562 3
                $this->execute(
563 3
                    sprintf(
564 3
                        'ALTER TABLE %s DROP INDEX %s',
565 3
                        $this->quoteTableName($tableName),
566 3
                        $this->quoteColumnName($indexName)
567 3
                    )
568 3
                );
569 3
                return;
570
            }
571 3
        }
572 1
    }
573
574
    /**
575
     * {@inheritdoc}
576
     */
577 2 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...
578
    {
579 2
        $indexes = $this->getIndexes($tableName);
580
581 2
        foreach ($indexes as $name => $index) {
582
            //$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...
583 2
            if ($name === $indexName) {
584 2
                $this->execute(
585 2
                    sprintf(
586 2
                        'ALTER TABLE %s DROP INDEX %s',
587 2
                        $this->quoteTableName($tableName),
588 2
                        $this->quoteColumnName($indexName)
589 2
                    )
590 2
                );
591 2
                return;
592
            }
593 2
        }
594
    }
595
596
    /**
597
     * {@inheritdoc}
598
     */
599 21 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...
600
    {
601 21
        if (is_string($columns)) {
602 5
            $columns = [$columns]; // str to array
603 5
        }
604 21
        $foreignKeys = $this->getForeignKeys($tableName);
605 21
        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...
606 6
            if (isset($foreignKeys[$constraint])) {
607 4
                return !empty($foreignKeys[$constraint]);
608
            }
609 4
            return false;
610
        } else {
611 15
            foreach ($foreignKeys as $key) {
612 12
                if ($columns == $key['columns']) {
613 10
                    return true;
614
                }
615 11
            }
616 11
            return false;
617
        }
618
    }
619
620
    /**
621
     * Get an array of foreign keys from a particular table.
622
     *
623
     * @param string $tableName Table Name
624
     * @return array
625
     */
626 22 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...
627
    {
628 22
        $foreignKeys = [];
629 22
        $rows = $this->fetchAll(sprintf(
630
            "SELECT
631
              CONSTRAINT_NAME,
632
              TABLE_NAME,
633
              COLUMN_NAME,
634
              REFERENCED_TABLE_NAME,
635
              REFERENCED_COLUMN_NAME
636
            FROM information_schema.KEY_COLUMN_USAGE
637
            WHERE REFERENCED_TABLE_SCHEMA = DATABASE()
638
              AND REFERENCED_TABLE_NAME IS NOT NULL
639
              AND TABLE_NAME = '%s'
640 22
            ORDER BY POSITION_IN_UNIQUE_CONSTRAINT",
641
            $tableName
642 22
        ));
643 22
        foreach ($rows as $row) {
644 19
            $foreignKeys[$row['CONSTRAINT_NAME']]['table'] = $row['TABLE_NAME'];
645 19
            $foreignKeys[$row['CONSTRAINT_NAME']]['columns'][] = $row['COLUMN_NAME'];
646 19
            $foreignKeys[$row['CONSTRAINT_NAME']]['referenced_table'] = $row['REFERENCED_TABLE_NAME'];
647 19
            $foreignKeys[$row['CONSTRAINT_NAME']]['referenced_columns'][] = $row['REFERENCED_COLUMN_NAME'];
648 22
        }
649 22
        return $foreignKeys;
650
    }
651
652
    /**
653
     * {@inheritdoc}
654
     */
655 15
    public function addForeignKey(Table $table, ForeignKey $foreignKey)
656
    {
657 15
        $this->execute(
658 15
            sprintf(
659 15
                'ALTER TABLE %s ADD %s',
660 15
                $this->quoteTableName($table->getName()),
661 15
                $this->getForeignKeySqlDefinition($foreignKey)
662 15
            )
663 15
        );
664 15
    }
665
666
    /**
667
     * {@inheritdoc}
668
     */
669 8 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...
670
    {
671 8
        if (is_string($columns)) {
672 3
            $columns = [$columns]; // str to array
673 3
        }
674
675
676 8
        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...
677 8
            $this->execute(
678 8
                sprintf(
679 8
                    'ALTER TABLE %s DROP FOREIGN KEY %s',
680 8
                    $this->quoteTableName($tableName),
681
                    $constraint
682 8
                )
683 8
            );
684 8
            return;
685
        } else {
686 7
            foreach ($columns as $column) {
687 7
                $rows = $this->fetchAll(sprintf(
688
                    "SELECT
689
                        CONSTRAINT_NAME
690
                      FROM information_schema.KEY_COLUMN_USAGE
691
                      WHERE REFERENCED_TABLE_SCHEMA = DATABASE()
692
                        AND REFERENCED_TABLE_NAME IS NOT NULL
693
                        AND TABLE_NAME = '%s'
694
                        AND COLUMN_NAME = '%s'
695 7
                      ORDER BY POSITION_IN_UNIQUE_CONSTRAINT",
696 7
                    $tableName,
697
                    $column
698 7
                ));
699 7
                foreach ($rows as $row) {
700 7
                    $this->dropForeignKey($tableName, $columns, $row['CONSTRAINT_NAME']);
701 7
                }
702 7
            }
703
        }
704 7
    }
705
706
    /**
707
     * {@inheritdoc}
708
     */
709 96
    public function getSqlType($type, $limit = null)
710
    {
711
        switch ($type) {
712 96
            case static::PHINX_TYPE_STRING:
713 87
                return ['name' => 'varchar', 'limit' => $limit ? $limit : 255];
714
                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...
715 96
            case static::PHINX_TYPE_CHAR:
716 4
                return ['name' => 'char', 'limit' => $limit ? $limit : 255];
717
                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...
718 96 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...
719 9
                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...
720
                    $sizes = [
721
                        // Order matters! Size must always be tested from longest to shortest!
722 6
                        'longtext'   => static::TEXT_LONG,
723 6
                        'mediumtext' => static::TEXT_MEDIUM,
724 6
                        'text'       => static::TEXT_REGULAR,
725 6
                        'tinytext'   => static::TEXT_SMALL,
726 6
                    ];
727 6
                    foreach ($sizes as $name => $length) {
728 6
                        if ($limit >= $length) {
729 6
                            return ['name' => $name];
730
                        }
731 5
                    }
732
                }
733 5
                return ['name' => 'text'];
734
                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...
735 95
            case static::PHINX_TYPE_BINARY:
736 5
                return ['name' => 'binary', 'limit' => $limit ? $limit : 255];
737
                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...
738 95
            case static::PHINX_TYPE_VARBINARY:
739 3
                return ['name' => 'varbinary', 'limit' => $limit ? $limit : 255];
740
                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...
741 95 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...
742 1
                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...
743
                    $sizes = [
744
                        // Order matters! Size must always be tested from longest to shortest!
745 1
                        'longblob'   => static::BLOB_LONG,
746 1
                        'mediumblob' => static::BLOB_MEDIUM,
747 1
                        'blob'       => static::BLOB_REGULAR,
748 1
                        'tinyblob'   => static::BLOB_SMALL,
749 1
                    ];
750 1
                    foreach ($sizes as $name => $length) {
751 1
                        if ($limit >= $length) {
752 1
                            return ['name' => $name];
753
                        }
754 1
                    }
755
                }
756 1
                return ['name' => 'blob'];
757
                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...
758 95
            case static::PHINX_TYPE_INTEGER:
759 82
                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...
760
                    $sizes = [
761
                        // Order matters! Size must always be tested from longest to shortest!
762 6
                        'bigint'    => static::INT_BIG,
763 6
                        'int'       => static::INT_REGULAR,
764 6
                        'mediumint' => static::INT_MEDIUM,
765 6
                        'smallint'  => static::INT_SMALL,
766 6
                        'tinyint'   => static::INT_TINY,
767 6
                    ];
768
                    $limits = [
769 6
                        'int'    => 11,
770 6
                        'bigint' => 20,
771 6
                    ];
772 6
                    foreach ($sizes as $name => $length) {
773 6
                        if ($limit >= $length) {
774 6
                            $def = ['name' => $name];
775 6
                            if (isset($limits[$name])) {
776 2
                                $def['limit'] = $limits[$name];
777 2
                            }
778 6
                            return $def;
779
                        }
780 5
                    }
781 82
                } 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...
782 76
                    $limit = 11;
783 76
                }
784 82
                return ['name' => 'int', 'limit' => $limit];
785
                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...
786 86
            case static::PHINX_TYPE_BIG_INTEGER:
787 82
                return ['name' => 'bigint', 'limit' => 20];
788
                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...
789 86
            case static::PHINX_TYPE_FLOAT:
790 7
                return ['name' => 'float'];
791
                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...
792 84
            case static::PHINX_TYPE_DECIMAL:
793 5
                return ['name' => 'decimal'];
794
                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...
795 83
            case static::PHINX_TYPE_DATETIME:
796 7
                return ['name' => 'datetime'];
797
                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...
798 83
            case static::PHINX_TYPE_TIMESTAMP:
799 80
                return ['name' => 'timestamp'];
800
                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...
801 83
            case static::PHINX_TYPE_TIME:
802 4
                return ['name' => 'time'];
803
                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...
804 83
            case static::PHINX_TYPE_DATE:
805 4
                return ['name' => 'date'];
806
                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...
807 83
            case static::PHINX_TYPE_BOOLEAN:
808 80
                return ['name' => 'tinyint', 'limit' => 1];
809
                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...
810 10
            case static::PHINX_TYPE_UUID:
811 2
                return ['name' => 'char', 'limit' => 36];
812
            // Geospatial database types
813 10
            case static::PHINX_TYPE_GEOMETRY:
814 10
            case static::PHINX_TYPE_POINT:
815 10
            case static::PHINX_TYPE_LINESTRING:
816 10
            case static::PHINX_TYPE_POLYGON:
817 5
                return ['name' => $type];
818 8
            case static::PHINX_TYPE_ENUM:
819 5
                return ['name' => 'enum'];
820
                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...
821 6
            case static::PHINX_TYPE_SET:
822 4
                return ['name' => 'set'];
823
                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...
824 2
            case static::TYPE_YEAR:
825
                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...
826
                    $limit = 4;
827
                }
828
                return ['name' => 'year', 'limit' => $limit];
829
                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...
830 2
            case static::PHINX_TYPE_JSON:
831
                return ['name' => 'json'];
832
                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...
833 2
            default:
834 2
                throw new \RuntimeException('The type: "' . $type . '" is not supported.');
835 2
        }
836
    }
837
838
    /**
839
     * Returns Phinx type by SQL type
840
     *
841
     * @param string $sqlTypeDef
842
     * @throws \RuntimeException
843
     * @internal param string $sqlType SQL type
844
     * @returns string Phinx type
845
     */
846 17
    public function getPhinxType($sqlTypeDef)
847
    {
848 17
        $matches = [];
849 17
        if (!preg_match('/^([\w]+)(\(([\d]+)*(,([\d]+))*\))*(.+)*$/', $sqlTypeDef, $matches)) {
850 1
            throw new \RuntimeException('Column type ' . $sqlTypeDef . ' is not supported');
851
        } else {
852 16
            $limit = null;
853 16
            $precision = null;
854 16
            $type = $matches[1];
855 16 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...
856 14
                $limit = $matches[3] ? (int) $matches[3] : null;
857 14
            }
858 16
            if (count($matches) > 4) {
859 4
                $precision = (int) $matches[5];
860 4
            }
861 16 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...
862 3
                $type = static::PHINX_TYPE_BOOLEAN;
863 3
                $limit = null;
864 3
            }
865
            switch ($type) {
866 16
                case 'varchar':
867 6
                    $type = static::PHINX_TYPE_STRING;
868 6
                    if ($limit === 255) {
869 3
                        $limit = null;
870 3
                    }
871 6
                    break;
872 16 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...
873 5
                    $type = static::PHINX_TYPE_CHAR;
874 5
                    if ($limit === 255) {
875 1
                        $limit = null;
876 1
                    }
877 5
                    if ($limit === 36) {
878 2
                        $type = static::PHINX_TYPE_UUID;
879 2
                    }
880 5
                    break;
881 16
                case 'tinyint':
882 2
                    $type  = static::PHINX_TYPE_INTEGER;
883 2
                    $limit = static::INT_TINY;
884 2
                    break;
885 16
                case 'smallint':
886 2
                    $type  = static::PHINX_TYPE_INTEGER;
887 2
                    $limit = static::INT_SMALL;
888 2
                    break;
889 16
                case 'mediumint':
890 2
                    $type  = static::PHINX_TYPE_INTEGER;
891 2
                    $limit = static::INT_MEDIUM;
892 2
                    break;
893 16
                case 'int':
894 15
                    $type = static::PHINX_TYPE_INTEGER;
895 15
                    if ($limit === 11) {
896 12
                        $limit = null;
897 12
                    }
898 15
                    break;
899 11
                case 'bigint':
900 6
                    if ($limit === 20) {
901 4
                        $limit = null;
902 4
                    }
903 6
                    $type = static::PHINX_TYPE_BIG_INTEGER;
904 6
                    break;
905 10
                case 'blob':
906 2
                    $type = static::PHINX_TYPE_BINARY;
907 2
                    break;
908 10
                case 'tinyblob':
909 1
                    $type  = static::PHINX_TYPE_BINARY;
910 1
                    $limit = static::BLOB_TINY;
911 1
                    break;
912 10
                case 'mediumblob':
913 1
                    $type  = static::PHINX_TYPE_BINARY;
914 1
                    $limit = static::BLOB_MEDIUM;
915 1
                    break;
916 10
                case 'longblob':
917 1
                    $type  = static::PHINX_TYPE_BINARY;
918 1
                    $limit = static::BLOB_LONG;
919 1
                    break;
920 10
                case 'tinytext':
921 2
                    $type  = static::PHINX_TYPE_TEXT;
922 2
                    $limit = static::TEXT_TINY;
923 2
                    break;
924 9
                case 'mediumtext':
925 2
                    $type  = static::PHINX_TYPE_TEXT;
926 2
                    $limit = static::TEXT_MEDIUM;
927 2
                    break;
928 8
                case 'longtext':
929 2
                    $type  = static::PHINX_TYPE_TEXT;
930 2
                    $limit = static::TEXT_LONG;
931 2
                    break;
932
            }
933
934
            // Call this to check if parsed type is supported.
935 16
            $this->getSqlType($type, $limit);
936
937
            $phinxType = [
938 15
                'name' => $type,
939 15
                'limit' => $limit,
940
                'precision' => $precision
941 15
            ];
942
943 15
            if (static::PHINX_TYPE_ENUM == $type) {
944 3
                $phinxType['values'] = explode("','", trim($matches[6], "()'"));
945 3
            }
946
947 15
            return $phinxType;
948
        }
949
    }
950
951
    /**
952
     * {@inheritdoc}
953
     */
954 83
    public function createDatabase($name, $options = [])
955
    {
956 83
        $charset = isset($options['charset']) ? $options['charset'] : 'utf8';
957
958 83 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...
959 1
            $this->execute(sprintf('CREATE DATABASE `%s` DEFAULT CHARACTER SET `%s` COLLATE `%s`', $name, $charset, $options['collation']));
960 1
        } else {
961 82
            $this->execute(sprintf('CREATE DATABASE `%s` DEFAULT CHARACTER SET `%s`', $name, $charset));
962
        }
963 83
    }
964
965
    /**
966
     * {@inheritdoc}
967
     */
968 4
    public function hasDatabase($name)
969
    {
970 4
        $rows = $this->fetchAll(
971 4
            sprintf(
972 4
                'SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = \'%s\'',
973
                $name
974 4
            )
975 4
        );
976
977 4
        foreach ($rows as $row) {
978 3
            if (!empty($row)) {
979 3
                return true;
980
            }
981 3
        }
982
983 3
        return false;
984
    }
985
986
    /**
987
     * {@inheritdoc}
988
     */
989 81
    public function dropDatabase($name)
990
    {
991 81
        $this->execute(sprintf('DROP DATABASE IF EXISTS `%s`', $name));
992 81
    }
993
994
    /**
995
     * Gets the MySQL Column Definition for a Column object.
996
     *
997
     * @param Column $column Column
998
     * @return string
999
     */
1000 89
    protected function getColumnSqlDefinition(Column $column)
1001
    {
1002 89
        $sqlType = $this->getSqlType($column->getType(), $column->getLimit());
1003
1004 89
        $def = '';
1005 89
        $def .= strtoupper($sqlType['name']);
1006 89
        if ($column->getPrecision() && $column->getScale()) {
1007 2
            $def .= '(' . $column->getPrecision() . ',' . $column->getScale() . ')';
1008 89
        } elseif (isset($sqlType['limit'])) {
1009 86
            $def .= '(' . $sqlType['limit'] . ')';
1010 86
        }
1011 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...
1012 5
            $def .= "('" . implode("', '", $values) . "')";
1013 5
        }
1014 89
        $def .= $column->getEncoding() ? ' CHARACTER SET ' . $column->getEncoding() : '';
1015 89
        $def .= $column->getCollation() ? ' COLLATE ' . $column->getCollation() : '';
1016 89
        $def .= (!$column->isSigned() && isset($this->signedColumnTypes[$column->getType()])) ? ' unsigned' : '' ;
1017 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...
1018 89
        $def .= ($column->isIdentity()) ? ' AUTO_INCREMENT' : '';
1019 89
        $def .= $this->getDefaultValueDefinition($column->getDefault());
1020
1021 89
        if ($column->getComment()) {
1022 2
            $def .= ' COMMENT ' . $this->getConnection()->quote($column->getComment());
1023 2
        }
1024
1025 89
        if ($column->getUpdate()) {
1026 1
            $def .= ' ON UPDATE ' . $column->getUpdate();
1027 1
        }
1028
1029 89
        return $def;
1030
    }
1031
1032
    /**
1033
     * Gets the MySQL Index Definition for an Index object.
1034
     *
1035
     * @param Index $index Index
1036
     * @return string
1037
     */
1038 16
    protected function getIndexSqlDefinition(Index $index)
1039
    {
1040 16
        $def = '';
1041 16
        $limit = '';
1042 16
        if ($index->getLimit()) {
1043 2
            $limit = '(' . $index->getLimit() . ')';
1044 2
        }
1045
1046 16
        if ($index->getType() == Index::UNIQUE) {
1047 5
            $def .= ' UNIQUE';
1048 5
        }
1049
1050 16
        if ($index->getType() == Index::FULLTEXT) {
1051 1
            $def .= ' FULLTEXT';
1052 1
        }
1053
1054 16
        $def .= ' KEY';
1055
1056 16
        if (is_string($index->getName())) {
1057 5
            $def .= ' `' . $index->getName() . '`';
1058 5
        }
1059
1060 16
        $def .= ' (`' . implode('`,`', $index->getColumns()) . '`' . $limit . ')';
1061
1062 16
        return $def;
1063
    }
1064
1065
    /**
1066
     * Gets the MySQL Foreign Key Definition for an ForeignKey object.
1067
     *
1068
     * @param ForeignKey $foreignKey
1069
     * @return string
1070
     */
1071 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...
1072
    {
1073 17
        $def = '';
1074 17
        if ($foreignKey->getConstraint()) {
1075 5
            $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...
1076 5
        }
1077 17
        $columnNames = [];
1078 17
        foreach ($foreignKey->getColumns() as $column) {
1079 17
            $columnNames[] = $this->quoteColumnName($column);
1080 17
        }
1081 17
        $def .= ' FOREIGN KEY (' . implode(',', $columnNames) . ')';
1082 17
        $refColumnNames = [];
1083 17
        foreach ($foreignKey->getReferencedColumns() as $column) {
1084 17
            $refColumnNames[] = $this->quoteColumnName($column);
1085 17
        }
1086 17
        $def .= ' REFERENCES ' . $this->quoteTableName($foreignKey->getReferencedTable()->getName()) . ' (' . implode(',', $refColumnNames) . ')';
1087 17
        if ($foreignKey->getOnDelete()) {
1088 2
            $def .= ' ON DELETE ' . $foreignKey->getOnDelete();
1089 2
        }
1090 17
        if ($foreignKey->getOnUpdate()) {
1091 2
            $def .= ' ON UPDATE ' . $foreignKey->getOnUpdate();
1092 2
        }
1093 17
        return $def;
1094
    }
1095
1096
    /**
1097
     * Describes a database table. This is a MySQL adapter specific method.
1098
     *
1099
     * @param string $tableName Table name
1100
     * @return array
1101
     */
1102 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...
1103
    {
1104 2
        $options = $this->getOptions();
1105
1106
        // mysql specific
1107 2
        $sql = sprintf(
1108
            "SELECT *
1109
             FROM information_schema.tables
1110
             WHERE table_schema = '%s'
1111 2
             AND table_name = '%s'",
1112 2
            $options['name'],
1113
            $tableName
1114 2
        );
1115
1116 2
        return $this->fetchRow($sql);
1117
    }
1118
1119
    /**
1120
     * Returns MySQL column types (inherited and MySQL specified).
1121
     * @return array
1122
     */
1123 85
    public function getColumnTypes()
1124
    {
1125 85
        return array_merge(parent::getColumnTypes(), ['enum', 'set', 'year', 'json']);
1126
    }
1127
}
1128