Completed
Pull Request — master (#1627)
by Alexandr
01:41
created

PdoAdapter   F

Complexity

Total Complexity 95

Size/Duplication

Total Lines 971
Duplicated Lines 1.24 %

Coupling/Cohesion

Components 1
Dependencies 21

Test Coverage

Coverage 91.21%

Importance

Changes 0
Metric Value
wmc 95
lcom 1
cbo 21
dl 12
loc 971
ccs 166
cts 182
cp 0.9121
rs 1.629
c 0
b 0
f 0

56 Methods

Rating   Name   Duplication   Size   Complexity  
A verboseLog() 0 10 3
A createPdoConnection() 0 14 2
A setOptions() 0 10 2
A setConnection() 0 27 4
A getConnection() 0 8 2
A connect() 0 3 1
A disconnect() 0 3 1
A execute() 0 11 2
getDecoratedConnection() 0 1 ?
A getQueryBuilder() 0 4 1
A query() 0 4 1
A fetchRow() 0 6 1
A fetchAll() 0 10 2
A insert() 0 24 4
A quoteValue() 0 12 3
A quoteString() 0 4 1
A bulkinsert() 0 38 5
A getVersions() 0 6 1
A migrated() 0 34 2
A setBreakpoint() 0 4 1
A unsetBreakpoint() 0 4 1
A markBreakpoint() 0 16 1
A createSchema() 0 4 1
A dropSchema() 0 4 1
A getColumnTypes() 0 29 1
A getAttribute() 0 4 1
B getDefaultValueDefinition() 12 12 7
A executeAlterSteps() 0 5 1
A addColumn() 0 5 1
getAddColumnInstructions() 0 1 ?
A renameColumn() 0 5 1
getRenameColumnInstructions() 0 1 ?
A changeColumn() 0 5 1
getChangeColumnInstructions() 0 1 ?
A dropColumn() 0 5 1
getDropColumnInstructions() 0 1 ?
A addIndex() 0 5 1
getAddIndexInstructions() 0 1 ?
A dropIndex() 0 5 1
getDropIndexByColumnsInstructions() 0 1 ?
A dropIndexByName() 0 5 1
getDropIndexByNameInstructions() 0 1 ?
A addForeignKey() 0 5 1
getAddForeignKeyInstructions() 0 1 ?
A dropForeignKey() 0 10 2
getDropForeignKeyInstructions() 0 1 ?
getDropForeignKeyByColumnsInstructions() 0 1 ?
A dropTable() 0 5 1
getDropTableInstructions() 0 1 ?
A renameTable() 0 5 1
getRenameTableInstructions() 0 1 ?
A changePrimaryKey() 0 5 1
getChangePrimaryKeyInstructions() 0 1 ?
A changeComment() 0 5 1
getChangeCommentInstructions() 0 1 ?
F executeActions() 0 105 20

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like PdoAdapter often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use PdoAdapter, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * MIT License
5
 * For full license information, please view the LICENSE file that was distributed with this source code.
6
 */
7
8
namespace Phinx\Db\Adapter;
9
10
use BadMethodCallException;
11
use InvalidArgumentException;
12
use PDO;
13
use PDOException;
14
use Phinx\Config\Config;
15
use Phinx\Db\Action\AddColumn;
16
use Phinx\Db\Action\AddForeignKey;
17
use Phinx\Db\Action\AddIndex;
18
use Phinx\Db\Action\ChangeColumn;
19
use Phinx\Db\Action\ChangeComment;
20
use Phinx\Db\Action\ChangePrimaryKey;
21
use Phinx\Db\Action\DropForeignKey;
22
use Phinx\Db\Action\DropIndex;
23
use Phinx\Db\Action\DropTable;
24
use Phinx\Db\Action\RemoveColumn;
25
use Phinx\Db\Action\RenameColumn;
26
use Phinx\Db\Action\RenameTable;
27
use Phinx\Db\Table as DbTable;
28
use Phinx\Db\Table\Column;
29
use Phinx\Db\Table\ForeignKey;
30
use Phinx\Db\Table\Index;
31
use Phinx\Db\Table\Table;
32
use Phinx\Db\Util\AlterInstructions;
33
use Phinx\Migration\MigrationInterface;
34
use RuntimeException;
35
use Symfony\Component\Console\Output\OutputInterface;
36
37
/**
38
 * Phinx PDO Adapter.
39
 *
40
 * @author Rob Morgan <[email protected]>
41
 */
42
abstract class PdoAdapter extends AbstractAdapter implements DirectActionInterface
43
{
44
    /**
45
     * @var \PDO|null
46
     */
47
    protected $connection;
48
49
    /**
50
     * Writes a message to stdout if verbose output is on
51 287
     *
52
     * @param string $message The message to show
53 287
     *
54
     * @return void
55 287
     */
56 3
    protected function verboseLog($message)
57 3
    {
58
        if (!$this->isDryRunEnabled() &&
59 287
             $this->getOutput()->getVerbosity() < OutputInterface::VERBOSITY_VERY_VERBOSE
60
        ) {
61
            return;
62
        }
63
64
        $this->getOutput()->writeln($message);
65
    }
66
67
    /**
68 193
     * Create PDO connection
69
     *
70 193
     * @param string $dsn Connection string
71
     * @param string|null $username Database username
72
     * @param string|null $password Database password
73 193
     * @param array $options Connection options
74 191
     * @return \PDO
75 191
     */
76 74
    protected function createPdoConnection($dsn, $username = null, $password = null, array $options = [])
77 74
    {
78
        try {
79
            $db = new PDO($dsn, $username, $password, $options);
80
            $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
81
        } catch (PDOException $e) {
82
            throw new InvalidArgumentException(sprintf(
83
                'There was a problem connecting to the database: %s',
84
                $e->getMessage()
85
            ), $e->getCode(), $e);
86 74
        }
87
88
        return $db;
89
    }
90
91
    /**
92
     * @inheritDoc
93 193
     */
94
    public function setOptions(array $options)
95
    {
96
        parent::setOptions($options);
97
98
        if (isset($options['connection'])) {
99
            $this->setConnection($options['connection']);
100
        }
101 191
102
        return $this;
103 191
    }
104 189
105 189
    /**
106 191
     * Sets the database connection.
107
     *
108
     * @param \PDO $connection Connection
109
     *
110
     * @return \Phinx\Db\Adapter\AdapterInterface
111
     */
112 1
    public function setConnection(PDO $connection)
113
    {
114 1
        $this->connection = $connection;
115
116
        // Create the schema table if it doesn't already exist
117
        if (!$this->hasSchemaTable()) {
118
            $this->createSchemaTable();
119
        } else {
120
            $table = new DbTable($this->getSchemaTableName(), [], $this);
121
            if (!$table->hasColumn('migration_name')) {
122
                $table
123
                    ->addColumn(
124
                        'migration_name',
125
                        'string',
126 218
                        ['limit' => 100, 'after' => 'version', 'default' => null, 'null' => true]
127
                    )
128 218
                    ->save();
129 3
            }
130 3
            if (!$table->hasColumn('breakpoint')) {
131
                $table
132
                    ->addColumn('breakpoint', 'boolean', ['default' => false])
133 217
                    ->save();
134
            }
135
        }
136
137
        return $this;
138
    }
139
140
    /**
141
     * Gets the database connection
142 220
     *
143
     * @return \PDO
144 220
     */
145
    public function getConnection()
146
    {
147
        if ($this->connection === null) {
148
            $this->connect();
149
        }
150 151
151
        return $this->connection;
152 151
    }
153 151
154
    /**
155
     * {@inheritDoc}
156
     *
157
     * @return void
158
     */
159 213
    public function connect()
160
    {
161 213
    }
162 213
163 213
    /**
164 208
     * {@inheritDoc}
165 208
     *
166 213
     * @return void
167
     */
168
    public function disconnect()
169
    {
170
    }
171
172 1
    /**
173
     * @inheritDoc
174 1
     */
175 1
    public function execute($sql)
176 1
    {
177 1
        $sql = rtrim($sql, "; \t\n\r\0\x0B") . ';';
178
        $this->verboseLog($sql);
179 1
180 1
        if ($this->isDryRunEnabled()) {
181 1
            return 0;
182
        }
183 1
184 1
        return $this->getConnection()->exec($sql);
185 1
    }
186
187
    /**
188
     * Returns the Cake\Database connection object using the same underlying
189
     * PDO object as this connection.
190 11
     *
191
     * @return \Cake\Database\Connection
192 11
     */
193 11
    abstract public function getDecoratedConnection();
194 11
195 11
    /**
196
     * @inheritDoc
197 11
     */
198 11
    public function getQueryBuilder()
199 11
    {
200
        return $this->getDecoratedConnection()->newQuery();
201 11
    }
202 11
203 11
    /**
204 11
     * Executes a query and returns PDOStatement.
205 11
     *
206 11
     * @param string $sql SQL
207
     *
208 11
     * @return \PDOStatement
209 11
     */
210
    public function query($sql)
211 11
    {
212 11
        return $this->getConnection()->query($sql);
213 11
    }
214
215 11
    /**
216 11
     * @inheritDoc
217 11
     */
218
    public function fetchRow($sql)
219
    {
220
        $result = $this->query($sql);
221
222 5
        return $result->fetch();
223
    }
224 5
225
    /**
226 5
     * @inheritDoc
227
     */
228
    public function fetchAll($sql)
229
    {
230
        $rows = [];
231
        $result = $this->query($sql);
232 8
        while ($row = $result->fetch()) {
233
            $rows[] = $row;
234 8
        }
235
236 8
        return $rows;
237 8
    }
238 6
239 6
    /**
240 2
     * {@inheritDoc}
241 1
     *
242 1
     * @return void
243 1
     */
244 1
    public function insert(Table $table, $row)
245 8
    {
246
        $sql = sprintf(
247 7
            'INSERT INTO %s ',
248 7
            $this->quoteTableName($table->getName())
249 7
        );
250 7
        $columns = array_keys($row);
251
        $sql .= '(' . implode(', ', array_map([$this, 'quoteColumnName'], $columns)) . ')';
252 7
253
        foreach ($row as $column => $value) {
254
            if (is_bool($value)) {
255
                $row[$column] = $this->castToBool($value);
256
            }
257
        }
258 5
259
        if ($this->isDryRunEnabled()) {
260 5
            $sql .= ' VALUES (' . implode(', ', array_map([$this, 'quoteValue'], $row)) . ');';
261
            $this->output->writeln($sql);
262 5
        } else {
263 5
            $sql .= ' VALUES (' . implode(', ', array_fill(0, count($columns), '?')) . ')';
264 5
            $stmt = $this->getConnection()->prepare($sql);
265 5
            $stmt->execute(array_values($row));
266 5
        }
267 5
    }
268 5
269 5
    /**
270 5
     * Quotes a database value.
271 5
     *
272 5
     * @param mixed $value The value to quote
273 5
     *
274 5
     * @return mixed
275 5
     */
276
    private function quoteValue($value)
277 5
    {
278 5
        if (is_numeric($value)) {
279
            return $value;
280 3
        }
281 3
282 3
        if ($value === null) {
283 3
            return 'null';
284 3
        }
285 3
286
        return $this->getConnection()->quote($value);
287 3
    }
288
289
    /**
290 5
     * Quotes a database string.
291
     *
292
     * @param string $value The string to quote
293
     *
294
     * @return string
295
     */
296 1
    protected function quoteString($value)
297
    {
298 1
        return $this->getConnection()->quote($value);
299 1
    }
300 1
301 1
    /**
302 1
     * @inheritDoc
303 1
     */
304 1
    public function bulkinsert(Table $table, $rows)
305 1
    {
306 1
        $sql = sprintf(
307 1
            'INSERT INTO %s ',
308 1
            $this->quoteTableName($table->getName())
309 1
        );
310
        $current = current($rows);
311 1
        $keys = array_keys($current);
312
        $sql .= '(' . implode(', ', array_map([$this, 'quoteColumnName'], $keys)) . ') VALUES ';
313
314
        if ($this->isDryRunEnabled()) {
315
            $values = array_map(function ($row) {
316
                return '(' . implode(', ', array_map([$this, 'quoteValue'], $row)) . ')';
317 1
            }, $rows);
318
            $sql .= implode(', ', $values) . ';';
319 1
            $this->output->writeln($sql);
320 1
        } else {
321 1
            $count_keys = count($keys);
322 1
            $query = '(' . implode(', ', array_fill(0, $count_keys, '?')) . ')';
323 1
            $count_vars = count($rows);
324 1
            $queries = array_fill(0, $count_vars, $query);
325 1
            $sql .= implode(',', $queries);
326 1
            $stmt = $this->getConnection()->prepare($sql);
327 1
            $vals = [];
328
329
            foreach ($rows as $row) {
330
                foreach ($row as $v) {
331
                    if (is_bool($v)) {
332
                        $vals[] = $this->castToBool($v);
333
                    } else {
334
                        $vals[] = $v;
335
                    }
336
                }
337
            }
338
339
            $stmt->execute($vals);
340
        }
341
    }
342
343
    /**
344
     * @inheritDoc
345
     */
346
    public function getVersions()
347
    {
348
        $rows = $this->getVersionLog();
349 208
350
        return array_keys($rows);
351
    }
352 208
353 208
    /**
354 208
     * {@inheritDoc}
355 208
     *
356 208
     * @throws \RuntimeException
357 208
     */
358 208
    public function getVersionLog()
359 208
    {
360 208
        $result = [];
361 208
362 208
        switch ($this->options['version_order']) {
363 208
            case Config::VERSION_ORDER_CREATION_TIME:
364 208
                $orderBy = 'version ASC';
365 208
                break;
366 208
            case Config::VERSION_ORDER_EXECUTION_TIME:
367 208
                $orderBy = 'start_time ASC, version ASC';
368
                break;
369 208
            default:
370 208
                throw new RuntimeException('Invalid version_order configuration option');
371 208
        }
372 208
373 208
        $rows = $this->fetchAll(sprintf('SELECT * FROM %s ORDER BY %s', $this->getSchemaTableName(), $orderBy));
374
        foreach ($rows as $version) {
375
            $result[$version['version']] = $version;
376
        }
377
378
        return $result;
379 121
    }
380
381 121
    /**
382
     * @inheritDoc
383
     */
384
    public function migrated(MigrationInterface $migration, $direction, $startTime, $endTime)
385
    {
386
        if (strcasecmp($direction, MigrationInterface::UP) === 0) {
387
            // up
388
            $sql = sprintf(
389
                "INSERT INTO %s (%s, %s, %s, %s, %s) VALUES ('%s', '%s', '%s', '%s', %s);",
390
                $this->quoteTableName($this->getSchemaTableName()),
391
                $this->quoteColumnName('version'),
392
                $this->quoteColumnName('migration_name'),
393
                $this->quoteColumnName('start_time'),
394
                $this->quoteColumnName('end_time'),
395
                $this->quoteColumnName('breakpoint'),
396
                $migration->getVersion(),
397
                substr($migration->getName(), 0, 100),
398
                $startTime,
399
                $endTime,
400
                $this->castToBool(false)
401
            );
402
403
            $this->execute($sql);
404
        } else {
405
            // down
406
            $sql = sprintf(
407
                "DELETE FROM %s WHERE %s = '%s'",
408
                $this->quoteTableName($this->getSchemaTableName()),
409
                $this->quoteColumnName('version'),
410
                $migration->getVersion()
411
            );
412
413
            $this->execute($sql);
414
        }
415
416
        return $this;
417
    }
418
419
    /**
420
     * @inheritDoc
421
     */
422
    public function toggleBreakpoint(MigrationInterface $migration)
423
    {
424
        $this->query(
425
            sprintf(
426
                'UPDATE %1$s SET %2$s = CASE %2$s WHEN %3$s THEN %4$s ELSE %3$s END, %7$s = %7$s WHERE %5$s = \'%6$s\';',
427
                $this->getSchemaTableName(),
428
                $this->quoteColumnName('breakpoint'),
429
                $this->castToBool(true),
430
                $this->castToBool(false),
431
                $this->quoteColumnName('version'),
432
                $migration->getVersion(),
433
                $this->quoteColumnName('start_time')
434
            )
435
        );
436
437
        return $this;
438
    }
439
440
    /**
441
     * @inheritDoc
442
     */
443
    public function resetAllBreakpoints()
444
    {
445
        return $this->execute(
446
            sprintf(
447
                'UPDATE %1$s SET %2$s = %3$s, %4$s = %4$s WHERE %2$s <> %3$s;',
448
                $this->getSchemaTableName(),
449
                $this->quoteColumnName('breakpoint'),
450
                $this->castToBool(false),
451
                $this->quoteColumnName('start_time')
452
            )
453
        );
454
    }
455
456
    /**
457
     * @inheritDoc
458
     */
459
    public function setBreakpoint(MigrationInterface $migration)
460
    {
461
        return $this->markBreakpoint($migration, true);
462
    }
463
464
    /**
465
     * @inheritDoc
466
     */
467
    public function unsetBreakpoint(MigrationInterface $migration)
468
    {
469
        return $this->markBreakpoint($migration, false);
470
    }
471
472
    /**
473
     * Mark a migration breakpoint.
474
     *
475
     * @param \Phinx\Migration\MigrationInterface $migration The migration target for the breakpoint
476
     * @param bool $state The required state of the breakpoint
477
     *
478
     * @return \Phinx\Db\Adapter\AdapterInterface
479
     */
480
    protected function markBreakpoint(MigrationInterface $migration, $state)
481
    {
482
        $this->query(
483
            sprintf(
484
                'UPDATE %1$s SET %2$s = %3$s, %4$s = %4$s WHERE %5$s = \'%6$s\';',
485
                $this->getSchemaTableName(),
486
                $this->quoteColumnName('breakpoint'),
487
                $this->castToBool($state),
488
                $this->quoteColumnName('start_time'),
489
                $this->quoteColumnName('version'),
490
                $migration->getVersion()
491
            )
492
        );
493
494
        return $this;
495
    }
496
497
    /**
498
     * {@inheritDoc}
499
     *
500
     * @throws \BadMethodCallException
501
     *
502
     * @return void
503
     */
504
    public function createSchema($schemaName = 'public')
505
    {
506
        throw new BadMethodCallException('Creating a schema is not supported');
507
    }
508
509
    /**
510
     * {@inheritDoc}
511
     *
512
     * @throws \BadMethodCallException
513
     *
514
     * @return void
515
     */
516
    public function dropSchema($name)
517
    {
518
        throw new BadMethodCallException('Dropping a schema is not supported');
519
    }
520
521
    /**
522
     * @inheritDoc
523
     */
524
    public function getColumnTypes()
525
    {
526
        return [
527
            'string',
528
            'char',
529
            'text',
530
            'smallinteger',
531
            'integer',
532
            'biginteger',
533
            'bit',
534
            'float',
535
            'decimal',
536
            'double',
537
            'datetime',
538
            'timestamp',
539
            'time',
540
            'date',
541
            'blob',
542
            'binary',
543
            'varbinary',
544
            'boolean',
545
            'uuid',
546
            // Geospatial data types
547
            'geometry',
548
            'point',
549
            'linestring',
550
            'polygon',
551
        ];
552
    }
553
554
    /**
555
     * @inheritDoc
556
     */
557
    public function castToBool($value)
558
    {
559
        return (bool)$value ? 1 : 0;
560
    }
561
562
    /**
563
     * Retrieve a database connection attribute
564
     *
565
     * @see http://php.net/manual/en/pdo.getattribute.php
566
     *
567
     * @param int $attribute One of the PDO::ATTR_* constants
568
     *
569
     * @return mixed
570
     */
571
    public function getAttribute($attribute)
572
    {
573
        return $this->connection->getAttribute($attribute);
574
    }
575
576
    /**
577
     * Get the definition for a `DEFAULT` statement.
578
     *
579
     * @param mixed $default Default value
580
     * @param string|null $columnType column type added
581
     *
582
     * @return string
583
     */
584 View Code Duplication
    protected function getDefaultValueDefinition($default, $columnType = 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...
585
    {
586
        if (is_string($default) && $default !== 'CURRENT_TIMESTAMP') {
587
            $default = $this->getConnection()->quote($default);
588
        } elseif (is_bool($default)) {
589
            $default = $this->castToBool($default);
590
        } elseif ($default !== null && $columnType === static::PHINX_TYPE_BOOLEAN) {
591
            $default = $this->castToBool((bool)$default);
592
        }
593
594
        return isset($default) ? " DEFAULT $default" : '';
595
    }
596
597
    /**
598
     * Executes all the ALTER TABLE instructions passed for the given table
599
     *
600
     * @param string $tableName The table name to use in the ALTER statement
601
     * @param \Phinx\Db\Util\AlterInstructions $instructions The object containing the alter sequence
602
     *
603
     * @return void
604
     */
605
    protected function executeAlterSteps($tableName, AlterInstructions $instructions)
606
    {
607
        $alter = sprintf('ALTER TABLE %s %%s', $this->quoteTableName($tableName));
608
        $instructions->execute($alter, [$this, 'execute']);
609
    }
610
611
    /**
612
     * {@inheritDoc}
613
     *
614
     * @return void
615
     */
616
    public function addColumn(Table $table, Column $column)
617
    {
618
        $instructions = $this->getAddColumnInstructions($table, $column);
619
        $this->executeAlterSteps($table->getName(), $instructions);
620
    }
621
622
    /**
623
     * Returns the instructions to add the specified column to a database table.
624
     *
625
     * @param \Phinx\Db\Table\Table $table Table
626
     * @param \Phinx\Db\Table\Column $column Column
627
     *
628
     * @return \Phinx\Db\Util\AlterInstructions
629
     */
630
    abstract protected function getAddColumnInstructions(Table $table, Column $column);
631
632
    /**
633
     * {@inheritDoc}
634
     *
635
     * @return void
636
     */
637
    public function renameColumn($tableName, $columnName, $newColumnName)
638
    {
639
        $instructions = $this->getRenameColumnInstructions($tableName, $columnName, $newColumnName);
640
        $this->executeAlterSteps($tableName, $instructions);
641
    }
642
643
    /**
644
     * Returns the instructions to rename the specified column.
645
     *
646
     * @param string $tableName Table Name
647
     * @param string $columnName Column Name
648
     * @param string $newColumnName New Column Name
649
     *
650
     * @return AlterInstructions:w
0 ignored issues
show
Documentation introduced by
The doc-type AlterInstructions:w could not be parsed: Unknown type name "AlterInstructions:w" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
651
     */
652
    abstract protected function getRenameColumnInstructions($tableName, $columnName, $newColumnName);
653
654
    /**
655
     * {@inheritDoc}
656
     *
657
     * @return void
658
     */
659
    public function changeColumn($tableName, $columnName, Column $newColumn)
660
    {
661
        $instructions = $this->getChangeColumnInstructions($tableName, $columnName, $newColumn);
662
        $this->executeAlterSteps($tableName, $instructions);
663
    }
664
665
    /**
666
     * Returns the instructions to change a table column type.
667
     *
668
     * @param string $tableName Table Name
669
     * @param string $columnName Column Name
670
     * @param \Phinx\Db\Table\Column $newColumn New Column
671
     *
672
     * @return \Phinx\Db\Util\AlterInstructions
673
     */
674
    abstract protected function getChangeColumnInstructions($tableName, $columnName, Column $newColumn);
675
676
    /**
677
     * {@inheritDoc}
678
     *
679
     * @return void
680
     */
681
    public function dropColumn($tableName, $columnName)
682
    {
683
        $instructions = $this->getDropColumnInstructions($tableName, $columnName);
684
        $this->executeAlterSteps($tableName, $instructions);
685
    }
686
687
    /**
688
     * Returns the instructions to drop the specified column.
689
     *
690
     * @param string $tableName Table Name
691
     * @param string $columnName Column Name
692
     *
693
     * @return \Phinx\Db\Util\AlterInstructions
694
     */
695
    abstract protected function getDropColumnInstructions($tableName, $columnName);
696
697
    /**
698
     * {@inheritDoc}
699
     *
700
     * @return void
701
     */
702
    public function addIndex(Table $table, Index $index)
703
    {
704
        $instructions = $this->getAddIndexInstructions($table, $index);
705
        $this->executeAlterSteps($table->getName(), $instructions);
706
    }
707
708
    /**
709
     * Returns the instructions to add the specified index to a database table.
710
     *
711
     * @param \Phinx\Db\Table\Table $table Table
712
     * @param \Phinx\Db\Table\Index $index Index
713
     *
714
     * @return \Phinx\Db\Util\AlterInstructions
715
     */
716
    abstract protected function getAddIndexInstructions(Table $table, Index $index);
717
718
    /**
719
     * {@inheritDoc}
720
     *
721
     * @return void
722
     */
723
    public function dropIndex($tableName, $columns)
724
    {
725
        $instructions = $this->getDropIndexByColumnsInstructions($tableName, $columns);
726
        $this->executeAlterSteps($tableName, $instructions);
727
    }
728
729
    /**
730
     * Returns the instructions to drop the specified index from a database table.
731
     *
732
     * @param string $tableName The name of of the table where the index is
733
     * @param mixed $columns Column(s)
734
     *
735
     * @return \Phinx\Db\Util\AlterInstructions
736
     */
737
    abstract protected function getDropIndexByColumnsInstructions($tableName, $columns);
738
739
    /**
740
     * {@inheritDoc}
741
     *
742
     * @return void
743
     */
744
    public function dropIndexByName($tableName, $indexName)
745
    {
746
        $instructions = $this->getDropIndexByNameInstructions($tableName, $indexName);
747
        $this->executeAlterSteps($tableName, $instructions);
748
    }
749
750
    /**
751
     * Returns the instructions to drop the index specified by name from a database table.
752
     *
753
     * @param string $tableName The table name whe the index is
754
     * @param string $indexName The name of the index
755
     *
756
     * @return \Phinx\Db\Util\AlterInstructions
757
     */
758
    abstract protected function getDropIndexByNameInstructions($tableName, $indexName);
759
760
    /**
761
     * {@inheritDoc}
762
     *
763
     * @return void
764
     */
765
    public function addForeignKey(Table $table, ForeignKey $foreignKey)
766
    {
767
        $instructions = $this->getAddForeignKeyInstructions($table, $foreignKey);
768
        $this->executeAlterSteps($table->getName(), $instructions);
769
    }
770
771
    /**
772
     * Returns the instructions to adds the specified foreign key to a database table.
773
     *
774
     * @param \Phinx\Db\Table\Table $table The table to add the constraint to
775
     * @param \Phinx\Db\Table\ForeignKey $foreignKey The foreign key to add
776
     *
777
     * @return \Phinx\Db\Util\AlterInstructions
778
     */
779
    abstract protected function getAddForeignKeyInstructions(Table $table, ForeignKey $foreignKey);
780
781
    /**
782
     * {@inheritDoc}
783
     *
784
     * @return void
785
     */
786
    public function dropForeignKey($tableName, $columns, $constraint = null)
787
    {
788
        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...
789
            $instructions = $this->getDropForeignKeyInstructions($tableName, $constraint);
790
        } else {
791
            $instructions = $this->getDropForeignKeyByColumnsInstructions($tableName, $columns);
792
        }
793
794
        $this->executeAlterSteps($tableName, $instructions);
795
    }
796
797
    /**
798
     * Returns the instructions to drop the specified foreign key from a database table.
799
     *
800
     * @param string $tableName The table where the foreign key constraint is
801
     * @param string $constraint Constraint name
802
     *
803
     * @return \Phinx\Db\Util\AlterInstructions
804
     */
805
    abstract protected function getDropForeignKeyInstructions($tableName, $constraint);
806
807
    /**
808
     * Returns the instructions to drop the specified foreign key from a database table.
809
     *
810
     * @param string $tableName The table where the foreign key constraint is
811
     * @param array $columns The list of column names
812
     *
813
     * @return \Phinx\Db\Util\AlterInstructions
814
     */
815
    abstract protected function getDropForeignKeyByColumnsInstructions($tableName, $columns);
816
817
    /**
818
     * {@inheritDoc}
819
     *
820
     * @return void
821
     */
822
    public function dropTable($tableName)
823
    {
824
        $instructions = $this->getDropTableInstructions($tableName);
825
        $this->executeAlterSteps($tableName, $instructions);
826
    }
827
828
    /**
829
     * Returns the instructions to drop the specified database table.
830
     *
831
     * @param string $tableName Table Name
832
     *
833
     * @return \Phinx\Db\Util\AlterInstructions
834
     */
835
    abstract protected function getDropTableInstructions($tableName);
836
837
    /**
838
     * {@inheritDoc}
839
     *
840
     * @return void
841
     */
842
    public function renameTable($tableName, $newTableName)
843
    {
844
        $instructions = $this->getRenameTableInstructions($tableName, $newTableName);
845
        $this->executeAlterSteps($tableName, $instructions);
846
    }
847
848
    /**
849
     * Returns the instructions to rename the specified database table.
850
     *
851
     * @param string $tableName Table Name
852
     * @param string $newTableName New Name
853
     *
854
     * @return \Phinx\Db\Util\AlterInstructions
855
     */
856
    abstract protected function getRenameTableInstructions($tableName, $newTableName);
857
858
    /**
859
     * {@inheritDoc}
860
     *
861
     * @return void
862
     */
863
    public function changePrimaryKey(Table $table, $newColumns)
864
    {
865
        $instructions = $this->getChangePrimaryKeyInstructions($table, $newColumns);
866
        $this->executeAlterSteps($table->getName(), $instructions);
867
    }
868
869
    /**
870
     * Returns the instructions to change the primary key for the specified database table.
871
     *
872
     * @param \Phinx\Db\Table\Table $table Table
873
     * @param string|array|null $newColumns Column name(s) to belong to the primary key, or null to drop the key
874
     *
875
     * @return \Phinx\Db\Util\AlterInstructions
876
     */
877
    abstract protected function getChangePrimaryKeyInstructions(Table $table, $newColumns);
878
879
    /**
880
     * {@inheritDoc}
881
     *
882
     * @return void
883
     */
884
    public function changeComment(Table $table, $newComment)
885
    {
886
        $instructions = $this->getChangeCommentInstructions($table, $newComment);
887
        $this->executeAlterSteps($table->getName(), $instructions);
888
    }
889
890
    /**
891
     * Returns the instruction to change the comment for the specified database table.
892
     *
893
     * @param \Phinx\Db\Table\Table $table Table
894
     * @param string|null $newComment New comment string, or null to drop the comment
895
     *
896
     * @return \Phinx\Db\Util\AlterInstructions
897
     */
898
    abstract protected function getChangeCommentInstructions(Table $table, $newComment);
899
900
    /**
901
     * {@inheritDoc}
902
     *
903
     * @throws \InvalidArgumentException
904
     *
905
     * @return void
906
     */
907
    public function executeActions(Table $table, array $actions)
908
    {
909
        $instructions = new AlterInstructions();
910
911
        foreach ($actions as $action) {
912
            switch (true) {
913
                case ($action instanceof AddColumn):
914
                    $instructions->merge($this->getAddColumnInstructions($table, $action->getColumn()));
915
                    break;
916
917
                case ($action instanceof AddIndex):
918
                    $instructions->merge($this->getAddIndexInstructions($table, $action->getIndex()));
919
                    break;
920
921
                case ($action instanceof AddForeignKey):
922
                    $instructions->merge($this->getAddForeignKeyInstructions($table, $action->getForeignKey()));
923
                    break;
924
925
                case ($action instanceof ChangeColumn):
926
                    $instructions->merge($this->getChangeColumnInstructions(
927
                        $table->getName(),
928
                        $action->getColumnName(),
929
                        $action->getColumn()
930
                    ));
931
                    break;
932
933
                case ($action instanceof DropForeignKey && !$action->getForeignKey()->getConstraint()):
934
                    $instructions->merge($this->getDropForeignKeyByColumnsInstructions(
935
                        $table->getName(),
936
                        $action->getForeignKey()->getColumns()
937
                    ));
938
                    break;
939
940
                case ($action instanceof DropForeignKey && $action->getForeignKey()->getConstraint()):
941
                    $instructions->merge($this->getDropForeignKeyInstructions(
942
                        $table->getName(),
943
                        $action->getForeignKey()->getConstraint()
0 ignored issues
show
Bug introduced by
It seems like $action->getForeignKey()->getConstraint() targeting Phinx\Db\Table\ForeignKey::getConstraint() can also be of type boolean; however, Phinx\Db\Adapter\PdoAdap...oreignKeyInstructions() 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...
944
                    ));
945
                    break;
946
947
                case ($action instanceof DropIndex && $action->getIndex()->getName() !== null):
948
                    $instructions->merge($this->getDropIndexByNameInstructions(
949
                        $table->getName(),
950
                        $action->getIndex()->getName()
951
                    ));
952
                    break;
953
954
                case ($action instanceof DropIndex && $action->getIndex()->getName() == null):
955
                    $instructions->merge($this->getDropIndexByColumnsInstructions(
956
                        $table->getName(),
957
                        $action->getIndex()->getColumns()
958
                    ));
959
                    break;
960
961
                case ($action instanceof DropTable):
962
                    $instructions->merge($this->getDropTableInstructions(
963
                        $table->getName()
964
                    ));
965
                    break;
966
967
                case ($action instanceof RemoveColumn):
968
                    $instructions->merge($this->getDropColumnInstructions(
969
                        $table->getName(),
970
                        $action->getColumn()->getName()
971
                    ));
972
                    break;
973
974
                case ($action instanceof RenameColumn):
975
                    $instructions->merge($this->getRenameColumnInstructions(
976
                        $table->getName(),
977
                        $action->getColumn()->getName(),
978
                        $action->getNewName()
979
                    ));
980
                    break;
981
982
                case ($action instanceof RenameTable):
983
                    $instructions->merge($this->getRenameTableInstructions(
984
                        $table->getName(),
985
                        $action->getNewName()
986
                    ));
987
                    break;
988
989
                case ($action instanceof ChangePrimaryKey):
990
                    $instructions->merge($this->getChangePrimaryKeyInstructions(
991
                        $table,
992
                        $action->getNewColumns()
993
                    ));
994
                    break;
995
996
                case ($action instanceof ChangeComment):
997
                    $instructions->merge($this->getChangeCommentInstructions(
998
                        $table,
999
                        $action->getNewComment()
1000
                    ));
1001
                    break;
1002
1003
                default:
1004
                    throw new InvalidArgumentException(
1005
                        sprintf("Don't know how to execute action: '%s'", get_class($action))
1006
                    );
1007
            }
1008
        }
1009
1010
        $this->executeAlterSteps($table->getName(), $instructions);
1011
    }
1012
}
1013