PdoAdapter::dropForeignKey()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 9
c 0
b 0
f 0
ccs 0
cts 0
cp 0
rs 10
cc 2
nc 2
nop 3
crap 6
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 Phinx\Util\Literal;
35
use RuntimeException;
36
use Symfony\Component\Console\Output\OutputInterface;
37
38
/**
39
 * Phinx PDO Adapter.
40
 *
41
 * @author Rob Morgan <[email protected]>
42
 */
43
abstract class PdoAdapter extends AbstractAdapter implements DirectActionInterface
44
{
45
    /**
46
     * @var \PDO|null
47
     */
48
    protected $connection;
49
50
    /**
51 287
     * Writes a message to stdout if verbose output is on
52
     *
53 287
     * @param string $message The message to show
54
     * @return void
55 287
     */
56 3
    protected function verboseLog($message)
57 3
    {
58
        if (
59 287
            !$this->isDryRunEnabled() &&
60
             $this->getOutput()->getVerbosity() < OutputInterface::VERBOSITY_VERY_VERBOSE
61
        ) {
62
            return;
63
        }
64
65
        $this->getOutput()->writeln($message);
66
    }
67
68 193
    /**
69
     * Create PDO connection
70 193
     *
71
     * @param string $dsn Connection string
72
     * @param string|null $username Database username
73 193
     * @param string|null $password Database password
74 191
     * @param array $options Connection options
75 191
     * @return \PDO
76 74
     */
77 74
    protected function createPdoConnection($dsn, $username = null, $password = null, array $options = [])
78
    {
79
        $adapterOptions = $this->getOptions() + [
80
            'attr_errmode' => PDO::ERRMODE_EXCEPTION,
81
        ];
82
83
        try {
84
            $db = new PDO($dsn, $username, $password, $options);
85
86 74
            foreach ($adapterOptions as $key => $option) {
87
                if (strpos($key, 'attr_') === 0) {
88
                    $pdoConstant = '\PDO::' . strtoupper($key);
89
                    if (!defined($pdoConstant)) {
90
                        throw new \UnexpectedValueException('Invalid PDO attribute: ' . $key . ' (' . $pdoConstant . ')');
91
                    }
92
                    $db->setAttribute(constant($pdoConstant), $option);
93 193
                }
94
            }
95
        } catch (PDOException $e) {
96
            throw new InvalidArgumentException(sprintf(
97
                'There was a problem connecting to the database: %s',
98
                $e->getMessage()
99
            ), $e->getCode(), $e);
100
        }
101 191
102
        return $db;
103 191
    }
104 189
105 189
    /**
106 191
     * @inheritDoc
107
     */
108
    public function setOptions(array $options)
109
    {
110
        parent::setOptions($options);
111
112 1
        if (isset($options['connection'])) {
113
            $this->setConnection($options['connection']);
114 1
        }
115
116
        return $this;
117
    }
118
119
    /**
120
     * Sets the database connection.
121
     *
122
     * @param \PDO $connection Connection
123
     * @return \Phinx\Db\Adapter\AdapterInterface
124
     */
125
    public function setConnection(PDO $connection)
126 218
    {
127
        $this->connection = $connection;
128 218
129 3
        // Create the schema table if it doesn't already exist
130 3
        if (!$this->hasSchemaTable()) {
131
            $this->createSchemaTable();
132
        } else {
133 217
            $table = new DbTable($this->getSchemaTableName(), [], $this);
134
            if (!$table->hasColumn('migration_name')) {
135
                $table
136
                    ->addColumn(
137
                        'migration_name',
138
                        'string',
139
                        ['limit' => 100, 'after' => 'version', 'default' => null, 'null' => true]
140
                    )
141
                    ->save();
142 220
            }
143
            if (!$table->hasColumn('breakpoint')) {
144 220
                $table
145
                    ->addColumn('breakpoint', 'boolean', ['default' => false])
146
                    ->save();
147
            }
148
        }
149
150 151
        return $this;
151
    }
152 151
153 151
    /**
154
     * Gets the database connection
155
     *
156
     * @return \PDO
157
     */
158
    public function getConnection()
159 213
    {
160
        if ($this->connection === null) {
161 213
            $this->connect();
162 213
        }
163 213
164 208
        return $this->connection;
165 208
    }
166 213
167
    /**
168
     * @inheritDoc
169
     */
170
    public function connect()
171
    {
172 1
    }
173
174 1
    /**
175 1
     * @inheritDoc
176 1
     */
177 1
    public function disconnect()
178
    {
179 1
    }
180 1
181 1
    /**
182
     * @inheritDoc
183 1
     */
184 1
    public function execute($sql)
185 1
    {
186
        $sql = rtrim($sql, "; \t\n\r\0\x0B") . ';';
187
        $this->verboseLog($sql);
188
189
        if ($this->isDryRunEnabled()) {
190 11
            return 0;
191
        }
192 11
193 11
        return $this->getConnection()->exec($sql);
194 11
    }
195 11
196
    /**
197 11
     * Returns the Cake\Database connection object using the same underlying
198 11
     * PDO object as this connection.
199 11
     *
200
     * @return \Cake\Database\Connection
201 11
     */
202 11
    abstract public function getDecoratedConnection();
203 11
204 11
    /**
205 11
     * @inheritDoc
206 11
     */
207
    public function getQueryBuilder()
208 11
    {
209 11
        return $this->getDecoratedConnection()->newQuery();
210
    }
211 11
212 11
    /**
213 11
     * Executes a query and returns PDOStatement.
214
     *
215 11
     * @param string $sql SQL
216 11
     * @return \PDOStatement
217 11
     */
218
    public function query($sql)
219
    {
220
        return $this->getConnection()->query($sql);
221
    }
222 5
223
    /**
224 5
     * @inheritDoc
225
     */
226 5
    public function fetchRow($sql)
227
    {
228
        return $this->query($sql)->fetch();
229
    }
230
231
    /**
232 8
     * @inheritDoc
233
     */
234 8
    public function fetchAll($sql)
235
    {
236 8
        return $this->query($sql)->fetchAll();
237 8
    }
238 6
239 6
    /**
240 2
     * @inheritDoc
241 1
     */
242 1
    public function insert(Table $table, $row)
243 1
    {
244 1
        $sql = sprintf(
245 8
            'INSERT INTO %s ',
246
            $this->quoteTableName($table->getName())
247 7
        );
248 7
        $columns = array_keys($row);
249 7
        $sql .= '(' . implode(', ', array_map([$this, 'quoteColumnName'], $columns)) . ')';
250 7
251
        foreach ($row as $column => $value) {
252 7
            if (is_bool($value)) {
253
                $row[$column] = $this->castToBool($value);
254
            }
255
        }
256
257
        if ($this->isDryRunEnabled()) {
258 5
            $sql .= ' VALUES (' . implode(', ', array_map([$this, 'quoteValue'], $row)) . ');';
259
            $this->output->writeln($sql);
260 5
        } else {
261
            $sql .= ' VALUES (' . implode(', ', array_fill(0, count($columns), '?')) . ')';
262 5
            $stmt = $this->getConnection()->prepare($sql);
263 5
            $stmt->execute(array_values($row));
264 5
        }
265 5
    }
266 5
267 5
    /**
268 5
     * Quotes a database value.
269 5
     *
270 5
     * @param mixed $value The value to quote
271 5
     * @return mixed
272 5
     */
273 5
    protected function quoteValue($value)
274 5
    {
275 5
        if (is_numeric($value)) {
276
            return $value;
277 5
        }
278 5
279
        if ($value === null) {
280 3
            return 'null';
281 3
        }
282 3
283 3
        return $this->getConnection()->quote($value);
284 3
    }
285 3
286
    /**
287 3
     * Quotes a database string.
288
     *
289
     * @param string $value The string to quote
290 5
     * @return string
291
     */
292
    protected function quoteString($value)
293
    {
294
        return $this->getConnection()->quote($value);
295
    }
296 1
297
    /**
298 1
     * @inheritDoc
299 1
     */
300 1
    public function bulkinsert(Table $table, $rows)
301 1
    {
302 1
        $sql = sprintf(
303 1
            'INSERT INTO %s ',
304 1
            $this->quoteTableName($table->getName())
305 1
        );
306 1
        $current = current($rows);
307 1
        $keys = array_keys($current);
308 1
        $sql .= '(' . implode(', ', array_map([$this, 'quoteColumnName'], $keys)) . ') VALUES ';
309 1
310
        if ($this->isDryRunEnabled()) {
311 1
            $values = array_map(function ($row) {
312
                return '(' . implode(', ', array_map([$this, 'quoteValue'], $row)) . ')';
313
            }, $rows);
314
            $sql .= implode(', ', $values) . ';';
315
            $this->output->writeln($sql);
316
        } else {
317 1
            $count_keys = count($keys);
318
            $query = '(' . implode(', ', array_fill(0, $count_keys, '?')) . ')';
319 1
            $count_vars = count($rows);
320 1
            $queries = array_fill(0, $count_vars, $query);
321 1
            $sql .= implode(',', $queries);
322 1
            $stmt = $this->getConnection()->prepare($sql);
323 1
            $vals = [];
324 1
325 1
            foreach ($rows as $row) {
326 1
                foreach ($row as $v) {
327 1
                    if (is_bool($v)) {
328
                        $vals[] = $this->castToBool($v);
329
                    } else {
330
                        $vals[] = $v;
331
                    }
332
                }
333
            }
334
335
            $stmt->execute($vals);
336
        }
337
    }
338
339
    /**
340
     * @inheritDoc
341
     */
342
    public function getVersions()
343
    {
344
        $rows = $this->getVersionLog();
345
346
        return array_keys($rows);
347
    }
348
349 208
    /**
350
     * {@inheritDoc}
351
     *
352 208
     * @throws \RuntimeException
353 208
     */
354 208
    public function getVersionLog()
355 208
    {
356 208
        $result = [];
357 208
358 208
        switch ($this->options['version_order']) {
359 208
            case Config::VERSION_ORDER_CREATION_TIME:
360 208
                $orderBy = 'version ASC';
361 208
                break;
362 208
            case Config::VERSION_ORDER_EXECUTION_TIME:
363 208
                $orderBy = 'start_time ASC, version ASC';
364 208
                break;
365 208
            default:
366 208
                throw new RuntimeException('Invalid version_order configuration option');
367 208
        }
368
369 208
        // This will throw an exception if doing a --dry-run without any migrations as phinxlog
370 208
        // does not exist, so in that case, we can just expect to trivially return empty set
371 208
        try {
372 208
            $rows = $this->fetchAll(sprintf('SELECT * FROM %s ORDER BY %s', $this->quoteTableName($this->getSchemaTableName()), $orderBy));
373 208
        } catch (PDOException $e) {
374
            if (!$this->isDryRunEnabled()) {
375
                throw $e;
376
            }
377
            $rows = [];
378
        }
379 121
380
        foreach ($rows as $version) {
381 121
            $result[$version['version']] = $version;
382
        }
383
384
        return $result;
385
    }
386
387
    /**
388
     * @inheritDoc
389
     */
390
    public function migrated(MigrationInterface $migration, $direction, $startTime, $endTime)
391
    {
392
        if (strcasecmp($direction, MigrationInterface::UP) === 0) {
393
            // up
394
            $sql = sprintf(
395
                "INSERT INTO %s (%s, %s, %s, %s, %s) VALUES ('%s', '%s', '%s', '%s', %s);",
396
                $this->quoteTableName($this->getSchemaTableName()),
397
                $this->quoteColumnName('version'),
398
                $this->quoteColumnName('migration_name'),
399
                $this->quoteColumnName('start_time'),
400
                $this->quoteColumnName('end_time'),
401
                $this->quoteColumnName('breakpoint'),
402
                $migration->getVersion(),
403
                substr($migration->getName(), 0, 100),
404
                $startTime,
405
                $endTime,
406
                $this->castToBool(false)
407
            );
408
409
            $this->execute($sql);
410
        } else {
411
            // down
412
            $sql = sprintf(
413
                "DELETE FROM %s WHERE %s = '%s'",
414
                $this->quoteTableName($this->getSchemaTableName()),
415
                $this->quoteColumnName('version'),
416
                $migration->getVersion()
417
            );
418
419
            $this->execute($sql);
420
        }
421
422
        return $this;
423
    }
424
425
    /**
426
     * @inheritDoc
427
     */
428
    public function toggleBreakpoint(MigrationInterface $migration)
429
    {
430
        $this->query(
431
            sprintf(
432
                '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\';',
433
                $this->quoteTableName($this->getSchemaTableName()),
434
                $this->quoteColumnName('breakpoint'),
435
                $this->castToBool(true),
436
                $this->castToBool(false),
437
                $this->quoteColumnName('version'),
438
                $migration->getVersion(),
439
                $this->quoteColumnName('start_time')
440
            )
441
        );
442
443
        return $this;
444
    }
445
446
    /**
447
     * @inheritDoc
448
     */
449
    public function resetAllBreakpoints()
450
    {
451
        return $this->execute(
452
            sprintf(
453
                'UPDATE %1$s SET %2$s = %3$s, %4$s = %4$s WHERE %2$s <> %3$s;',
454
                $this->quoteTableName($this->getSchemaTableName()),
455
                $this->quoteColumnName('breakpoint'),
456
                $this->castToBool(false),
457
                $this->quoteColumnName('start_time')
458
            )
459
        );
460
    }
461
462
    /**
463
     * @inheritDoc
464
     */
465
    public function setBreakpoint(MigrationInterface $migration)
466
    {
467
        return $this->markBreakpoint($migration, true);
468
    }
469
470
    /**
471
     * @inheritDoc
472
     */
473
    public function unsetBreakpoint(MigrationInterface $migration)
474
    {
475
        return $this->markBreakpoint($migration, false);
476
    }
477
478
    /**
479
     * Mark a migration breakpoint.
480
     *
481
     * @param \Phinx\Migration\MigrationInterface $migration The migration target for the breakpoint
482
     * @param bool $state The required state of the breakpoint
483
     * @return \Phinx\Db\Adapter\AdapterInterface
484
     */
485
    protected function markBreakpoint(MigrationInterface $migration, $state)
486
    {
487
        $this->query(
488
            sprintf(
489
                'UPDATE %1$s SET %2$s = %3$s, %4$s = %4$s WHERE %5$s = \'%6$s\';',
490
                $this->quoteTableName($this->getSchemaTableName()),
491
                $this->quoteColumnName('breakpoint'),
492
                $this->castToBool($state),
493
                $this->quoteColumnName('start_time'),
494
                $this->quoteColumnName('version'),
495
                $migration->getVersion()
496
            )
497
        );
498
499
        return $this;
500
    }
501
502
    /**
503
     * {@inheritDoc}
504
     *
505
     * @throws \BadMethodCallException
506
     * @return void
507
     */
508
    public function createSchema($schemaName = 'public')
509
    {
510
        throw new BadMethodCallException('Creating a schema is not supported');
511
    }
512
513
    /**
514
     * {@inheritDoc}
515
     *
516
     * @throws \BadMethodCallException
517
     * @return void
518
     */
519
    public function dropSchema($name)
520
    {
521
        throw new BadMethodCallException('Dropping a schema is not supported');
522
    }
523
524
    /**
525
     * @inheritDoc
526
     */
527
    public function getColumnTypes()
528
    {
529
        return [
530
            'string',
531
            'char',
532
            'text',
533
            'tinyinteger',
534
            'smallinteger',
535
            'integer',
536
            'biginteger',
537
            'bit',
538
            'float',
539
            'decimal',
540
            'double',
541
            'datetime',
542
            'timestamp',
543
            'time',
544
            'date',
545
            'blob',
546
            'binary',
547
            'varbinary',
548
            'boolean',
549
            'uuid',
550
            // Geospatial data types
551
            'geometry',
552
            'point',
553
            'linestring',
554
            'polygon',
555
        ];
556
    }
557
558
    /**
559
     * @inheritDoc
560
     */
561
    public function castToBool($value)
562
    {
563
        return (bool)$value ? 1 : 0;
564
    }
565
566
    /**
567
     * Retrieve a database connection attribute
568
     *
569
     * @see http://php.net/manual/en/pdo.getattribute.php
570
     * @param int $attribute One of the PDO::ATTR_* constants
571
     * @return mixed
572
     */
573
    public function getAttribute($attribute)
574
    {
575
        return $this->connection->getAttribute($attribute);
0 ignored issues
show
Bug introduced by
The method getAttribute() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

575
        return $this->connection->/** @scrutinizer ignore-call */ getAttribute($attribute);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
576
    }
577
578
    /**
579
     * Get the definition for a `DEFAULT` statement.
580
     *
581
     * @param mixed $default Default value
582
     * @param string|null $columnType column type added
583
     * @return string
584
     */
585
    protected function getDefaultValueDefinition($default, $columnType = null)
586
    {
587
        if ($default instanceof Literal) {
588
            $default = (string)$default;
589
        } elseif (is_string($default) && strpos($default, 'CURRENT_TIMESTAMP') !== 0) {
590
            // Ensure a defaults of CURRENT_TIMESTAMP(3) is not quoted.
591
            $default = $this->getConnection()->quote($default);
592
        } elseif (is_bool($default)) {
593
            $default = $this->castToBool($default);
594
        } elseif ($default !== null && $columnType === static::PHINX_TYPE_BOOLEAN) {
595
            $default = $this->castToBool((bool)$default);
596
        }
597
598
        return isset($default) ? " DEFAULT $default" : '';
599
    }
600
601
    /**
602
     * Executes all the ALTER TABLE instructions passed for the given table
603
     *
604
     * @param string $tableName The table name to use in the ALTER statement
605
     * @param \Phinx\Db\Util\AlterInstructions $instructions The object containing the alter sequence
606
     * @return void
607
     */
608
    protected function executeAlterSteps($tableName, AlterInstructions $instructions)
609
    {
610
        $alter = sprintf('ALTER TABLE %s %%s', $this->quoteTableName($tableName));
611
        $instructions->execute($alter, [$this, 'execute']);
612
    }
613
614
    /**
615
     * @inheritDoc
616
     */
617
    public function addColumn(Table $table, Column $column)
618
    {
619
        $instructions = $this->getAddColumnInstructions($table, $column);
620
        $this->executeAlterSteps($table->getName(), $instructions);
621
    }
622
623
    /**
624
     * Returns the instructions to add the specified column to a database table.
625
     *
626
     * @param \Phinx\Db\Table\Table $table Table
627
     * @param \Phinx\Db\Table\Column $column Column
628
     * @return \Phinx\Db\Util\AlterInstructions
629
     */
630
    abstract protected function getAddColumnInstructions(Table $table, Column $column);
631
632
    /**
633
     * @inheritdoc
634
     */
635
    public function renameColumn($tableName, $columnName, $newColumnName)
636
    {
637
        $instructions = $this->getRenameColumnInstructions($tableName, $columnName, $newColumnName);
638
        $this->executeAlterSteps($tableName, $instructions);
639
    }
640
641
    /**
642
     * Returns the instructions to rename the specified column.
643
     *
644
     * @param string $tableName Table name
645
     * @param string $columnName Column Name
646
     * @param string $newColumnName New Column Name
647
     * @return \Phinx\Db\Util\AlterInstructions
648
     */
649
    abstract protected function getRenameColumnInstructions($tableName, $columnName, $newColumnName);
650
651
    /**
652
     * @inheritdoc
653
     */
654
    public function changeColumn($tableName, $columnName, Column $newColumn)
655
    {
656
        $instructions = $this->getChangeColumnInstructions($tableName, $columnName, $newColumn);
657
        $this->executeAlterSteps($tableName, $instructions);
658
    }
659
660
    /**
661
     * Returns the instructions to change a table column type.
662
     *
663
     * @param string $tableName Table name
664
     * @param string $columnName Column Name
665
     * @param \Phinx\Db\Table\Column $newColumn New Column
666
     * @return \Phinx\Db\Util\AlterInstructions
667
     */
668
    abstract protected function getChangeColumnInstructions($tableName, $columnName, Column $newColumn);
669
670
    /**
671
     * @inheritdoc
672
     */
673
    public function dropColumn($tableName, $columnName)
674
    {
675
        $instructions = $this->getDropColumnInstructions($tableName, $columnName);
676
        $this->executeAlterSteps($tableName, $instructions);
677
    }
678
679
    /**
680
     * Returns the instructions to drop the specified column.
681
     *
682
     * @param string $tableName Table name
683
     * @param string $columnName Column Name
684
     * @return \Phinx\Db\Util\AlterInstructions
685
     */
686
    abstract protected function getDropColumnInstructions($tableName, $columnName);
687
688
    /**
689
     * @inheritdoc
690
     */
691
    public function addIndex(Table $table, Index $index)
692
    {
693
        $instructions = $this->getAddIndexInstructions($table, $index);
694
        $this->executeAlterSteps($table->getName(), $instructions);
695
    }
696
697
    /**
698
     * Returns the instructions to add the specified index to a database table.
699
     *
700
     * @param \Phinx\Db\Table\Table $table Table
701
     * @param \Phinx\Db\Table\Index $index Index
702
     * @return \Phinx\Db\Util\AlterInstructions
703
     */
704
    abstract protected function getAddIndexInstructions(Table $table, Index $index);
705
706
    /**
707
     * @inheritdoc
708
     */
709
    public function dropIndex($tableName, $columns)
710
    {
711
        $instructions = $this->getDropIndexByColumnsInstructions($tableName, $columns);
712
        $this->executeAlterSteps($tableName, $instructions);
713
    }
714
715
    /**
716
     * Returns the instructions to drop the specified index from a database table.
717
     *
718
     * @param string $tableName The name of of the table where the index is
719
     * @param mixed $columns Column(s)
720
     * @return \Phinx\Db\Util\AlterInstructions
721
     */
722
    abstract protected function getDropIndexByColumnsInstructions($tableName, $columns);
723
724
    /**
725
     * @inheritdoc
726
     */
727
    public function dropIndexByName($tableName, $indexName)
728
    {
729
        $instructions = $this->getDropIndexByNameInstructions($tableName, $indexName);
730
        $this->executeAlterSteps($tableName, $instructions);
731
    }
732
733
    /**
734
     * Returns the instructions to drop the index specified by name from a database table.
735
     *
736
     * @param string $tableName The table name whe the index is
737
     * @param string $indexName The name of the index
738
     * @return \Phinx\Db\Util\AlterInstructions
739
     */
740
    abstract protected function getDropIndexByNameInstructions($tableName, $indexName);
741
742
    /**
743
     * @inheritdoc
744
     */
745
    public function addForeignKey(Table $table, ForeignKey $foreignKey)
746
    {
747
        $instructions = $this->getAddForeignKeyInstructions($table, $foreignKey);
748
        $this->executeAlterSteps($table->getName(), $instructions);
749
    }
750
751
    /**
752
     * Returns the instructions to adds the specified foreign key to a database table.
753
     *
754
     * @param \Phinx\Db\Table\Table $table The table to add the constraint to
755
     * @param \Phinx\Db\Table\ForeignKey $foreignKey The foreign key to add
756
     * @return \Phinx\Db\Util\AlterInstructions
757
     */
758
    abstract protected function getAddForeignKeyInstructions(Table $table, ForeignKey $foreignKey);
759
760
    /**
761
     * @inheritDoc
762
     */
763
    public function dropForeignKey($tableName, $columns, $constraint = null)
764
    {
765
        if ($constraint) {
766
            $instructions = $this->getDropForeignKeyInstructions($tableName, $constraint);
767
        } else {
768
            $instructions = $this->getDropForeignKeyByColumnsInstructions($tableName, $columns);
769
        }
770
771
        $this->executeAlterSteps($tableName, $instructions);
772
    }
773
774
    /**
775
     * Returns the instructions to drop the specified foreign key from a database table.
776
     *
777
     * @param string $tableName The table where the foreign key constraint is
778
     * @param string $constraint Constraint name
779
     * @return \Phinx\Db\Util\AlterInstructions
780
     */
781
    abstract protected function getDropForeignKeyInstructions($tableName, $constraint);
782
783
    /**
784
     * Returns the instructions to drop the specified foreign key from a database table.
785
     *
786
     * @param string $tableName The table where the foreign key constraint is
787
     * @param string[] $columns The list of column names
788
     * @return \Phinx\Db\Util\AlterInstructions
789
     */
790
    abstract protected function getDropForeignKeyByColumnsInstructions($tableName, $columns);
791
792
    /**
793
     * @inheritdoc
794
     */
795
    public function dropTable($tableName)
796
    {
797
        $instructions = $this->getDropTableInstructions($tableName);
798
        $this->executeAlterSteps($tableName, $instructions);
799
    }
800
801
    /**
802
     * Returns the instructions to drop the specified database table.
803
     *
804
     * @param string $tableName Table name
805
     * @return \Phinx\Db\Util\AlterInstructions
806
     */
807
    abstract protected function getDropTableInstructions($tableName);
808
809
    /**
810
     * @inheritdoc
811
     */
812
    public function renameTable($tableName, $newTableName)
813
    {
814
        $instructions = $this->getRenameTableInstructions($tableName, $newTableName);
815
        $this->executeAlterSteps($tableName, $instructions);
816
    }
817
818
    /**
819
     * Returns the instructions to rename the specified database table.
820
     *
821
     * @param string $tableName Table name
822
     * @param string $newTableName New Name
823
     * @return \Phinx\Db\Util\AlterInstructions
824
     */
825
    abstract protected function getRenameTableInstructions($tableName, $newTableName);
826
827
    /**
828
     * @inheritdoc
829
     */
830
    public function changePrimaryKey(Table $table, $newColumns)
831
    {
832
        $instructions = $this->getChangePrimaryKeyInstructions($table, $newColumns);
833
        $this->executeAlterSteps($table->getName(), $instructions);
834
    }
835
836
    /**
837
     * Returns the instructions to change the primary key for the specified database table.
838
     *
839
     * @param \Phinx\Db\Table\Table $table Table
840
     * @param string|string[]|null $newColumns Column name(s) to belong to the primary key, or null to drop the key
841
     * @return \Phinx\Db\Util\AlterInstructions
842
     */
843
    abstract protected function getChangePrimaryKeyInstructions(Table $table, $newColumns);
844
845
    /**
846
     * @inheritdoc
847
     */
848
    public function changeComment(Table $table, $newComment)
849
    {
850
        $instructions = $this->getChangeCommentInstructions($table, $newComment);
851
        $this->executeAlterSteps($table->getName(), $instructions);
852
    }
853
854
    /**
855
     * Returns the instruction to change the comment for the specified database table.
856
     *
857
     * @param \Phinx\Db\Table\Table $table Table
858
     * @param string|null $newComment New comment string, or null to drop the comment
859
     * @return \Phinx\Db\Util\AlterInstructions
860
     */
861
    abstract protected function getChangeCommentInstructions(Table $table, $newComment);
862
863
    /**
864
     * {@inheritDoc}
865
     *
866
     * @throws \InvalidArgumentException
867
     * @return void
868
     */
869
    public function executeActions(Table $table, array $actions)
870
    {
871
        $instructions = new AlterInstructions();
872
873
        foreach ($actions as $action) {
874
            switch (true) {
875
                case $action instanceof AddColumn:
876
                    $instructions->merge($this->getAddColumnInstructions($table, $action->getColumn()));
877
                    break;
878
879
                case $action instanceof AddIndex:
880
                    $instructions->merge($this->getAddIndexInstructions($table, $action->getIndex()));
881
                    break;
882
883
                case $action instanceof AddForeignKey:
884
                    $instructions->merge($this->getAddForeignKeyInstructions($table, $action->getForeignKey()));
885
                    break;
886
887
                case $action instanceof ChangeColumn:
888
                    $instructions->merge($this->getChangeColumnInstructions(
889
                        $table->getName(),
890
                        $action->getColumnName(),
891
                        $action->getColumn()
892
                    ));
893
                    break;
894
895
                case $action instanceof DropForeignKey && !$action->getForeignKey()->getConstraint():
896
                    $instructions->merge($this->getDropForeignKeyByColumnsInstructions(
897
                        $table->getName(),
898
                        $action->getForeignKey()->getColumns()
899
                    ));
900
                    break;
901
902
                case $action instanceof DropForeignKey && $action->getForeignKey()->getConstraint():
903
                    $instructions->merge($this->getDropForeignKeyInstructions(
904
                        $table->getName(),
905
                        $action->getForeignKey()->getConstraint()
906
                    ));
907
                    break;
908
909
                case $action instanceof DropIndex && $action->getIndex()->getName() !== null:
910
                    $instructions->merge($this->getDropIndexByNameInstructions(
911
                        $table->getName(),
912
                        $action->getIndex()->getName()
913
                    ));
914
                    break;
915
916
                case $action instanceof DropIndex && $action->getIndex()->getName() == null:
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $action->getIndex()->getName() of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
917
                    $instructions->merge($this->getDropIndexByColumnsInstructions(
918
                        $table->getName(),
919
                        $action->getIndex()->getColumns()
920
                    ));
921
                    break;
922
923
                case $action instanceof DropTable:
924
                    $instructions->merge($this->getDropTableInstructions(
925
                        $table->getName()
926
                    ));
927
                    break;
928
929
                case $action instanceof RemoveColumn:
930
                    $instructions->merge($this->getDropColumnInstructions(
931
                        $table->getName(),
932
                        $action->getColumn()->getName()
933
                    ));
934
                    break;
935
936
                case $action instanceof RenameColumn:
937
                    $instructions->merge($this->getRenameColumnInstructions(
938
                        $table->getName(),
939
                        $action->getColumn()->getName(),
940
                        $action->getNewName()
941
                    ));
942
                    break;
943
944
                case $action instanceof RenameTable:
945
                    $instructions->merge($this->getRenameTableInstructions(
946
                        $table->getName(),
947
                        $action->getNewName()
948
                    ));
949
                    break;
950
951
                case $action instanceof ChangePrimaryKey:
952
                    $instructions->merge($this->getChangePrimaryKeyInstructions(
953
                        $table,
954
                        $action->getNewColumns()
955
                    ));
956
                    break;
957
958
                case $action instanceof ChangeComment:
959
                    $instructions->merge($this->getChangeCommentInstructions(
960
                        $table,
961
                        $action->getNewComment()
962
                    ));
963
                    break;
964
965
                default:
966
                    throw new InvalidArgumentException(
967
                        sprintf("Don't know how to execute action: '%s'", get_class($action))
968
                    );
969
            }
970
        }
971
972
        $this->executeAlterSteps($table->getName(), $instructions);
973
    }
974
}
975