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

PostgresAdapter::getSchemaName()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 0
cts 0
cp 0
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 3
nc 2
nop 0
crap 6
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
class PostgresAdapter extends PdoAdapter implements AdapterInterface
38
{
39
    const INT_SMALL = 65535;
40
41
    /**
42
     * Columns with comments
43
     *
44
     * @var array
45
     */
46
    protected $columnsWithComments = [];
47
48
    /**
49
     * {@inheritdoc}
50 68
     */
51
    public function connect()
52 68
    {
53 68
        if ($this->connection === null) {
54
            if (!class_exists('PDO') || !in_array('pgsql', \PDO::getAvailableDrivers(), true)) {
55
                // @codeCoverageIgnoreStart
56
                throw new \RuntimeException('You need to enable the PDO_Pgsql extension for Phinx to run properly.');
57
                // @codeCoverageIgnoreEnd
58
            }
59 68
60 68
            $db = null;
61
            $options = $this->getOptions();
62
63 68
            // if port is specified use it, otherwise use the PostgreSQL default
64 68 View Code Duplication
            if (isset($options['port'])) {
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...
65 68
                $dsn = 'pgsql:host=' . $options['host'] . ';port=' . $options['port'] . ';dbname=' . $options['name'];
66 1
            } else {
67
                $dsn = 'pgsql:host=' . $options['host'] . ';dbname=' . $options['name'];
68
            }
69
70 68
            try {
71 68
                $db = new \PDO($dsn, $options['user'], $options['pass'], [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]);
72 1
            } catch (\PDOException $exception) {
73 1
                throw new \InvalidArgumentException(sprintf(
74 1
                    'There was a problem connecting to the database: %s',
75 1
                    $exception->getMessage()
76
                ));
77
            }
78 68
79 68
            $this->setConnection($db);
80 68
        }
81
    }
82
83
    /**
84
     * {@inheritdoc}
85 68
     */
86
    public function disconnect()
87 68
    {
88 68
        $this->connection = null;
89
    }
90
91
    /**
92
     * {@inheritdoc}
93
     */
94
    public function hasTransactions()
95
    {
96
        return true;
97
    }
98
99
    /**
100
     * {@inheritdoc}
101
     */
102
    public function beginTransaction()
103
    {
104
        $this->execute('BEGIN');
105
    }
106
107
    /**
108
     * {@inheritdoc}
109
     */
110
    public function commitTransaction()
111
    {
112
        $this->execute('COMMIT');
113
    }
114
115
    /**
116
     * {@inheritdoc}
117
     */
118
    public function rollbackTransaction()
119
    {
120
        $this->execute('ROLLBACK');
121
    }
122
123
    /**
124
     * Quotes a schema name for use in a query.
125
     *
126
     * @param string $schemaName Schema Name
127
     * @return string
128 68
     */
129
    public function quoteSchemaName($schemaName)
130 68
    {
131
        return $this->quoteColumnName($schemaName);
132
    }
133
134
    /**
135
     * {@inheritdoc}
136 68
     */
137
    public function quoteTableName($tableName)
138 68
    {
139
        return $this->quoteSchemaName($this->getSchemaName()) . '.' . $this->quoteColumnName($tableName);
140
    }
141
142
    /**
143
     * {@inheritdoc}
144 68
     */
145
    public function quoteColumnName($columnName)
146 68
    {
147
        return '"' . $columnName . '"';
148
    }
149
150
    /**
151
     * {@inheritdoc}
152 68
     */
153
    public function hasTable($tableName)
154 68
    {
155 68
        $result = $this->getConnection()->query(
156
            sprintf(
157
                'SELECT *
158
                FROM information_schema.tables
159 68
                WHERE table_schema = %s
160 68
                AND lower(table_name) = lower(%s)',
161 68
                $this->getConnection()->quote($this->getSchemaName()),
162 68
                $this->getConnection()->quote($tableName)
163 68
            )
164
        );
165 68
166
        return $result->rowCount() === 1;
167
    }
168
169
    /**
170
     * {@inheritdoc}
171 68
     */
172
    public function createTable(Table $table)
173 68
    {
174
        $options = $table->getOptions();
175
176 68
         // Add the default primary key
177 68
        $columns = $table->getPendingColumns();
178 48 View Code Duplication
        if (!isset($options['id']) || (isset($options['id']) && $options['id'] === true)) {
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...
179 48
            $column = new Column();
180 48
            $column->setName('id')
181 48
                   ->setType('integer')
182
                   ->setIdentity(true);
183 48
184 48
            array_unshift($columns, $column);
185 68
            $options['primary_key'] = 'id';
186
        } elseif (isset($options['id']) && is_string($options['id'])) {
187 2
            // Handle id => "field_name" to support AUTO_INCREMENT
188 2
            $column = new Column();
189 2
            $column->setName($options['id'])
190 2
                   ->setType('integer')
191
                   ->setIdentity(true);
192 2
193 2
            array_unshift($columns, $column);
194 2
            $options['primary_key'] = $options['id'];
195
        }
196
197 68
        // TODO - process table options like collation etc
198 68
        $sql = 'CREATE TABLE ';
199
        $sql .= $this->quoteTableName($table->getName()) . ' (';
200 68
201 68
        $this->columnsWithComments = [];
202 68 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...
203
            $sql .= $this->quoteColumnName($column->getName()) . ' ' . $this->getColumnSqlDefinition($column) . ', ';
204
205 68
            // set column comments, if needed
206 6
            if ($column->getComment()) {
207 6
                $this->columnsWithComments[] = $column;
208 68
            }
209
        }
210
211 68
         // set the primary key(s)
212 68 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...
213 68
            $sql = rtrim($sql);
214 68
            $sql .= sprintf(' CONSTRAINT %s_pkey PRIMARY KEY (', $table->getName());
215 68
            if (is_string($options['primary_key'])) { // handle primary_key => 'id'
216 68
                $sql .= $this->quoteColumnName($options['primary_key']);
217
            } 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...
218
                $sql .= implode(',', array_map([$this, 'quoteColumnName'], $options['primary_key']));
219 1
            }
220 1
            $sql .= ')';
221 1
        } else {
222 1
            $sql = rtrim($sql, ', '); // no primary keys
223 1
        }
224 1
225 1
        // set the foreign keys
226 1
        $foreignKeys = $table->getForeignKeys();
227 1
        if (!empty($foreignKeys)) {
228 1
            foreach ($foreignKeys as $foreignKey) {
229 68
                $sql .= ', ' . $this->getForeignKeySqlDefinition($foreignKey, $table->getName());
230 68
            }
231 2
        }
232
233
        $sql .= ');';
234
235 68
        // process column comments
236 68
        if (!empty($this->columnsWithComments)) {
237 1
            foreach ($this->columnsWithComments as $column) {
238 1
                $sql .= $this->getColumnCommentSqlDefinition($column, $table->getName());
239 1
            }
240 1
        }
241
242 68
        // set the indexes
243
        $indexes = $table->getIndexes();
244
        if (!empty($indexes)) {
245 68
            foreach ($indexes as $index) {
246 6
                $sql .= $this->getIndexSqlDefinition($index, $table->getName());
247 6
            }
248 6
        }
249 6
250
        // execute the sql
251
        $this->execute($sql);
252
253 68
        // process table comments
254 68
        if (isset($options['comment'])) {
255 5
            $sql = sprintf(
256 5
                'COMMENT ON TABLE %s IS %s',
257 5
                $this->quoteTableName($table->getName()),
258 5
                $this->getConnection()->quote($options['comment'])
259
            );
260
            $this->execute($sql);
261 68
        }
262
    }
263
264 68
    /**
265 1
     * {@inheritdoc}
266 1
     */
267 1
    public function renameTable($tableName, $newTableName)
268 1
    {
269 1
        $sql = sprintf(
270 1
            'ALTER TABLE %s RENAME TO %s',
271 1
            $this->quoteTableName($tableName),
272 68
            $this->quoteColumnName($newTableName)
273
        );
274
        $this->execute($sql);
275
    }
276
277 1
    /**
278
     * {@inheritdoc}
279 1
     */
280 1
    public function dropTable($tableName)
281 1
    {
282 1
        $this->execute(sprintf('DROP TABLE %s', $this->quoteTableName($tableName)));
283 1
    }
284 1
285 1
    /**
286
     * {@inheritdoc}
287
     */
288
    public function truncateTable($tableName)
289
    {
290 1
        $sql = sprintf(
291
            'TRUNCATE TABLE %s',
292 1
            $this->quoteTableName($tableName)
293 1
        );
294
295
        $this->execute($sql);
296
    }
297
298 1
    /**
299
     * {@inheritdoc}
300 1
     */
301 1
    public function getColumns($tableName)
302 1
    {
303 1
        $columns = [];
304
        $sql = sprintf(
305 1
            "SELECT column_name, data_type, udt_name, is_identity, is_nullable,
306 1
             column_default, character_maximum_length, numeric_precision, numeric_scale
307
             FROM information_schema.columns
308
             WHERE table_name ='%s'",
309
            $tableName
310
        );
311 9
        $columnsInfo = $this->fetchAll($sql);
312
313 9
        foreach ($columnsInfo as $columnInfo) {
314 9
            $isUserDefined = $columnInfo['data_type'] === 'USER-DEFINED';
315
            if ($isUserDefined) {
316
                $columnType = Literal::from($columnInfo['udt_name']);
317
            } else {
318 9
                $columnType = $this->getPhinxType($columnInfo['data_type']);
319
            }
320 9
            // If the default value begins with a ' or looks like a function mark it as literal
321 9
            if (isset($columnInfo['column_default'][0]) && $columnInfo['column_default'][0] === "'") {
322
                if (preg_match('/^\'(.*)\'::[^:]+$/', $columnInfo['column_default'], $match)) {
323 9
                    // '' and \' are replaced with a single '
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...
324 9
                    $columnDefault = preg_replace('/[\'\\\\]\'/', "'", $match[1]);
325 9
                } else {
326 9
                    $columnDefault = Literal::from($columnInfo['column_default']);
327 9
                }
328 9
            } elseif (preg_match('/^\D[a-z_\d]*\(.*\)$/', $columnInfo['column_default'])) {
329 9
                $columnDefault = Literal::from($columnInfo['column_default']);
330 9
            } else {
331 9
                $columnDefault = $columnInfo['column_default'];
332
            }
333 9
334 1
            $column = new Column();
335 1
            $column->setName($columnInfo['column_name'])
336
                   ->setType($columnType)
337 9
                   ->setNull($columnInfo['is_nullable'] === 'YES')
338 5
                   ->setDefault($columnDefault)
339 5
                   ->setIdentity($columnInfo['is_identity'] === 'YES')
340 9
                   ->setPrecision($columnInfo['numeric_precision'])
341 9
                   ->setScale($columnInfo['numeric_scale']);
342 9
343
            if (preg_match('/\bwith time zone$/', $columnInfo['data_type'])) {
344
                $column->setTimezone(true);
345
            }
346
347
            if (isset($columnInfo['character_maximum_length'])) {
348 24
                $column->setLimit($columnInfo['character_maximum_length']);
349
            }
350 24
            $columns[] = $column;
351
        }
352
353 24
        return $columns;
354 24
    }
355 24
356
    /**
357 24
     * {@inheritdoc}
358
     */
359 24 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...
360 24
    {
361
        $sql = sprintf(
362
            "SELECT count(*)
363
            FROM information_schema.columns
364
            WHERE table_schema = '%s' AND table_name = '%s' AND column_name = '%s'",
365
            $this->getSchemaName(),
366 18
            $tableName,
367
            $columnName
368 18
        );
369 18
370 18
        $result = $this->fetchRow($sql);
371 18
372 18
        return $result['count'] > 0;
373 18
    }
374
375 18
    /**
376 18
     * {@inheritdoc}
377
     */
378
    public function addColumn(Table $table, Column $column)
379
    {
380
        $sql = sprintf(
381 3
            'ALTER TABLE %s ADD %s %s;',
382
            $this->quoteTableName($table->getName()),
383 3
            $this->quoteColumnName($column->getName()),
384
            $this->getColumnSqlDefinition($column)
385
        );
386 3
387 3
        if ($column->getComment()) {
388
            $sql .= $this->getColumnCommentSqlDefinition($column, $table->getName());
389 3
        }
390 3
391 3
        $this->execute($sql);
392 1
    }
393
394 2
    /**
395 2
     * {@inheritdoc}
396 2
     */
397 2
    public function renameColumn($tableName, $columnName, $newColumnName)
398 2
    {
399 2
        $sql = sprintf(
400 2
            "SELECT CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END AS column_exists
401 2
             FROM information_schema.columns
402 2
             WHERE table_name ='%s' AND column_name = '%s'",
403
            $tableName,
404
            $columnName
405
        );
406
        $result = $this->fetchRow($sql);
407 5
        if (!(bool)$result['column_exists']) {
408
            throw new \InvalidArgumentException("The specified column does not exist: $columnName");
409
        }
410
        $this->execute(
411 5
            sprintf(
412 5
                'ALTER TABLE %s RENAME COLUMN %s TO %s',
413 5
                $this->quoteTableName($tableName),
414 5
                $this->quoteColumnName($columnName),
415 5
                $this->quoteColumnName($newColumnName)
416 5
            )
417
        );
418 5
    }
419 5
420
    /**
421 5
     * {@inheritdoc}
422 5
     */
423
    public function changeColumn($tableName, $columnName, Column $newColumn)
424 5
    {
425 5
        // TODO - is it possible to merge these 3 queries into less?
426 5
        // change data type
427 5
        $sql = sprintf(
428 5
            'ALTER TABLE %s ALTER COLUMN %s TYPE %s',
429 5
            $this->quoteTableName($tableName),
430 2
            $this->quoteColumnName($columnName),
431 2
            $this->getColumnSqlDefinition($newColumn)
432 4
        );
433
        //NULL and DEFAULT cannot be set while changing column type
434 5
        $sql = preg_replace('/ NOT NULL/', '', $sql);
435 5
        $sql = preg_replace('/ NULL/', '', $sql);
436
        //If it is set, DEFAULT is the last definition
437 1
        $sql = preg_replace('/DEFAULT .*/', '', $sql);
438 1
        $this->execute($sql);
439 1
        // process null
440 1
        $sql = sprintf(
441 1
            'ALTER TABLE %s ALTER COLUMN %s',
442 1
            $this->quoteTableName($tableName),
443 1
            $this->quoteColumnName($columnName)
444 1
        );
445 1
        if ($newColumn->isNull()) {
446
            $sql .= ' DROP NOT NULL';
447 4
        } else {
448 4
            $sql .= ' SET NOT NULL';
449 4
        }
450 4
        $this->execute($sql);
451 4
        if (!is_null($newColumn->getDefault())) {
452 4
            //change default
453 4
            $this->execute(
454
                sprintf(
455
                    'ALTER TABLE %s ALTER COLUMN %s SET %s',
456 5
                    $this->quoteTableName($tableName),
457 1
                    $this->quoteColumnName($columnName),
458 1
                    $this->getDefaultValueDefinition($newColumn->getDefault())
459 1
                )
460 1
            );
461 1
        } else {
462 1
            //drop default
463 1
            $this->execute(
464 1
                sprintf(
465 1
                    'ALTER TABLE %s ALTER COLUMN %s DROP DEFAULT',
466
                    $this->quoteTableName($tableName),
467
                    $this->quoteColumnName($columnName)
468 5
                )
469 2
            );
470 2
        }
471 2
        // rename column
472 5
        if ($columnName !== $newColumn->getName()) {
473
            $this->execute(
474
                sprintf(
475
                    'ALTER TABLE %s RENAME COLUMN %s TO %s',
476
                    $this->quoteTableName($tableName),
477 1
                    $this->quoteColumnName($columnName),
478
                    $this->quoteColumnName($newColumn->getName())
479 1
                )
480 1
            );
481 1
        }
482 1
483 1
        // change column comment if needed
484 1
        if ($newColumn->getComment()) {
485 1
            $sql = $this->getColumnCommentSqlDefinition($newColumn, $tableName);
486 1
            $this->execute($sql);
487
        }
488
    }
489
490
    /**
491
     * {@inheritdoc}
492
     */
493
    public function dropColumn($tableName, $columnName)
494 9
    {
495
        $this->execute(
496 9
            sprintf(
497
                'ALTER TABLE %s DROP COLUMN %s',
498
                $this->quoteTableName($tableName),
499
                $this->quoteColumnName($columnName)
500
            )
501
        );
502
    }
503
504
    /**
505
     * Get an array of indexes from a particular table.
506
     *
507
     * @param string $tableName Table Name
508
     * @return array
509
     */
510 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...
511
    {
512
        $indexes = [];
513
        $sql = "SELECT
514 9
            i.relname AS index_name,
515 9
            a.attname AS column_name
516 9
        FROM
517 9
            pg_class t,
518 9
            pg_class i,
519 9
            pg_index ix,
520 9
            pg_attribute a
521 9
        WHERE
522 9
            t.oid = ix.indrelid
523
            AND i.oid = ix.indexrelid
524
            AND a.attrelid = t.oid
525
            AND a.attnum = ANY(ix.indkey)
526
            AND t.relkind = 'r'
527
            AND t.relname = '$tableName'
528 9
        ORDER BY
529
            t.relname,
530 9
            i.relname;";
531 4
        $rows = $this->fetchAll($sql);
532 4
        foreach ($rows as $row) {
533 9
            if (!isset($indexes[$row['index_name']])) {
534 9
                $indexes[$row['index_name']] = ['columns' => []];
535 9
            }
536 9
            $indexes[$row['index_name']]['columns'][] = strtolower($row['column_name']);
537 9
        }
538
539 8
        return $indexes;
540 8
    }
541
542
    /**
543
     * {@inheritdoc}
544
     */
545 View Code Duplication
    public function hasIndex($tableName, $columns)
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...
546 1
    {
547
        if (is_string($columns)) {
548 1
            $columns = [$columns];
549 1
        }
550 1
        $columns = array_map('strtolower', $columns);
551 1
        $indexes = $this->getIndexes($tableName);
552
        foreach ($indexes as $index) {
553
            if (array_diff($index['columns'], $columns) === array_diff($columns, $index['columns'])) {
554
                return true;
555
            }
556
        }
557
558
        return false;
559
    }
560 2
561
    /**
562 2
     * {@inheritdoc}
563 2
     */
564 2 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...
565
    {
566
        $indexes = $this->getIndexes($tableName);
567
        foreach ($indexes as $name => $index) {
568
            if ($name === $indexName) {
569 1
                return true;
570
            }
571 1
        }
572 1
573 1
        return false;
574
    }
575 1
576 1
    /**
577
     * {@inheritdoc}
578 1
     */
579 1
    public function addIndex(Table $table, Index $index)
580 1
    {
581 1
        $sql = $this->getIndexSqlDefinition($index, $table->getName());
582 1
        $this->execute($sql);
583 1
    }
584 1
585 1
    /**
586 1
     * {@inheritdoc}
587
     */
588 1
    public function dropIndex($tableName, $columns)
589
    {
590
        if (is_string($columns)) {
591
            $columns = [$columns]; // str to array
592
        }
593
594
        $indexes = $this->getIndexes($tableName);
595
        $columns = array_map('strtolower', $columns);
596 1
597
        foreach ($indexes as $indexName => $index) {
598 1
            $a = array_diff($columns, $index['columns']);
599 1
            if (empty($a)) {
600
                $this->execute(
601 1
                    sprintf(
602 1
                        'DROP INDEX IF EXISTS %s',
603 1
                        $this->quoteColumnName($indexName)
604
                    )
605
                );
606
607
                return;
608 3
            }
609
        }
610 3
    }
611 1
612 1
    /**
613 3
     * {@inheritdoc}
614 3
     */
615
    public function dropIndexByName($tableName, $indexName)
616
    {
617
        $sql = sprintf(
618
            'DROP INDEX IF EXISTS %s',
619
            $indexName
620 3
        );
621 3
        $this->execute($sql);
622 3
    }
623 3
624
    /**
625 1
     * {@inheritdoc}
626 1
     */
627 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...
628
    {
629
        if (is_string($columns)) {
630
            $columns = [$columns]; // str to array
631
        }
632
        $foreignKeys = $this->getForeignKeys($tableName);
633
        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...
634
            if (isset($foreignKeys[$constraint])) {
635
                return !empty($foreignKeys[$constraint]);
636 3
            }
637
638 3
            return false;
639 3
        } else {
640
            foreach ($foreignKeys as $key) {
641
                $a = array_diff($columns, $key['columns']);
642
                if (empty($a)) {
643
                    return true;
644
                }
645
            }
646
647
            return false;
648
        }
649
    }
650 3
651
    /**
652 3
     * Get an array of foreign keys from a particular table.
653 3
     *
654 3
     * @param string $tableName Table Name
655 3
     * @return array
656 3
     */
657 3 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...
658 3
    {
659 3
        $foreignKeys = [];
660
        $rows = $this->fetchAll(sprintf(
661
            "SELECT
662
                    tc.constraint_name,
663
                    tc.table_name, kcu.column_name,
664
                    ccu.table_name AS referenced_table_name,
665 2
                    ccu.column_name AS referenced_column_name
666
                FROM
667 2
                    information_schema.table_constraints AS tc
668 2
                    JOIN information_schema.key_column_usage AS kcu ON tc.constraint_name = kcu.constraint_name
669 2
                    JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name
670 2
                WHERE constraint_type = 'FOREIGN KEY' AND tc.table_name = '%s'
671 2
                ORDER BY kcu.position_in_unique_constraint",
672 2
            $tableName
673 2
        ));
674
        foreach ($rows as $row) {
675
            $foreignKeys[$row['constraint_name']]['table'] = $row['table_name'];
676
            $foreignKeys[$row['constraint_name']]['columns'][] = $row['column_name'];
677
            $foreignKeys[$row['constraint_name']]['referenced_table'] = $row['referenced_table_name'];
678 1
            $foreignKeys[$row['constraint_name']]['referenced_columns'][] = $row['referenced_column_name'];
679
        }
680 1
681
        return $foreignKeys;
682
    }
683
684 1
    /**
685 1
     * {@inheritdoc}
686 1
     */
687 1 View Code Duplication
    public function addForeignKey(Table $table, 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...
688 1
    {
689
        $sql = sprintf(
690 1
            'ALTER TABLE %s ADD %s',
691 1
            $this->quoteTableName($table->getName()),
692 1
            $this->getForeignKeySqlDefinition($foreignKey, $table->getName())
693 1
        );
694 1
        $this->execute($sql);
695
    }
696
697
    /**
698
     * {@inheritdoc}
699
     */
700 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...
701 1
    {
702 1
        if (is_string($columns)) {
703
            $columns = [$columns]; // str to array
704 1
        }
705
706 1
        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...
707 1
            $this->execute(
708 1
                sprintf(
709 1
                    'ALTER TABLE %s DROP CONSTRAINT %s',
710
                    $this->quoteTableName($tableName),
711 1
                    $constraint
712
                )
713
            );
714
        } else {
715
            foreach ($columns as $column) {
716 68
                $rows = $this->fetchAll(sprintf(
717
                    "SELECT CONSTRAINT_NAME
718
                      FROM information_schema.KEY_COLUMN_USAGE
719 68
                      WHERE TABLE_SCHEMA = CURRENT_SCHEMA()
720 14
                        AND TABLE_NAME IS NOT NULL
721
                        AND TABLE_NAME = '%s'
722 1
                        AND COLUMN_NAME = '%s'
723
                      ORDER BY POSITION_IN_UNIQUE_CONSTRAINT",
724 1
                    $tableName,
725
                    $column
726 14
                ));
727 68
728 68
                foreach ($rows as $row) {
729 68
                    $this->dropForeignKey($tableName, $columns, $row['constraint_name']);
730 68
                }
731 68
            }
732 68
        }
733 68
    }
734 68
735 68
    /**
736 68
     * {@inheritdoc}
737 68
     */
738 68
    public function getSqlType($type, $limit = null)
739 2
    {
740 68
        switch ($type) {
741 68
            case static::PHINX_TYPE_INTEGER:
742 68
                if ($limit && $limit == static::INT_SMALL) {
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
                    return [
744 68
                        'name' => 'smallint',
745 68
                        'limit' => static::INT_SMALL
746 68
                    ];
747 1
                }
748 68
749 68
                return ['name' => $type];
750 68
            case static::PHINX_TYPE_TEXT:
751 15
            case static::PHINX_TYPE_TIME:
752 15
            case static::PHINX_TYPE_DATE:
753 1
            case static::PHINX_TYPE_BOOLEAN:
754
            case static::PHINX_TYPE_JSON:
755
            case static::PHINX_TYPE_JSONB:
756
            case static::PHINX_TYPE_UUID:
757
            case static::PHINX_TYPE_CIDR:
758 14
            case static::PHINX_TYPE_INET:
759
            case static::PHINX_TYPE_MACADDR:
760
                return ['name' => $type];
761 14
            case static::PHINX_TYPE_DECIMAL:
762
                return ['name' => $type, 'precision' => 18, 'scale' => 0];
763
            case static::PHINX_TYPE_STRING:
764 14
                return ['name' => 'character varying', 'limit' => 255];
765
            case static::PHINX_TYPE_CHAR:
766
                return ['name' => 'character', 'limit' => 255];
767 14
            case static::PHINX_TYPE_BIG_INTEGER:
768
                return ['name' => 'bigint'];
769
            case static::PHINX_TYPE_FLOAT:
770 14
                return ['name' => 'real'];
771 14
            case static::PHINX_TYPE_DATETIME:
772 13
            case static::PHINX_TYPE_TIMESTAMP:
773
                return ['name' => 'timestamp'];
774
            case static::PHINX_TYPE_BLOB:
775 1
            case static::PHINX_TYPE_BINARY:
776 14
                return ['name' => 'bytea'];
777
            case static::PHINX_TYPE_INTERVAL:
778
                return ['name' => 'interval'];
779
            // Geospatial database types
780
            // Spatial storage in Postgres is done via the PostGIS extension,
781
            // which enables the use of the "geography" type in combination
782
            // with SRID 4326.
783
            case static::PHINX_TYPE_GEOMETRY:
784
                return ['name' => 'geography', 'type' => 'geometry', 'srid' => 4326];
785 10
            case static::PHINX_TYPE_POINT:
786
                return ['name' => 'geography', 'type' => 'point', 'srid' => 4326];
787
            case static::PHINX_TYPE_LINESTRING:
788 10
                return ['name' => 'geography', 'type' => 'linestring', 'srid' => 4326];
789 10
            case static::PHINX_TYPE_POLYGON:
790 6
                return ['name' => 'geography', 'type' => 'polygon', 'srid' => 4326];
791 10
            default:
792 10
                if ($this->isArrayType($type)) {
793
                    return ['name' => $type];
794 10
                }
795 2
                // Return array type
796 10
                throw new \RuntimeException('The type: "' . $type . '" is not supported');
797
        }
798 10
    }
799
800 10
    /**
801
     * Returns Phinx type by SQL type
802 1
     *
803
     * @param string $sqlType SQL type
804 1
     * @returns string Phinx type
805 10
     */
806 10
    public function getPhinxType($sqlType)
807 10
    {
808 9
        switch ($sqlType) {
809 5
            case 'character varying':
810 5
            case 'varchar':
811 3
                return static::PHINX_TYPE_STRING;
812 4
            case 'character':
813 4
            case 'char':
814 2
                return static::PHINX_TYPE_CHAR;
815 4
            case 'text':
816 4
                return static::PHINX_TYPE_TEXT;
817 2
            case 'json':
818 4
                return static::PHINX_TYPE_JSON;
819 1
            case 'jsonb':
820
                return static::PHINX_TYPE_JSONB;
821 4
            case 'smallint':
822 4
                return [
823 4
                    'name' => 'smallint',
824 4
                    'limit' => static::INT_SMALL
825 3
                ];
826 4
            case 'int':
827 2
            case 'int4':
828 4
            case 'integer':
829 4
                return static::PHINX_TYPE_INTEGER;
830 4
            case 'decimal':
831 4
            case 'numeric':
832 3
                return static::PHINX_TYPE_DECIMAL;
833 3
            case 'bigint':
834 3
            case 'int8':
835 3
                return static::PHINX_TYPE_BIG_INTEGER;
836 1
            case 'real':
837 1
            case 'float4':
838
                return static::PHINX_TYPE_FLOAT;
839
            case 'bytea':
840
                return static::PHINX_TYPE_BINARY;
841
            case 'interval':
842
                return static::PHINX_TYPE_INTERVAL;
843
            case 'time':
844
            case 'timetz':
845
            case 'time with time zone':
846
            case 'time without time zone':
847
                return static::PHINX_TYPE_TIME;
848
            case 'date':
849
                return static::PHINX_TYPE_DATE;
850
            case 'timestamp':
851
            case 'timestamptz':
852 1
            case 'timestamp with time zone':
853
            case 'timestamp without time zone':
854 1
                return static::PHINX_TYPE_DATETIME;
855 1
            case 'bool':
856 1
            case 'boolean':
857
                return static::PHINX_TYPE_BOOLEAN;
858
            case 'uuid':
859
                return static::PHINX_TYPE_UUID;
860
            case 'cidr':
861 2
                return static::PHINX_TYPE_CIDR;
862
            case 'inet':
863 2
                return static::PHINX_TYPE_INET;
864 2
            case 'macaddr':
865 2
                return static::PHINX_TYPE_MACADDR;
866
            default:
867
                throw new \RuntimeException('The PostgreSQL type: "' . $sqlType . '" is not supported');
868
        }
869
    }
870
871 1
    /**
872
     * {@inheritdoc}
873 1
     */
874 1
    public function createDatabase($name, $options = [])
875 1
    {
876 1
        $charset = isset($options['charset']) ? $options['charset'] : 'utf8';
877
        $this->execute(sprintf("CREATE DATABASE %s WITH ENCODING = '%s'", $name, $charset));
878
    }
879
880
    /**
881
     * {@inheritdoc}
882
     */
883
    public function hasDatabase($databaseName)
884 68
    {
885
        $sql = sprintf("SELECT count(*) FROM pg_database WHERE datname = '%s'", $databaseName);
886 68
        $result = $this->fetchRow($sql);
887 4
888 68
        return $result['count'] > 0;
889 68
    }
890 68
891 68
    /**
892
     * {@inheritdoc}
893
     */
894
    public function dropDatabase($name)
895
    {
896
        $this->disconnect();
897
        $this->execute(sprintf('DROP DATABASE IF EXISTS %s', $name));
898
        $this->connect();
899
    }
900 68
901
    /**
902 68
     * Gets the PostgreSQL Column Definition for a Column object.
903 68
     *
904 50
     * @param \Phinx\Db\Table\Column $column Column
905 50
     * @return string
906 68
     */
907 68
    protected function getColumnSqlDefinition(Column $column)
908
    {
909 68
        $buffer = [];
910 1
        if ($column->isIdentity()) {
911 1
            $buffer[] = $column->getType() == 'biginteger' ? 'BIGSERIAL' : 'SERIAL';
912 1
        } elseif ($column->getType() instanceof Literal) {
913 1
            $buffer[] = (string)$column->getType();
914 1
        } else {
915 68
            $sqlType = $this->getSqlType($column->getType(), $column->getLimit());
916
            $buffer[] = strtoupper($sqlType['name']);
917
918
            // integers cant have limits in postgres
919
            if (static::PHINX_TYPE_DECIMAL === $sqlType['name'] && ($column->getPrecision() || $column->getScale())) {
920
                $buffer[] = sprintf(
921
                    '(%s, %s)',
922 68
                    $column->getPrecision() ?: $sqlType['precision'],
923 68
                    $column->getScale() ?: $sqlType['scale']
924 68
                );
925 68
            } elseif (in_array($sqlType['name'], ['geography'])) {
926 68
                // geography type must be written with geometry type and srid, like this: geography(POLYGON,4326)
927
                $buffer[] = sprintf(
928
                    '(%s,%s)',
929 68
                    strtoupper($sqlType['type']),
930 68
                    $sqlType['srid']
931 68
                );
932 68
            } elseif (!in_array($sqlType['name'], ['integer', 'smallint', 'bigint'])) {
933 1
                if ($column->getLimit() || isset($sqlType['limit'])) {
934 1
                    $buffer[] = sprintf('(%s)', $column->getLimit() ?: $sqlType['limit']);
935
                }
936
            }
937 68
938
            $timeTypes = [
939 68
                'time',
940 68
                'timestamp',
941 68
            ];
942
            if (in_array($sqlType['name'], $timeTypes) && $column->isTimezone()) {
943 68
                $buffer[] = strtoupper('with time zone');
944
            }
945
        }
946
947
        $buffer[] = $column->isNull() ? 'NULL' : 'NOT NULL';
948
        $buffer = implode(' ', $buffer);
949
950
        if (!is_null($column->getDefault())) {
951
            $buffer .= $this->getDefaultValueDefinition($column->getDefault());
952
        }
953 6
954
        return $buffer;
955
    }
956 6
957 6
    /**
958 6
     * Gets the PostgreSQL Column Comment Defininition for a column object.
959
     *
960 6
     * @param \Phinx\Db\Table\Column $column Column
961 6
     * @param string $tableName Table name
962 6
     * @return string
963 6
     */
964
    protected function getColumnCommentSqlDefinition(Column $column, $tableName)
965 6
    {
966
        // passing 'null' is to remove column comment
967
        $comment = (strcasecmp($column->getComment(), 'NULL') !== 0)
968
                 ? $this->getConnection()->quote($column->getComment())
969
                 : 'NULL';
970
971
        return sprintf(
972
            'COMMENT ON COLUMN %s.%s IS %s;',
973
            $this->quoteSchemaName($tableName),
974
            $this->quoteColumnName($column->getName()),
975 7
            $comment
976
        );
977 7
    }
978 3
979 3
    /**
980 5
     * Gets the PostgreSQL Index Definition for an Index object.
981 5
     *
982
     * @param \Phinx\Db\Table\Index  $index Index
983
     * @param string $tableName Table name
984 5
     * @return string
985
     */
986 7
    protected function getIndexSqlDefinition(Index $index, $tableName)
987 7
    {
988 7 View Code Duplication
        if (is_string($index->getName())) {
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...
989 7
            $indexName = $index->getName();
990 7
        } else {
991 7
            $columnNames = $index->getColumns();
992 7
            if (is_string($columnNames)) {
993 7
                $columnNames = [$columnNames];
994
            }
995
            $indexName = sprintf('%s_%s', $tableName, implode('_', $columnNames));
996
        }
997
        $def = sprintf(
998
            "CREATE %s INDEX %s ON %s (%s);",
999
            ($index->getType() === Index::UNIQUE ? 'UNIQUE' : ''),
1000
            $indexName,
1001
            $this->quoteTableName($tableName),
1002
            implode(',', array_map([$this, 'quoteColumnName'], $index->getColumns()))
1003 3
        );
1004
1005 3
        return $def;
1006 3
    }
1007 3
1008 3
    /**
1009
     * Gets the MySQL Foreign Key Definition for an ForeignKey object.
1010
     *
1011 3
     * @param \Phinx\Db\Table\ForeignKey $foreignKey
1012
     * @param string     $tableName  Table name
1013
     * @return string
1014 3
     */
1015 View Code Duplication
    protected function getForeignKeySqlDefinition(ForeignKey $foreignKey, $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...
1016
    {
1017
        $constraintName = $foreignKey->getConstraint() ?: $tableName . '_' . implode('_', $foreignKey->getColumns());
1018
1019
        $def = ' CONSTRAINT "' . $constraintName . '" FOREIGN KEY ("' . implode('", "', $foreignKey->getColumns()) . '")';
1020 68
        $def .= " REFERENCES {$this->quoteTableName($foreignKey->getReferencedTable()->getName())} (\"" . implode('", "', $foreignKey->getReferencedColumns()) . '")';
1021
        if ($foreignKey->getOnDelete()) {
1022
            $def .= " ON DELETE {$foreignKey->getOnDelete()}";
1023 68
        }
1024 67
        if ($foreignKey->getOnUpdate()) {
1025 67
            $def .= " ON UPDATE {$foreignKey->getOnUpdate()}";
1026
        }
1027 68
1028
        return $def;
1029 68
    }
1030 68
1031
    /**
1032
     * {@inheritdoc}
1033
     */
1034
    public function createSchemaTable()
1035
    {
1036
        // Create the public/custom schema if it doesn't already exist
1037
        if ($this->hasSchema($this->getSchemaName()) === false) {
1038 68
            $this->createSchema($this->getSchemaName());
1039
        }
1040 68
1041 68
        $this->fetchAll(sprintf('SET search_path TO %s', $this->getSchemaName()));
1042 68
1043
        parent::createSchemaTable();
1044
    }
1045
1046
    /**
1047
     * Creates the specified schema.
1048
     *
1049
     * @param  string $schemaName Schema Name
1050 68
     * @return void
1051
     */
1052 68
    public function createSchema($schemaName = 'public')
1053
    {
1054
        $sql = sprintf('CREATE SCHEMA %s;', $this->quoteSchemaName($schemaName)); // from postgres 9.3 we can use "CREATE SCHEMA IF NOT EXISTS schema_name"
1055 68
        $this->execute($sql);
1056
    }
1057 68
1058 68
    /**
1059 68
     * Checks to see if a schema exists.
1060
     *
1061
     * @param string $schemaName Schema Name
1062
     * @return bool
1063
     */
1064
    public function hasSchema($schemaName)
1065
    {
1066
        $sql = sprintf(
1067
            "SELECT count(*)
1068 68
             FROM pg_namespace
1069
             WHERE nspname = '%s'",
1070 68
            $schemaName
1071 68
        );
1072 68
        $result = $this->fetchRow($sql);
1073
1074
        return $result['count'] > 0;
1075
    }
1076
1077
    /**
1078
     * Drops the specified schema table.
1079 68
     *
1080
     * @param string $schemaName Schema name
1081 68
     * @return void
1082 68
     */
1083 68
    public function dropSchema($schemaName)
1084 68
    {
1085
        $sql = sprintf("DROP SCHEMA IF EXISTS %s CASCADE;", $this->quoteSchemaName($schemaName));
1086
        $this->execute($sql);
1087
    }
1088
1089
    /**
1090
     * Drops all schemas.
1091 68
     *
1092
     * @return void
1093
     */
1094
    public function dropAllSchemas()
1095 68
    {
1096 68
        foreach ($this->getAllSchemas() as $schema) {
1097 68
            $this->dropSchema($schema);
1098 68
        }
1099 68
    }
1100 68
1101 68
    /**
1102
     * Returns schemas.
1103
     *
1104
     * @return array
1105
     */
1106
    public function getAllSchemas()
1107 73
    {
1108
        $sql = "SELECT schema_name
1109 73
                FROM information_schema.schemata
1110
                WHERE schema_name <> 'information_schema' AND schema_name !~ '^pg_'";
1111
        $items = $this->fetchAll($sql);
1112
        $schemaNames = [];
1113
        foreach ($items as $item) {
1114
            $schemaNames[] = $item['schema_name'];
1115 73
        }
1116
1117
        return $schemaNames;
1118 73
    }
1119
1120
    /**
1121
     * {@inheritdoc}
1122
     */
1123
    public function getColumnTypes()
1124
    {
1125
        return array_merge(parent::getColumnTypes(), ['json', 'jsonb', 'cidr', 'inet', 'macaddr', 'interval']);
1126
    }
1127 14
1128
    /**
1129 14
     * {@inheritdoc}
1130 1
     */
1131
    public function isValidColumnType(Column $column)
1132
    {
1133 13
        // If not a standard column type, maybe it is array type?
1134 13
        return (parent::isValidColumnType($column) || $this->isArrayType($column->getType()));
0 ignored issues
show
Bug introduced by
It seems like $column->getType() targeting Phinx\Db\Table\Column::getType() can also be of type object<Phinx\Util\Literal>; however, Phinx\Db\Adapter\PostgresAdapter::isArrayType() 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...
1135
    }
1136
1137
    /**
1138
     * Check if the given column is an array of a valid type.
1139
     *
1140
     * @param  string $columnType
1141
     * @return bool
1142 68
     */
1143
    protected function isArrayType($columnType)
1144 68
    {
1145 68
        if (!preg_match('/^([a-z]+)(?:\[\]){1,}$/', $columnType, $matches)) {
1146
            return false;
1147
        }
1148
1149
        $baseType = $matches[1];
1150
1151 68
        return in_array($baseType, $this->getColumnTypes());
1152
    }
1153 68
1154
    /**
1155
     * Gets the schema name.
1156
     *
1157
     * @return string
1158
     */
1159
    private function getSchemaName()
1160
    {
1161
        $options = $this->getOptions();
1162
1163
        return empty($options['schema']) ? 'public' : $options['schema'];
1164
    }
1165
1166
    /**
1167
     * {@inheritdoc}
1168
     */
1169
    public function castToBool($value)
1170
    {
1171
        return (bool)$value ? 'TRUE' : 'FALSE';
1172
    }
1173
}
1174