Completed
Pull Request — master (#1175)
by David Joseph
01:44
created

MysqlAdapter::getIndexSqlDefinition()   B

Complexity

Conditions 5
Paths 16

Size

Total Lines 26
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 26
ccs 15
cts 15
cp 1
rs 8.439
c 0
b 0
f 0
cc 5
eloc 14
nc 16
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\ForeignKey;
34
use Phinx\Db\Table\Index;
35
use Phinx\Util\Literal;
36
37
/**
38
 * Phinx MySQL Adapter.
39
 *
40
 * @author Rob Morgan <[email protected]>
41
 */
42
class MysqlAdapter extends PdoAdapter implements AdapterInterface
43
{
44
45
    protected $signedColumnTypes = ['integer' => true, 'biginteger' => true, 'float' => true, 'decimal' => true, 'boolean' => true];
46
47
    const TEXT_TINY = 255;
48
    const TEXT_SMALL = 255; /* deprecated, alias of TEXT_TINY */
49
    const TEXT_REGULAR = 65535;
50
    const TEXT_MEDIUM = 16777215;
51
    const TEXT_LONG = 4294967295;
52
53
    // According to https://dev.mysql.com/doc/refman/5.0/en/blob.html BLOB sizes are the same as TEXT
54
    const BLOB_TINY = 255;
55
    const BLOB_SMALL = 255; /* deprecated, alias of BLOB_TINY */
56
    const BLOB_REGULAR = 65535;
57
    const BLOB_MEDIUM = 16777215;
58
    const BLOB_LONG = 4294967295;
59
60
    const INT_TINY = 255;
61
    const INT_SMALL = 65535;
62
    const INT_MEDIUM = 16777215;
63
    const INT_REGULAR = 4294967295;
64
    const INT_BIG = 18446744073709551615;
65
66
    const TYPE_YEAR = 'year';
67
68
    /**
69
     * {@inheritdoc}
70 80
     */
71
    public function connect()
72 80
    {
73 80
        if ($this->connection === null) {
74
            if (!class_exists('PDO') || !in_array('mysql', \PDO::getAvailableDrivers(), true)) {
75
                // @codeCoverageIgnoreStart
76
                throw new \RuntimeException('You need to enable the PDO_Mysql extension for Phinx to run properly.');
77
                // @codeCoverageIgnoreEnd
78
            }
79 80
80 80
            $db = null;
81
            $options = $this->getOptions();
82 80
83
            $dsn = 'mysql:';
84 80
85
            if (!empty($options['unix_socket'])) {
86
                // use socket connection
87
                $dsn .= 'unix_socket=' . $options['unix_socket'];
88
            } else {
89 80
                // use network connection
90 80
                $dsn .= 'host=' . $options['host'];
91 80
                if (!empty($options['port'])) {
92 80
                    $dsn .= ';port=' . $options['port'];
93
                }
94
            }
95 80
96
            $dsn .= ';dbname=' . $options['name'];
97
98 80
            // charset support
99
            if (!empty($options['charset'])) {
100
                $dsn .= ';charset=' . $options['charset'];
101
            }
102 80
103
            $driverOptions = [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION];
104
105
            // support arbitrary \PDO::MYSQL_ATTR_* driver options and pass them to PDO
106 80
            // http://php.net/manual/en/ref.pdo-mysql.php#pdo-mysql.constants
107 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...
108
                if (strpos($key, 'mysql_attr_') === 0) {
109
                    $driverOptions[constant('\PDO::' . strtoupper($key))] = $option;
110 80
                }
111
            }
112
113 80
            try {
114 80
                $db = new \PDO($dsn, $options['user'], $options['pass'], $driverOptions);
115 1
            } catch (\PDOException $exception) {
116 1
                throw new \InvalidArgumentException(sprintf(
117 1
                    'There was a problem connecting to the database: %s',
118 1
                    $exception->getMessage()
119
                ));
120
            }
121 80
122 80
            $this->setConnection($db);
123 80
        }
124
    }
125
126
    /**
127
     * {@inheritdoc}
128 81
     */
129
    public function disconnect()
130 81
    {
131 81
        $this->connection = null;
132
    }
133
134
    /**
135
     * {@inheritdoc}
136 6
     */
137
    public function hasTransactions()
138 6
    {
139
        return true;
140
    }
141
142
    /**
143
     * {@inheritdoc}
144 6
     */
145
    public function beginTransaction()
146 6
    {
147 6
        $this->execute('START TRANSACTION');
148
    }
149
150
    /**
151
     * {@inheritdoc}
152 6
     */
153
    public function commitTransaction()
154 6
    {
155 6
        $this->execute('COMMIT');
156
    }
157
158
    /**
159
     * {@inheritdoc}
160 1
     */
161
    public function rollbackTransaction()
162 1
    {
163 1
        $this->execute('ROLLBACK');
164
    }
165
166
    /**
167
     * {@inheritdoc}
168 112
     */
169
    public function quoteTableName($tableName)
170 112
    {
171
        return str_replace('.', '`.`', $this->quoteColumnName($tableName));
172
    }
173
174
    /**
175
     * {@inheritdoc}
176 112
     */
177
    public function quoteColumnName($columnName)
178 112
    {
179
        return '`' . str_replace('`', '``', $columnName) . '`';
180
    }
181
182
    /**
183
     * {@inheritdoc}
184 82
     */
185 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...
186 82
    {
187
        $options = $this->getOptions();
188 82
189
        $exists = $this->fetchRow(sprintf(
190
            "SELECT TABLE_NAME
191 82
            FROM INFORMATION_SCHEMA.TABLES
192 82
            WHERE TABLE_SCHEMA = '%s' AND TABLE_NAME = '%s'",
193
            $options['name'],
194 82
            $tableName
195
        ));
196 82
197
        return !empty($exists);
198
    }
199
200
    /**
201
     * {@inheritdoc}
202 82
     */
203
    public function createTable(Table $table)
204
    {
205
        // This method is based on the MySQL docs here: http://dev.mysql.com/doc/refman/5.1/en/create-index.html
206 82
        $defaultOptions = [
207
            'engine' => 'InnoDB',
208 82
            'collation' => 'utf8_general_ci'
209 82
        ];
210
211
        $options = array_merge(
212 82
            $defaultOptions,
213 82
            array_intersect_key($this->getOptions(), $defaultOptions),
214 68
            $table->getOptions()
215 68
        );
216 68
217 68
        // Add the default primary key
218 68
        $columns = $table->getPendingColumns();
219
        if (!isset($options['id']) || (isset($options['id']) && $options['id'] === true)) {
220 68
            $column = new Column();
221 68
            $column->setName('id')
222 82
                   ->setType('integer')
223
                   ->setSigned(isset($options['signed']) ? $options['signed'] : true)
224 2
                   ->setIdentity(true);
225 2
226 2
            array_unshift($columns, $column);
227 2
            $options['primary_key'] = 'id';
228
        } elseif (isset($options['id']) && is_string($options['id'])) {
229 2
            // Handle id => "field_name" to support AUTO_INCREMENT
230 2
            $column = new Column();
231 2
            $column->setName($options['id'])
232
                   ->setType('integer')
233
                   ->setIdentity(true);
234
235
            array_unshift($columns, $column);
236 82
            $options['primary_key'] = $options['id'];
237 82
        }
238 82
239 82
        // TODO - process table options like collation etc
240
241
        // process table engine (default to InnoDB)
242 82
        $optionsStr = 'ENGINE = InnoDB';
243 82
        if (isset($options['engine'])) {
244 82
            $optionsStr = sprintf('ENGINE = %s', $options['engine']);
245 82
        }
246 82
247
        // process table collation
248
        if (isset($options['collation'])) {
249 82
            $charset = explode('_', $options['collation']);
250 2
            $optionsStr .= sprintf(' CHARACTER SET %s', $charset[0]);
251 2
            $optionsStr .= sprintf(' COLLATE %s', $options['collation']);
252
        }
253 82
254 82
        // set the table comment
255 82
        if (isset($options['comment'])) {
256 82
            $optionsStr .= sprintf(" COMMENT=%s ", $this->getConnection()->quote($options['comment']));
257 82
        }
258
259
        $sql = 'CREATE TABLE ';
260 82
        $sql .= $this->quoteTableName($table->getName()) . ' (';
261 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...
262 82
            $sql .= $this->quoteColumnName($column->getName()) . ' ' . $this->getColumnSqlDefinition($column) . ', ';
263 82
        }
264 81
265 82
        // set the primary key(s)
266 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...
267
            $sql = rtrim($sql);
268 2
            $sql .= ' PRIMARY KEY (';
269 2
            if (is_string($options['primary_key'])) { // handle primary_key => 'id'
270 2
                $sql .= $this->quoteColumnName($options['primary_key']);
271 2
            } elseif (is_array($options['primary_key'])) { // handle primary_key => array('tag_id', 'resource_id')
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

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

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

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