Completed
Pull Request — master (#1371)
by
unknown
04:33
created

SQLiteAdapter   D

Complexity

Total Complexity 168

Size/Duplication

Total Lines 1085
Duplicated Lines 12.35 %

Coupling/Cohesion

Components 3
Dependencies 8

Test Coverage

Coverage 86.84%

Importance

Changes 0
Metric Value
wmc 168
lcom 3
cbo 8
dl 134
loc 1085
ccs 541
cts 623
cp 0.8684
rs 4.415
c 0
b 0
f 0

45 Methods

Rating   Name   Duplication   Size   Complexity  
C connect() 0 35 7
A setOptions() 0 13 3
A disconnect() 0 4 1
A hasTransactions() 0 4 1
A beginTransaction() 0 4 1
A commitTransaction() 0 4 1
A rollbackTransaction() 0 4 1
A quoteTableName() 0 4 1
A quoteColumnName() 0 4 1
A hasTable() 0 10 2
C createTable() 12 63 15
A getRenameTableInstructions() 10 10 1
A getDropTableInstructions() 0 6 1
B getColumns() 0 25 3
A hasColumn() 11 11 3
A getAddColumnInstructions() 10 10 1
A getDeclaringSql() 0 13 3
A copyDataToNewTable() 0 11 1
A copyAndDropTmpTable() 0 17 1
B calculateNewTableColumns() 0 36 5
A beginAlterByCopyTable() 0 20 1
A getRenameColumnInstructions() 5 22 1
B getChangeColumnInstructions() 5 25 1
B getDropColumnInstructions() 5 28 2
A getIndexes() 0 17 4
A hasIndex() 18 18 4
A hasIndexByName() 12 12 3
A getAddIndexInstructions() 0 16 2
B getDropIndexByColumnsInstructions() 0 22 4
A getDropIndexByNameInstructions() 0 16 3
A hasForeignKey() 0 9 2
B getForeignKeys() 0 31 5
A getAddForeignKeyInstructions() 0 23 1
A getDropForeignKeyInstructions() 0 4 1
B getDropForeignKeyByColumnsInstructions() 0 40 4
D getSqlType() 0 43 23
C getPhinxType() 15 62 17
A createDatabase() 0 4 1
A hasDatabase() 0 4 1
A dropDatabase() 0 6 2
F getColumnSqlDefinition() 6 35 15
A getCommentDefinition() 0 8 2
A getIndexSqlDefinition() 0 20 4
B getForeignKeySqlDefinition() 25 26 6
B getDecoratedConnection() 0 23 4

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 SQLiteAdapter 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 SQLiteAdapter, and based on these observations, apply Extract Interface, too.

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 Cake\Database\Connection;
32
use Cake\Database\Driver\Sqlite as SqliteDriver;
33
use Phinx\Db\Table\Column;
34
use Phinx\Db\Table\ForeignKey;
35
use Phinx\Db\Table\Index;
36
use Phinx\Db\Table\Table;
37
use Phinx\Db\Util\AlterInstructions;
38
use Phinx\Util\Literal;
39
40
/**
41
 * Phinx SQLite Adapter.
42
 *
43
 * @author Rob Morgan <[email protected]>
44
 * @author Richard McIntyre <[email protected]>
45
 */
46
class SQLiteAdapter extends PdoAdapter implements AdapterInterface
47
{
48
    protected $definitionsWithLimits = [
49
        'CHARACTER',
50
        'VARCHAR',
51
        'VARYING CHARACTER',
52
        'NCHAR',
53
        'NATIVE CHARACTER',
54
        'NVARCHAR'
55
    ];
56 42
57
    protected $suffix = '.sqlite3';
58 42
59 42
    /**
60
     * {@inheritdoc}
61
     */
62
    public function connect()
63
    {
64
        if ($this->connection === null) {
65 42
            if (!class_exists('PDO') || !in_array('sqlite', \PDO::getAvailableDrivers(), true)) {
66 42
                // @codeCoverageIgnoreStart
67
                throw new \RuntimeException('You need to enable the PDO_SQLITE extension for Phinx to run properly.');
68
                // @codeCoverageIgnoreEnd
69 42
            }
70
71
            $db = null;
72 42
            $options = $this->getOptions();
73 42
74 42
            // if port is specified use it, otherwise use the MySQL default
75 42
            if (isset($options['memory'])) {
76
                $dsn = 'sqlite::memory:';
77
            } else {
78
                $dsn = 'sqlite:' . $options['name'];
79 42
                if (file_exists($options['name'] . $this->suffix)) {
80 42
                    $dsn = 'sqlite:' . $options['name'] . $this->suffix;
81
                }
82
            }
83
84
            try {
85
                $db = new \PDO($dsn);
86
            } catch (\PDOException $exception) {
87 42
                throw new \InvalidArgumentException(sprintf(
88 42
                    'There was a problem connecting to the database: %s',
89 42
                    $exception->getMessage()
90
                ));
91
            }
92
93
            $db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
94 48
            $this->setConnection($db);
95
        }
96 48
    }
97 48
98
    /**
99
     * {@inheritdoc}
100
     */
101
    public function setOptions(array $options)
102
    {
103
        parent::setOptions($options);
104
105
        if (isset($options['suffix'])) {
106
            $this->suffix = $options['suffix'];
107
        }
108
        if (substr($this->suffix, 0,1) !== '.') {
109
            $this->suffix = '.'.$this->suffix;
110 1
        }
111
112 1
        return $this;
113 1
    }
114
115
116
117
    /**
118
     * {@inheritdoc}
119
     */
120
    public function disconnect()
121
    {
122
        $this->connection = null;
123
    }
124
125
    /**
126
     * {@inheritdoc}
127
     */
128
    public function hasTransactions()
129
    {
130
        return true;
131
    }
132
133
    /**
134 43
     * {@inheritdoc}
135
     */
136 43
    public function beginTransaction()
137
    {
138
        $this->getConnection()->beginTransaction();
139
    }
140
141
    /**
142 44
     * {@inheritdoc}
143
     */
144 44
    public function commitTransaction()
145
    {
146
        $this->getConnection()->commit();
147
    }
148
149
    /**
150 42
     * {@inheritdoc}
151
     */
152 42
    public function rollbackTransaction()
153 42
    {
154 42
        $this->getConnection()->rollBack();
155 12
    }
156 42
157
    /**
158 42
     * {@inheritdoc}
159
     */
160
    public function quoteTableName($tableName)
161
    {
162
        return str_replace('.', '`.`', $this->quoteColumnName($tableName));
163
    }
164 42
165
    /**
166
     * {@inheritdoc}
167 42
     */
168 42
    public function quoteColumnName($columnName)
169 42
    {
170 35
        return '`' . str_replace('`', '``', $columnName) . '`';
171 35
    }
172 35
173 35
    /**
174
     * {@inheritdoc}
175 35
     */
176 42
    public function hasTable($tableName)
177
    {
178 1
        $tables = [];
179 1
        $rows = $this->fetchAll(sprintf('SELECT name FROM sqlite_master WHERE type=\'table\' AND name=\'%s\'', $tableName));
180 1
        foreach ($rows as $row) {
181 1
            $tables[] = strtolower($row[0]);
182
        }
183 1
184 1
        return in_array(strtolower($tableName), $tables);
185
    }
186
187 42
    /**
188 42
     * {@inheritdoc}
189 42
     */
190 42
    public function createTable(Table $table, array $columns = [], array $indexes = [])
191 42
    {
192
        // Add the default primary key
193
        $options = $table->getOptions();
194 42
        if (!isset($options['id']) || (isset($options['id']) && $options['id'] === true)) {
195 42
            $column = new Column();
196 42
            $column->setName('id')
197 42
                   ->setType('integer')
198 42
                   ->setIdentity(true);
199 42
200
            array_unshift($columns, $column);
201
        } elseif (isset($options['id']) && is_string($options['id'])) {
202 1
            // Handle id => "field_name" to support AUTO_INCREMENT
203 1
            $column = new Column();
204 1
            $column->setName($options['id'])
205
                   ->setType('integer')
206 1
                   ->setIdentity(true);
207 1
208 1
            array_unshift($columns, $column);
209 1
        }
210 1
211 1
        $sql = 'CREATE TABLE ';
212 42
        $sql .= $this->quoteTableName($table->getName()) . ' (';
213 42
        foreach ($columns as $column) {
214 37
            $sql .= $this->quoteColumnName($column->getName()) . ' ' . $this->getColumnSqlDefinition($column) . ', ';
215
216
            if (isset($options['primary_key']) && $column->getIdentity()) {
217
                //remove column from the primary key array as it is already defined as an autoincrement
218 42
                //primary id
219 42
                $identityColumnIndex = array_search($column->getName(), $options['primary_key']);
220 1
                if ($identityColumnIndex !== false) {
221 1
                    unset($options['primary_key'][$identityColumnIndex]);
222 1
223 1
                    if (empty($options['primary_key'])) {
224
                        //The last primary key has been removed
225 42
                        unset($options['primary_key']);
226
                    }
227 42
                }
228
            }
229 42
        }
230 6
231 42
        // set the primary key(s)
232 42 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...
233
            $sql = rtrim($sql);
234
            $sql .= ' PRIMARY KEY (';
235
            if (is_string($options['primary_key'])) { // handle primary_key => 'id'
236
                $sql .= $this->quoteColumnName($options['primary_key']);
237 1
            } 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...
238
                $sql .= implode(',', array_map([$this, 'quoteColumnName'], $options['primary_key']));
239 1
            }
240 1
            $sql .= ')';
241
        } else {
242
            $sql = substr(rtrim($sql), 0, -1); // no primary keys
243
        }
244
245 1
        $sql = rtrim($sql) . ');';
246
        // execute the sql
247 1
        $this->execute($sql);
248 1
249
        foreach ($indexes as $index) {
250
            $this->addIndex($table, $index);
251
        }
252
    }
253 1
254
    /**
255 1
     * {@inheritdoc}
256 1
     */
257 1 View Code Duplication
    protected function getRenameTableInstructions($tableName, $newTableName)
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...
258 1
    {
259
        $sql = sprintf(
260 1
            'ALTER TABLE %s RENAME TO %s',
261 1
            $this->quoteTableName($tableName),
262
            $this->quoteTableName($newTableName)
263
        );
264
265
        return new AlterInstructions([], [$sql]);
266 1
    }
267
268 1
    /**
269 1
     * {@inheritdoc}
270
     */
271 1
    protected function getDropTableInstructions($tableName)
272 1
    {
273 1
        $sql = sprintf('DROP TABLE %s', $this->quoteTableName($tableName));
274 1
275 1
        return new AlterInstructions([], [$sql]);
276 1
    }
277
278 1
    /**
279 1
     * {@inheritdoc}
280 1
     */
281
    public function truncateTable($tableName)
282 1
    {
283 1
        $sql = sprintf(
284 1
            'DELETE FROM %s',
285
            $this->quoteTableName($tableName)
286 1
        );
287 1
288
        $this->execute($sql);
289 1
    }
290
291
    /**
292
     * {@inheritdoc}
293
     */
294
    public function getColumns($tableName)
295 8
    {
296
        $columns = [];
297 8
        $rows = $this->fetchAll(sprintf('pragma table_info(%s)', $this->quoteTableName($tableName)));
298 8
299 8
        foreach ($rows as $columnInfo) {
300 7
            $column = new Column();
301
            $type = strtolower($columnInfo['type']);
302 8
            $column->setName($columnInfo['name'])
303
                   ->setNull($columnInfo['notnull'] !== '1')
304 8
                   ->setDefault($columnInfo['dflt_value']);
305
306
            $phinxType = $this->getPhinxType($type);
307
            $column->setType($phinxType['name'])
308
                   ->setLimit($phinxType['limit']);
309
310 4
            if ($columnInfo['pk'] == 1) {
311
                $column->setIdentity(true);
312 4
            }
313 4
314 4
            $columns[] = $column;
315 4
        }
316 4
317 4
        return $columns;
318
    }
319 4
320 4
    /**
321
     * {@inheritdoc}
322
     */
323 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...
324
    {
325 2
        $rows = $this->fetchAll(sprintf('pragma table_info(%s)', $this->quoteTableName($tableName)));
326
        foreach ($rows as $column) {
327 2
            if (strcasecmp($column['name'], $columnName) === 0) {
328
                return true;
329 2
            }
330
        }
331 2
332 2
        return false;
333 2
    }
334 2
335 2
    /**
336 2
     * {@inheritdoc}
337
     */
338 2 View Code Duplication
    protected function getAddColumnInstructions(Table $table, Column $column)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
339 2
    {
340 2
        $alter = sprintf(
341 2
            'ADD COLUMN %s %s',
342 2
            $this->quoteColumnName($column->getName()),
343 2
            $this->getColumnSqlDefinition($column)
344 2
        );
345 2
346 2
        return new AlterInstructions([$alter]);
347
    }
348 2
349 1
    /**
350
     * Returns the original CREATE statement for the give table
351 1
     *
352
     * @param string $tableName The table name to get the create statement for
353
     * @return string
354 1
     */
355
    protected function getDeclaringSql($tableName)
356 1
    {
357 1
        $rows = $this->fetchAll('select * from sqlite_master where `type` = \'table\'');
358 1
359
        $sql = '';
360 1
        foreach ($rows as $table) {
361 1
            if ($table['tbl_name'] === $tableName) {
362
                $sql = $table['sql'];
363
            }
364 1
        }
365 1
366 1
        return $sql;
367 1
    }
368 1
369
    /**
370 1
     * Copies all the data from a tmp table to another table
371
     *
372 1
     * @param string $tableName The table name to copy the data to
373
     * @param string $tmpTableName The tmp table name where the data is stored
374 1
     * @param string[] $writeColumns The list of columns in the target table
375 1
     * @param string[] $selectColumns The list of columns in the tmp table
376
     * @return void
377
     */
378
    protected function copyDataToNewTable($tableName, $tmpTableName, $writeColumns, $selectColumns)
379
    {
380 6
        $sql = sprintf(
381
            'INSERT INTO %s(%s) SELECT %s FROM %s',
382
            $this->quoteTableName($tableName),
383
            implode(', ', $writeColumns),
384 6
            implode(', ', $selectColumns),
385
            $this->quoteTableName($tmpTableName)
386 6
        );
387
        $this->execute($sql);
388 6
    }
389 6
390 6
    /**
391 6
     * Modifies the passed instructions to copy all data from the tmp table into
392 6
     * the provided table and then drops the tmp table.
393 6
     *
394
     * @param AlterInstructions $instructions The instructions to modify
395 6
     * @param string $tableName The table name to copy the data to
396 6
     * @return AlterInstructions
397 6
     */
398 6
    protected function copyAndDropTmpTable($instructions, $tableName)
399 6
    {
400 6
        $instructions->addPostStep(function ($state) use ($tableName) {
401 6
            $this->copyDataToNewTable(
402 6
                $tableName,
403 6
                $state['tmpTableName'],
404
                $state['writeColumns'],
405 6
                $state['selectColumns']
406
            );
407
408
            $this->execute(sprintf('DROP TABLE %s', $this->quoteTableName($state['tmpTableName'])));
409
410
            return $state;
411 6
        });
412
413 6
        return $instructions;
414 6
    }
415 6
416 6
    /**
417
     * Returns the columns and type to use when copying a table to another in the process
418 6
     * of altering a table
419
     *
420 6
     * @param string $tableName The table to modify
421
     * @param string $columnName The column name that is about to change
422 6
     * @param string|false $newColumnName Optionally the new name for the column
423 6
     * @return AlterInstructions
424 6
     */
425 6
    protected function calculateNewTableColumns($tableName, $columnName, $newColumnName)
426 6
    {
427
        $columns = $this->fetchAll(sprintf('pragma table_info(%s)', $this->quoteTableName($tableName)));
428 6
        $selectColumns = [];
429
        $writeColumns = [];
430 6
        $columnType = null;
431 6
        $found = false;
432 6
433
        foreach ($columns as $column) {
434
            $selectName = $column['name'];
435
            $writeName = $selectName;
436
437 2
            if ($selectName == $columnName) {
438
                $writeName = $newColumnName;
439
                $found = true;
440 2
                $columnType = $column['type'];
441
                $selectName = $newColumnName === false ? $newColumnName : $selectName;
442 2
            }
443
444 2
            $selectColumns[] = $selectName;
445 2
            $writeColumns[] = $writeName;
446 2
        }
447 2
448 2
        $selectColumns = array_filter($selectColumns, 'strlen');
449 2
        $writeColumns = array_filter($writeColumns, 'strlen');
450
        $selectColumns = array_map([$this, 'quoteColumnName'], $selectColumns);
451 2
        $writeColumns = array_map([$this, 'quoteColumnName'], $writeColumns);
452 2
453 2
        if (!$found) {
454 2
            throw new \InvalidArgumentException(sprintf(
455 2
                'The specified column doesn\'t exist: ' . $columnName
456 2
            ));
457 2
        }
458 2
459 2
        return compact('writeColumns', 'selectColumns', 'columnType');
460
    }
461 2
462
    /**
463 2
     * Returns the initial instructions to alter a table using the
464
     * rename-alter-copy strategy
465
     *
466
     * @param string $tableName The table to modify
467
     * @return AlterInstructions
468
     */
469 2
    protected function beginAlterByCopyTable($tableName)
470
    {
471 2
        $instructions = new AlterInstructions();
472 2
        $instructions->addPostStep(function ($state) use ($tableName) {
473 2
            $createSQL = $this->getDeclaringSql($tableName);
474
475 2
            $tmpTableName = 'tmp_' . $tableName;
476
            $this->execute(
477 2
                sprintf(
478 2
                    'ALTER TABLE %s RENAME TO %s',
479 2
                    $this->quoteTableName($tableName),
480
                    $this->quoteTableName($tmpTableName)
481 2
                )
482
            );
483 2
484 2
            return compact('createSQL', 'tmpTableName') + $state;
485 2
        });
486 2
487 2
        return $instructions;
488
    }
489 2
490
    /**
491 2
     * {@inheritdoc}
492 2
     */
493 2
    protected function getRenameColumnInstructions($tableName, $columnName, $newColumnName)
494
    {
495
        $instructions = $this->beginAlterByCopyTable($tableName);
496 View Code Duplication
        $instructions->addPostStep(function ($state) use ($columnName, $newColumnName) {
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...
497
            $newState = $this->calculateNewTableColumns($state['tmpTableName'], $columnName, $newColumnName);
498
499
            return $newState + $state;
500
        });
501 9
502
        $instructions->addPostStep(function ($state) use ($columnName, $newColumnName) {
503 9
            $sql = str_replace(
504 9
                $this->quoteColumnName($columnName),
505
                $this->quoteColumnName($newColumnName),
506 9
                $state['createSQL']
507 9
            );
508 9
            $this->execute($sql);
509 9
510 9
            return $state;
511 9
        });
512 9
513 9
        return $this->copyAndDropTmpTable($instructions, $tableName);
514 9
    }
515 9
516
    /**
517
     * {@inheritdoc}
518
     */
519
    protected function getChangeColumnInstructions($tableName, $columnName, Column $newColumn)
520
    {
521 9
        $instructions = $this->beginAlterByCopyTable($tableName);
522
523 9
        $newColumnName = $newColumn->getName();
524 4 View Code Duplication
        $instructions->addPostStep(function ($state) use ($columnName, $newColumnName) {
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...
525 4
            $newState = $this->calculateNewTableColumns($state['tmpTableName'], $columnName, $newColumnName);
526
527 9
            return $newState + $state;
528 9
        });
529
530 9
        $instructions->addPostStep(function ($state) use ($columnName, $newColumn) {
531 9
            $sql = preg_replace(
532 9
                sprintf("/%s(?:\/\*.*?\*\/|\([^)]+\)|'[^']*?'|[^,])+([,)])/", $this->quoteColumnName($columnName)),
533 9
                sprintf('%s %s$1', $this->quoteColumnName($newColumn->getName()), $this->getColumnSqlDefinition($newColumn)),
534
                $state['createSQL'],
535 8
                1
536
            );
537 8
            $this->execute($sql);
538
539
            return $state;
540
        });
541
542
        return $this->copyAndDropTmpTable($instructions, $tableName);
543 1
    }
544
545 1
    /**
546
     * {@inheritdoc}
547 1
     */
548 1
    protected function getDropColumnInstructions($tableName, $columnName)
549 1
    {
550
        $instructions = $this->beginAlterByCopyTable($tableName);
551
552 View Code Duplication
        $instructions->addPostStep(function ($state) use ($columnName) {
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...
553
            $newState = $this->calculateNewTableColumns($state['tmpTableName'], $columnName, false);
554
555
            return $newState + $state;
556
        });
557
558
        $instructions->addPostStep(function ($state) use ($columnName) {
559 8
            $sql = preg_replace(
560
                sprintf("/%s\s%s.*(,\s(?!')|\)$)/U", preg_quote($this->quoteColumnName($columnName)), preg_quote($state['columnType'])),
561 8
                "",
562 8
                $state['createSQL']
563 8
            );
564 8
565 8
            if (substr($sql, -2) === ', ') {
566 8
                $sql = substr($sql, 0, -2) . ')';
567 8
            }
568 8
569 8
            $this->execute($sql);
570 8
571
            return $state;
572 8
        });
573 8
574 8
        return $this->copyAndDropTmpTable($instructions, $tableName);
575
    }
576
577
    /**
578
     * Get an array of indexes from a particular table.
579 1
     *
580
     * @param string $tableName Table Name
581 1
     * @return array
582 1
     */
583 1
    protected function getIndexes($tableName)
584
    {
585 1
        $indexes = [];
586 1
        $rows = $this->fetchAll(sprintf('pragma index_list(%s)', $tableName));
587
588 1
        foreach ($rows as $row) {
589 1
            $indexData = $this->fetchAll(sprintf('pragma index_info(%s)', $row['name']));
590 1
            if (!isset($indexes[$tableName])) {
591 1
                $indexes[$tableName] = ['index' => $row['name'], 'columns' => []];
592 1
            }
593 1
            foreach ($indexData as $indexItem) {
594 1
                $indexes[$tableName]['columns'][] = strtolower($indexItem['name']);
595 1
            }
596 1
        }
597 1
598
        return $indexes;
599
    }
600
601
    /**
602
     * {@inheritdoc}
603
     */
604 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...
605 1
    {
606
        if (is_string($columns)) {
607 1
            $columns = [$columns]; // str to array
608
        }
609 1
610 1
        $columns = array_map('strtolower', $columns);
611 1
        $indexes = $this->getIndexes($tableName);
612 1
613 1
        foreach ($indexes as $index) {
614 1
            $a = array_diff($columns, $index['columns']);
615 1
            if (empty($a)) {
616 1
                return true;
617 1
            }
618
        }
619
620
        return false;
621
    }
622
623
    /**
624
     * {@inheritdoc}
625 5
     */
626 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...
627 5
    {
628
        $indexes = $this->getIndexes($tableName);
629
630 5
        foreach ($indexes as $index) {
631
            if ($indexName === $index['index']) {
632 5
                return true;
633 5
            }
634 5
        }
635
636 1
        return false;
637
    }
638
639
    /**
640
     * {@inheritdoc}
641
     */
642
    protected function getAddIndexInstructions(Table $table, Index $index)
643
    {
644
        $indexColumnArray = [];
645 5
        foreach ($index->getColumns() as $column) {
646
            $indexColumnArray[] = sprintf('`%s` ASC', $column);
647 5
        }
648 5
        $indexColumns = implode(',', $indexColumnArray);
649
        $sql = sprintf(
650
            'CREATE %s ON %s (%s)',
651
            $this->getIndexSqlDefinition($table, $index),
652
            $this->quoteTableName($table->getName()),
653
            $indexColumns
654
        );
655
656
        return new AlterInstructions([], [$sql]);
657
    }
658
659
    /**
660
     * {@inheritdoc}
661 5
     */
662
    protected function getDropIndexByColumnsInstructions($tableName, $columns)
663 5
    {
664 5
        if (is_string($columns)) {
665 5
            $columns = [$columns]; // str to array
666 5
        }
667 5
668 5
        $indexes = $this->getIndexes($tableName);
669 5
        $columns = array_map('strtolower', $columns);
670 5
        $instructions = new AlterInstructions();
671 5
672 5
        foreach ($indexes as $index) {
673 5
            $a = array_diff($columns, $index['columns']);
674
            if (empty($a)) {
675
                $instructions->addPostStep(sprintf(
676
                    'DROP INDEX %s',
677
                    $this->quoteColumnName($index['index'])
678
                ));
679 4
            }
680
        }
681
682 4
        return $instructions;
683
    }
684 4
685 4
    /**
686
     * {@inheritdoc}
687 4
     */
688 4
    protected function getDropIndexByNameInstructions($tableName, $indexName)
689 4
    {
690 4
        $indexes = $this->getIndexes($tableName);
691 4
        $instructions = new AlterInstructions();
692 4
693
        foreach ($indexes as $index) {
694 4
            if ($indexName === $index['index']) {
695 4
                $instructions->addPostStep(sprintf(
696 4
                    'DROP INDEX %s',
697 4
                    $this->quoteColumnName($indexName)
698 4
                ));
699
            }
700 4
        }
701
702 4
        return $instructions;
703 4
    }
704
705 4
    /**
706 4
     * {@inheritdoc}
707 4
     */
708 4
    public function hasForeignKey($tableName, $columns, $constraint = null)
709 4
    {
710 4
        if (is_string($columns)) {
711 4
            $columns = [$columns]; // str to array
712
        }
713 4
        $foreignKeys = $this->getForeignKeys($tableName);
714 4
715 4
        return !array_diff($columns, $foreignKeys);
716
    }
717
718
    /**
719
     * Get an array of foreign keys from a particular table.
720 1
     *
721
     * @param string $tableName Table Name
722
     * @return array
723 1
     */
724
    protected function getForeignKeys($tableName)
725
    {
726
        $foreignKeys = [];
727 1
        $rows = $this->fetchAll(
728
            "SELECT sql, tbl_name
729 1
              FROM (
730
                    SELECT sql sql, type type, tbl_name tbl_name, name name
731 1
                      FROM sqlite_master
732 1
                     UNION ALL
733 1
                    SELECT sql, type, tbl_name, name
734 1
                      FROM sqlite_temp_master
735 1
                   )
736 1
             WHERE type != 'meta'
737
               AND sql NOTNULL
738 1
               AND name NOT LIKE 'sqlite_%'
739 1
             ORDER BY substr(type, 2, 1), name"
740 1
        );
741 1
742 1
        foreach ($rows as $row) {
743 1
            if ($row['tbl_name'] === $tableName) {
744 1
                if (strpos($row['sql'], 'REFERENCES') !== false) {
745
                    preg_match_all("/\(`([^`]*)`\) REFERENCES/", $row['sql'], $matches);
746 1
                    foreach ($matches[1] as $match) {
747
                        $foreignKeys[] = $match;
748 1
                    }
749
                }
750
            }
751
        }
752
753
        return $foreignKeys;
754 1
    }
755
756 1
    /**
757 1
     * {@inheritdoc}
758 1
     */
759 1
    protected function getAddForeignKeyInstructions(Table $table, ForeignKey $foreignKey)
760 1
    {
761 1
        $instructions = $this->beginAlterByCopyTable($table->getName());
762 1
763
        $tableName = $table->getName();
764 1
        $instructions->addPostStep(function ($state) use ($foreignKey) {
765
            $this->execute('pragma foreign_keys = ON');
766 1
            $sql = substr($state['createSQL'], 0, -1) . ',' . $this->getForeignKeySqlDefinition($foreignKey) . ')';
767 1
            $this->execute($sql);
768 1
769 1
            return $state;
770 1
        });
771
772 1
        $instructions->addPostStep(function ($state) {
773
            $columns = $this->fetchAll(sprintf('pragma table_info(%s)', $this->quoteTableName($state['tmpTableName'])));
774 1
            $names = array_map([$this, 'quoteColumnName'], array_column($columns, 'name'));
775 1
            $selectColumns = $writeColumns = $names;
776 1
777
            return compact('selectColumns', 'writeColumns') + $state;
778
        });
779
780
        return $this->copyAndDropTmpTable($instructions, $tableName);
781
    }
782
783
    /**
784
     * {@inheritdoc}
785
     */
786
    protected function getDropForeignKeyInstructions($tableName, $constraint)
787
    {
788
        throw new \BadMethodCallException('SQLite does not have named foreign keys');
789
    }
790
791
    /**
792
     * {@inheritdoc}
793
     */
794
    protected function getDropForeignKeyByColumnsInstructions($tableName, $columns)
795
    {
796
        $instructions = $this->beginAlterByCopyTable($tableName);
797
798
        $instructions->addPostStep(function ($state) use ($columns) {
799
            $newState = $this->calculateNewTableColumns($state['tmpTableName'], $columns[0], $columns[0]);
800
801
            $selectColumns = $newState['selectColumns'];
802
            $columns = array_map([$this, 'quoteColumnName'], $columns);
0 ignored issues
show
Bug introduced by
Consider using a different name than the imported variable $columns, or did you forget to import by reference?

It seems like you are assigning to a variable which was imported through a use statement which was not imported by reference.

For clarity, we suggest to use a different name or import by reference depending on whether you would like to have the change visibile in outer-scope.

Change not visible in outer-scope

$x = 1;
$callable = function() use ($x) {
    $x = 2; // Not visible in outer scope. If you would like this, how
            // about using a different variable name than $x?
};

$callable();
var_dump($x); // integer(1)

Change visible in outer-scope

$x = 1;
$callable = function() use (&$x) {
    $x = 2;
};

$callable();
var_dump($x); // integer(2)
Loading history...
803
            $diff = array_diff($columns, $selectColumns);
804
805
            if (!empty($diff)) {
806
                throw new \InvalidArgumentException(sprintf(
807
                    'The specified columns doen\'t exist: ' . implode(', ', $diff)
808
                ));
809
            }
810 43
811
            return $newState + $state;
812
        });
813 43
814 42
        $instructions->addPostStep(function ($state) use ($columns) {
815
            $sql = '';
816 43
817
            foreach ($columns as $columnName) {
818
                $search = sprintf(
819 43
                    "/,[^,]*\(%s(?:,`?(.*)`?)?\) REFERENCES[^,]*\([^\)]*\)[^,)]*/",
820 1
                    $this->quoteColumnName($columnName)
821
                );
822 43
                $sql = preg_replace($search, '', $state['createSQL'], 1);
823 38
            }
824
825 43
            if ($sql) {
826 42
                $this->execute($sql);
827
            }
828 43
829 2
            return $state;
830
        });
831 43
832 1
        return $this->copyAndDropTmpTable($instructions, $tableName);
833
    }
834 43
835 1
    /**
836
     * {@inheritdoc}
837 43
     */
838 42
    public function getSqlType($type, $limit = null)
839
    {
840 43
        switch ($type) {
841 1
            case static::PHINX_TYPE_TEXT:
842
            case static::PHINX_TYPE_INTEGER:
843 43
            case static::PHINX_TYPE_FLOAT:
844 1
            case static::PHINX_TYPE_DECIMAL:
845
            case static::PHINX_TYPE_DATETIME:
846 43
            case static::PHINX_TYPE_TIME:
847 43
            case static::PHINX_TYPE_DATE:
848 1
            case static::PHINX_TYPE_BLOB:
849
            case static::PHINX_TYPE_BOOLEAN:
850 43
            case static::PHINX_TYPE_ENUM:
851 42
                return ['name' => $type];
852
            case static::PHINX_TYPE_STRING:
853 5
                return ['name' => 'varchar', 'limit' => 255];
854
            case static::PHINX_TYPE_CHAR:
855 5
                return ['name' => 'char', 'limit' => 255];
856 4
            case static::PHINX_TYPE_BIG_INTEGER:
857
                return ['name' => 'bigint'];
858
            case static::PHINX_TYPE_TIMESTAMP:
859
                return ['name' => 'datetime'];
860 1
            case static::PHINX_TYPE_BINARY:
861 1
                return ['name' => 'blob'];
862
            case static::PHINX_TYPE_UUID:
863
                return ['name' => 'char', 'limit' => 36];
864 1
            case static::PHINX_TYPE_JSON:
865
            case static::PHINX_TYPE_JSONB:
866
                return ['name' => 'text'];
867 1
            // Geospatial database types
868
            // No specific data types exist in SQLite, instead all geospatial
869 1
            // functionality is handled in the client. See also: SpatiaLite.
870 1
            case static::PHINX_TYPE_GEOMETRY:
871 1
            case static::PHINX_TYPE_POLYGON:
872
                return ['name' => 'text'];
873
            case static::PHINX_TYPE_LINESTRING:
874
                return ['name' => 'varchar', 'limit' => 255];
875
            case static::PHINX_TYPE_POINT:
876
                return ['name' => 'float'];
877
            default:
878
                throw new \RuntimeException('The type: "' . $type . '" is not supported.');
879
        }
880 3
    }
881
882 3
    /**
883 1
     * Returns Phinx type by SQL type
884
     *
885 2
     * @param string $sqlTypeDef SQL type
886 2
     * @returns string Phinx type
887 2
     */
888 2
    public function getPhinxType($sqlTypeDef)
889 1
    {
890 1
        if (!preg_match('/^([\w]+)(\(([\d]+)*(,([\d]+))*\))*$/', $sqlTypeDef, $matches)) {
891 2
            throw new \RuntimeException('Column type ' . $sqlTypeDef . ' is not supported');
892
        } else {
893
            $limit = null;
894 2
            $precision = null;
895 2
            $type = $matches[1];
896 1
            if (count($matches) > 2) {
897 1
                $limit = $matches[3] ?: null;
898
            }
899
            if (count($matches) > 4) {
900 1
                $precision = $matches[5];
901 2
            }
902
            switch ($matches[1]) {
903
                case 'varchar':
904
                    $type = static::PHINX_TYPE_STRING;
905
                    if ($limit === 255) {
906
                        $limit = null;
907
                    }
908
                    break;
909 View Code Duplication
                case 'char':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
910 2
                    $type = static::PHINX_TYPE_CHAR;
911
                    if ($limit === 255) {
912
                        $limit = null;
913
                    }
914
                    if ($limit === 36) {
915
                        $type = static::PHINX_TYPE_UUID;
916 2
                    }
917 1
                    break;
918
                case 'int':
919
                    $type = static::PHINX_TYPE_INTEGER;
920 1
                    if ($limit === 11) {
921 1
                        $limit = null;
922 2
                    }
923 1
                    break;
924 1
                case 'bigint':
925 2
                    if ($limit === 11) {
926 2
                        $limit = null;
927
                    }
928
                    $type = static::PHINX_TYPE_BIG_INTEGER;
929
                    break;
930
                case 'blob':
931
                    $type = static::PHINX_TYPE_BINARY;
932
                    break;
933 2
            }
934 View Code Duplication
            if ($type === 'tinyint') {
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...
935
                if ($matches[3] === 1) {
936 1
                    $type = static::PHINX_TYPE_BOOLEAN;
937 1
                    $limit = null;
938
                }
939 1
            }
940
941
            $this->getSqlType($type);
942
943
            return [
944
                'name' => $type,
945
                'limit' => $limit,
946 48
                'precision' => $precision
947
            ];
948 48
        }
949 48
    }
950
951
    /**
952
     * {@inheritdoc}
953
     */
954 2
    public function createDatabase($name, $options = [])
955
    {
956 2
        touch($name . $this->suffix);
957
    }
958
959
    /**
960
     * {@inheritdoc}
961
     */
962 48
    public function hasDatabase($name)
963
    {
964 48
        return is_file($name . $this->suffix);
965 47
    }
966 47
967 48
    /**
968
     * {@inheritdoc}
969
     */
970
    public function dropDatabase($name)
971
    {
972
        if (file_exists($name . '.sqlite3')) {
973
            unlink($name . '.sqlite3');
974
        }
975 42
    }
976
977 42
    /**
978 8
     * Gets the SQLite Column Definition for a Column object.
979 42
     *
980 42
     * @param \Phinx\Db\Table\Column $column Column
981 42
     * @return string
982 42
     */
983
    protected function getColumnSqlDefinition(Column $column)
984
    {
985
        $isLiteralType = $column->getType() instanceof Literal;
986
        if ($isLiteralType) {
987
            $def = (string)$column->getType();
988
        } else {
989
            $sqlType = $this->getSqlType($column->getType());
990
            $def = strtoupper($sqlType['name']);
991 42
992
            $limitable = in_array(strtoupper($sqlType['name']), $this->definitionsWithLimits);
993 42
            if (($column->getLimit() || isset($sqlType['limit'])) && $limitable) {
994 42
                $def .= '(' . ($column->getLimit() ?: $sqlType['limit']) . ')';
995 42
            }
996 42
        }
997 View Code Duplication
        if ($column->getPrecision() && $column->getScale()) {
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...
998
            $def .= '(' . $column->getPrecision() . ',' . $column->getScale() . ')';
999 42
        }
1000 42 View Code Duplication
        if (($values = $column->getValues()) && is_array($values)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1001 42
            $def .= " CHECK({$column->getName()} IN ('" . implode("', '", $values) . "'))";
1002 42
        }
1003 42
1004 4
        $default = $column->getDefault();
1005 4
1006
        $def .= (!$column->isIdentity() && ($column->isNull() || is_null($default))) ? ' NULL' : ' NOT NULL';
1007 42
        $def .= $this->getDefaultValueDefinition($default, $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\PdoAdap...efaultValueDefinition() does only seem to accept string|null, 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...
1008
        $def .= $column->isIdentity() ? ' PRIMARY KEY AUTOINCREMENT' : '';
1009 42
1010 42
        if ($column->getUpdate()) {
1011 42
            $def .= ' ON UPDATE ' . $column->getUpdate();
1012
        }
1013 42
1014
        $def .= $this->getCommentDefinition($column);
1015
1016
        return $def;
1017 42
    }
1018
1019 42
    /**
1020
     * Gets the comment Definition for a Column object.
1021
     *
1022
     * @param \Phinx\Db\Table\Column $column Column
1023
     * @return string
1024
     */
1025
    protected function getCommentDefinition(Column $column)
1026
    {
1027
        if ($column->getComment()) {
1028 42
            return ' /* ' . $column->getComment() . ' */ ';
1029
        }
1030 42
1031 2
        return '';
1032
    }
1033 42
1034
    /**
1035
     * Gets the SQLite Index Definition for an Index object.
1036
     *
1037
     * @param \Phinx\Db\Table\Table $table Table
1038
     * @param \Phinx\Db\Table\Index $index Index
1039
     * @return string
1040
     */
1041
    protected function getIndexSqlDefinition(Table $table, Index $index)
1042 8
    {
1043
        if ($index->getType() === Index::UNIQUE) {
1044 8
            $def = 'UNIQUE INDEX';
1045 2
        } else {
1046 2
            $def = 'INDEX';
1047 6
        }
1048
        if (is_string($index->getName())) {
1049 8
            $indexName = $index->getName();
1050 3
        } else {
1051 3
            $indexName = $table->getName() . '_';
1052 6
            foreach ($index->getColumns() as $column) {
1053 6
                $indexName .= $column . '_';
1054 6
            }
1055 6
            $indexName .= 'index';
1056 6
        }
1057
        $def .= ' `' . $indexName . '`';
1058 8
1059 8
        return $def;
1060
    }
1061
1062
    /**
1063
     * {@inheritdoc}
1064
     */
1065 47
    public function getColumnTypes()
1066
    {
1067 47
        return array_merge(parent::getColumnTypes(), ['enum', 'json', 'jsonb']);
1068
    }
1069
1070
    /**
1071
     * Gets the SQLite Foreign Key Definition for an ForeignKey object.
1072
     *
1073
     * @param \Phinx\Db\Table\ForeignKey $foreignKey
1074
     * @return string
1075
     */
1076 5 View Code Duplication
    protected function getForeignKeySqlDefinition(ForeignKey $foreignKey)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1077
    {
1078 5
        $def = '';
1079 5
        if ($foreignKey->getConstraint()) {
1080
            $def .= ' CONSTRAINT ' . $this->quoteColumnName($foreignKey->getConstraint());
0 ignored issues
show
Bug introduced by
It seems like $foreignKey->getConstraint() targeting Phinx\Db\Table\ForeignKey::getConstraint() can also be of type boolean; however, Phinx\Db\Adapter\SQLiteAdapter::quoteColumnName() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
1081
        } else {
1082 5
            $columnNames = [];
1083 5
            foreach ($foreignKey->getColumns() as $column) {
1084 5
                $columnNames[] = $this->quoteColumnName($column);
1085 5
            }
1086 5
            $def .= ' FOREIGN KEY (' . implode(',', $columnNames) . ')';
1087 5
            $refColumnNames = [];
1088 5
            foreach ($foreignKey->getReferencedColumns() as $column) {
1089 5
                $refColumnNames[] = $this->quoteColumnName($column);
1090 5
            }
1091 5
            $def .= ' REFERENCES ' . $this->quoteTableName($foreignKey->getReferencedTable()->getName()) . ' (' . implode(',', $refColumnNames) . ')';
1092 5
            if ($foreignKey->getOnDelete()) {
1093 1
                $def .= ' ON DELETE ' . $foreignKey->getOnDelete();
1094 1
            }
1095 5
            if ($foreignKey->getOnUpdate()) {
1096 1
                $def .= ' ON UPDATE ' . $foreignKey->getOnUpdate();
1097 1
            }
1098
        }
1099 5
1100
        return $def;
1101
    }
1102
1103
    /**
1104
     * {@inheritDoc}
1105
     *
1106
     */
1107
    public function getDecoratedConnection()
1108
    {
1109
        $options = $this->getOptions();
1110
        $options['quoteIdentifiers'] = true;
1111
        $database = ':memory:';
0 ignored issues
show
Unused Code introduced by
$database is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1112
1113
        if (!empty($options['name'])) {
1114
            $options['database'] = $options['name'];
1115
1116
            if (file_exists($options['name'] . $this->suffix)) {
1117
                $options['database'] = $options['name'] . $this->suffix;
1118
            }
1119
        }
1120
1121
        $driver = new SqliteDriver($options);
1122
        if (method_exists($driver, 'setConnection')) {
1123
            $driver->setConnection($this->connection);
0 ignored issues
show
Bug introduced by
It seems like $this->connection can be null; however, setConnection() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1124
        } else {
1125
            $driver->connection($this->connection);
0 ignored issues
show
Deprecated Code introduced by
The method Cake\Database\Driver::connection() has been deprecated with message: 3.6.0 Use getConnection()/setConnection() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
1126
        }
1127
1128
        return new Connection(['driver' => $driver] + $options);
1129
    }
1130
}
1131