Passed
Push — 2.7 ( bd5e19...0d26c7 )
by Sergei
14:54
created

SqliteSchemaManager   F

Complexity

Total Complexity 74

Size/Duplication

Total Lines 426
Duplicated Lines 0 %

Test Coverage

Coverage 84.83%

Importance

Changes 0
Metric Value
wmc 74
dl 0
loc 426
ccs 179
cts 211
cp 0.8483
rs 2.3809
c 0
b 0
f 0

17 Methods

Rating   Name   Duplication   Size   Complexity  
A dropForeignKey() 0 6 1
A dropDatabase() 0 4 2
C _getPortableTableColumnList() 0 52 15
A dropAndCreateForeignKey() 0 6 1
C listTableForeignKeys() 0 39 11
A createForeignKey() 0 6 1
F _getPortableTableColumnDefinition() 0 68 14
A renameTable() 0 6 1
A _getPortableTableIndexDefinition() 0 5 1
A parseColumnCollationFromSQL() 0 10 2
A createDatabase() 0 11 1
C _getPortableTableForeignKeysList() 0 44 8
A parseColumnCommentFromSQL() 0 12 3
A _getPortableViewDefinition() 0 3 1
A getTableDiffForAlterForeignKey() 0 15 3
A _getPortableTableDefinition() 0 3 1
C _getPortableTableIndexesList() 0 47 8

How to fix   Complexity   

Complex Class

Complex classes like SqliteSchemaManager 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.

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

1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\DBAL\Schema;
21
22
use Doctrine\DBAL\DBALException;
23
use Doctrine\DBAL\FetchMode;
24
use Doctrine\DBAL\Types\StringType;
25
use Doctrine\DBAL\Types\TextType;
26
use Doctrine\DBAL\Types\Type;
27
use const CASE_LOWER;
28
use function array_change_key_case;
29
use function array_map;
30
use function array_reverse;
31
use function array_values;
32
use function explode;
33
use function file_exists;
34
use function preg_match;
35
use function preg_match_all;
36
use function preg_quote;
37
use function preg_replace;
38
use function rtrim;
39
use function sprintf;
40
use function str_replace;
41
use function strpos;
42
use function strtolower;
43
use function trim;
44
use function unlink;
45
use function usort;
46
47
/**
48
 * Sqlite SchemaManager.
49
 *
50
 * @author Konsta Vesterinen <[email protected]>
51
 * @author Lukas Smith <[email protected]> (PEAR MDB2 library)
52
 * @author Jonathan H. Wage <[email protected]>
53
 * @author Martin Hasoň <[email protected]>
54
 * @since  2.0
55
 */
56
class SqliteSchemaManager extends AbstractSchemaManager
57
{
58
    /**
59
     * {@inheritdoc}
60
     */
61 2
    public function dropDatabase($database)
62
    {
63 2
        if (file_exists($database)) {
64 2
            unlink($database);
65
        }
66 2
    }
67
68
    /**
69
     * {@inheritdoc}
70
     */
71 2
    public function createDatabase($database)
72
    {
73 2
        $params = $this->_conn->getParams();
74 2
        $driver = $params['driver'];
75
        $options = [
76 2
            'driver' => $driver,
77 2
            'path' => $database
78
        ];
79 2
        $conn = \Doctrine\DBAL\DriverManager::getConnection($options);
80 2
        $conn->connect();
81 2
        $conn->close();
82 2
    }
83
84
    /**
85
     * {@inheritdoc}
86
     */
87 1
    public function renameTable($name, $newName)
88
    {
89 1
        $tableDiff = new TableDiff($name);
90 1
        $tableDiff->fromTable = $this->listTableDetails($name);
91 1
        $tableDiff->newName = $newName;
92 1
        $this->alterTable($tableDiff);
93 1
    }
94
95
    /**
96
     * {@inheritdoc}
97
     */
98
    public function createForeignKey(ForeignKeyConstraint $foreignKey, $table)
99
    {
100
        $tableDiff = $this->getTableDiffForAlterForeignKey($foreignKey, $table);
101
        $tableDiff->addedForeignKeys[] = $foreignKey;
102
103
        $this->alterTable($tableDiff);
104
    }
105
106
    /**
107
     * {@inheritdoc}
108
     */
109
    public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table)
110
    {
111
        $tableDiff = $this->getTableDiffForAlterForeignKey($foreignKey, $table);
112
        $tableDiff->changedForeignKeys[] = $foreignKey;
113
114
        $this->alterTable($tableDiff);
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     */
120
    public function dropForeignKey($foreignKey, $table)
121
    {
122
        $tableDiff = $this->getTableDiffForAlterForeignKey($foreignKey, $table);
123
        $tableDiff->removedForeignKeys[] = $foreignKey;
124
125
        $this->alterTable($tableDiff);
126
    }
127
128
    /**
129
     * {@inheritdoc}
130
     */
131 1
    public function listTableForeignKeys($table, $database = null)
132
    {
133 1
        if (null === $database) {
134 1
            $database = $this->_conn->getDatabase();
135
        }
136 1
        $sql = $this->_platform->getListTableForeignKeysSQL($table, $database);
0 ignored issues
show
Unused Code introduced by
The call to Doctrine\DBAL\Platforms\...stTableForeignKeysSQL() has too many arguments starting with $database. ( Ignorable by Annotation )

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

136
        /** @scrutinizer ignore-call */ 
137
        $sql = $this->_platform->getListTableForeignKeysSQL($table, $database);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
137 1
        $tableForeignKeys = $this->_conn->fetchAll($sql);
138
139 1
        if ( ! empty($tableForeignKeys)) {
140 1
            $createSql = $this->_conn->fetchAll("SELECT sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type = 'table' AND name = '$table'");
141 1
            $createSql = $createSql[0]['sql'] ?? '';
142
143 1
            if (preg_match_all('#
144
                    (?:CONSTRAINT\s+([^\s]+)\s+)?
145
                    (?:FOREIGN\s+KEY[^\)]+\)\s*)?
146
                    REFERENCES\s+[^\s]+\s+(?:\([^\)]+\))?
147
                    (?:
148
                        [^,]*?
149
                        (NOT\s+DEFERRABLE|DEFERRABLE)
150
                        (?:\s+INITIALLY\s+(DEFERRED|IMMEDIATE))?
151
                    )?#isx',
152 1
                    $createSql, $match)) {
153
154 1
                $names = array_reverse($match[1]);
155 1
                $deferrable = array_reverse($match[2]);
156 1
                $deferred = array_reverse($match[3]);
157
            } else {
158
                $names = $deferrable = $deferred = [];
159
            }
160
161 1
            foreach ($tableForeignKeys as $key => $value) {
162 1
                $id = $value['id'];
163 1
                $tableForeignKeys[$key]['constraint_name'] = isset($names[$id]) && '' != $names[$id] ? $names[$id] : $id;
164 1
                $tableForeignKeys[$key]['deferrable'] = isset($deferrable[$id]) && 'deferrable' == strtolower($deferrable[$id]) ? true : false;
165 1
                $tableForeignKeys[$key]['deferred'] = isset($deferred[$id]) && 'deferred' == strtolower($deferred[$id]) ? true : false;
166
            }
167
        }
168
169 1
        return $this->_getPortableTableForeignKeysList($tableForeignKeys);
170
    }
171
172
    /**
173
     * {@inheritdoc}
174
     */
175 63
    protected function _getPortableTableDefinition($table)
176
    {
177 63
        return $table['name'];
178
    }
179
180
    /**
181
     * {@inheritdoc}
182
     *
183
     * @license New BSD License
184
     * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html
185
     */
186 33
    protected function _getPortableTableIndexesList($tableIndexes, $tableName=null)
187
    {
188 33
        $indexBuffer = [];
189
190
        // fetch primary
191 33
        $stmt = $this->_conn->executeQuery("PRAGMA TABLE_INFO ('$tableName')");
192 33
        $indexArray = $stmt->fetchAll(FetchMode::ASSOCIATIVE);
193
194
        usort($indexArray, function($a, $b) {
195 22
            if ($a['pk'] == $b['pk']) {
196 18
                return $a['cid'] - $b['cid'];
197
            }
198
199 12
            return $a['pk'] - $b['pk'];
200 33
        });
201 33
        foreach ($indexArray as $indexColumnRow) {
202 33
            if ($indexColumnRow['pk'] != "0") {
203 21
                $indexBuffer[] = [
204 21
                    'key_name' => 'primary',
205
                    'primary' => true,
206
                    'non_unique' => false,
207 33
                    'column_name' => $indexColumnRow['name']
208
                ];
209
            }
210
        }
211
212
        // fetch regular indexes
213 33
        foreach ($tableIndexes as $tableIndex) {
214
            // Ignore indexes with reserved names, e.g. autoindexes
215 8
            if (strpos($tableIndex['name'], 'sqlite_') !== 0) {
216 6
                $keyName = $tableIndex['name'];
217 6
                $idx = [];
218 6
                $idx['key_name'] = $keyName;
219 6
                $idx['primary'] = false;
220 6
                $idx['non_unique'] = $tableIndex['unique']?false:true;
221
222 6
                $stmt = $this->_conn->executeQuery("PRAGMA INDEX_INFO ('{$keyName}')");
223 6
                $indexArray = $stmt->fetchAll(FetchMode::ASSOCIATIVE);
224
225 6
                foreach ($indexArray as $indexColumnRow) {
226 6
                    $idx['column_name'] = $indexColumnRow['name'];
227 8
                    $indexBuffer[] = $idx;
228
                }
229
            }
230
        }
231
232 33
        return parent::_getPortableTableIndexesList($indexBuffer, $tableName);
233
    }
234
235
    /**
236
     * {@inheritdoc}
237
     */
238
    protected function _getPortableTableIndexDefinition($tableIndex)
239
    {
240
        return [
241
            'name' => $tableIndex['name'],
242
            'unique' => (bool) $tableIndex['unique']
243
        ];
244
    }
245
246
    /**
247
     * {@inheritdoc}
248
     */
249 40
    protected function _getPortableTableColumnList($table, $database, $tableColumns)
250
    {
251 40
        $list = parent::_getPortableTableColumnList($table, $database, $tableColumns);
252
253
        // find column with autoincrement
254 40
        $autoincrementColumn = null;
255 40
        $autoincrementCount = 0;
256
257 40
        foreach ($tableColumns as $tableColumn) {
258 40
            if ('0' != $tableColumn['pk']) {
259 24
                $autoincrementCount++;
260 24
                if (null === $autoincrementColumn && 'integer' == strtolower($tableColumn['type'])) {
261 40
                    $autoincrementColumn = $tableColumn['name'];
262
                }
263
            }
264
        }
265
266 40
        if (1 == $autoincrementCount && null !== $autoincrementColumn) {
0 ignored issues
show
introduced by
The condition null !== $autoincrementColumn is always false.
Loading history...
267 23
            foreach ($list as $column) {
268 23
                if ($autoincrementColumn == $column->getName()) {
269 23
                    $column->setAutoincrement(true);
270
                }
271
            }
272
        }
273
274
        // inspect column collation and comments
275 40
        $createSql = $this->_conn->fetchAll("SELECT sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type = 'table' AND name = '$table'");
276 40
        $createSql = $createSql[0]['sql'] ?? '';
277
278 40
        foreach ($list as $columnName => $column) {
279 40
            $type = $column->getType();
280
281 40
            if ($type instanceof StringType || $type instanceof TextType) {
282 16
                $column->setPlatformOption('collation', $this->parseColumnCollationFromSQL($columnName, $createSql) ?: 'BINARY');
283
            }
284
285 40
            $comment = $this->parseColumnCommentFromSQL($columnName, $createSql);
286
287 40
            if ($comment !== null) {
288 16
                $type = $this->extractDoctrineTypeFromComment($comment, null);
289
290 16
                if (null !== $type) {
291 4
                    $column->setType(Type::getType($type));
292
293 4
                    $comment = $this->removeDoctrineTypeFromComment($comment, $type);
294
                }
295
296 40
                $column->setComment($comment);
297
            }
298
        }
299
300 40
        return $list;
301
    }
302
303
    /**
304
     * {@inheritdoc}
305
     */
306 40
    protected function _getPortableTableColumnDefinition($tableColumn)
307
    {
308 40
        $parts = explode('(', $tableColumn['type']);
309 40
        $tableColumn['type'] = trim($parts[0]);
310 40
        if (isset($parts[1])) {
311 12
            $length = trim($parts[1], ')');
312 12
            $tableColumn['length'] = $length;
313
        }
314
315 40
        $dbType   = strtolower($tableColumn['type']);
316 40
        $length   = $tableColumn['length'] ?? null;
317 40
        $unsigned = false;
318
319 40
        if (strpos($dbType, ' unsigned') !== false) {
320 1
            $dbType = str_replace(' unsigned', '', $dbType);
321 1
            $unsigned = true;
322
        }
323
324 40
        $fixed = false;
325 40
        $type = $this->_platform->getDoctrineTypeMapping($dbType);
326 40
        $default = $tableColumn['dflt_value'];
327 40
        if ($default == 'NULL') {
328 4
            $default = null;
329
        }
330 40
        if ($default !== null) {
331
            // SQLite returns strings wrapped in single quotes, so we need to strip them
332 6
            $default = preg_replace("/^'(.*)'$/", '\1', $default);
333
        }
334 40
        $notnull = (bool) $tableColumn['notnull'];
335
336 40
        if ( ! isset($tableColumn['name'])) {
337
            $tableColumn['name'] = '';
338
        }
339
340 40
        $precision = null;
341 40
        $scale = null;
342
343
        switch ($dbType) {
344 40
            case 'char':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
345 4
                $fixed = true;
346 4
                break;
347 39
            case 'float':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
348 39
            case 'double':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
349 39
            case 'real':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
350 39
            case 'decimal':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
351 39
            case 'numeric':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
352 4
                if (isset($tableColumn['length'])) {
353 4
                    if (strpos($tableColumn['length'], ',') === false) {
354
                        $tableColumn['length'] .= ",0";
355
                    }
356 4
                    list($precision, $scale) = array_map('trim', explode(',', $tableColumn['length']));
357
                }
358 4
                $length = null;
359 4
                break;
360
        }
361
362
        $options = [
363 40
            'length'   => $length,
364 40
            'unsigned' => (bool) $unsigned,
365 40
            'fixed'    => $fixed,
366 40
            'notnull'  => $notnull,
367 40
            'default'  => $default,
368 40
            'precision' => $precision,
369 40
            'scale'     => $scale,
370
            'autoincrement' => false,
371
        ];
372
373 40
        return new Column($tableColumn['name'], \Doctrine\DBAL\Types\Type::getType($type), $options);
374
    }
375
376
    /**
377
     * {@inheritdoc}
378
     */
379 1
    protected function _getPortableViewDefinition($view)
380
    {
381 1
        return new View($view['name'], $view['sql']);
382
    }
383
384
    /**
385
     * {@inheritdoc}
386
     */
387 1
    protected function _getPortableTableForeignKeysList($tableForeignKeys)
388
    {
389 1
        $list = [];
390 1
        foreach ($tableForeignKeys as $value) {
391 1
            $value = array_change_key_case($value, CASE_LOWER);
392 1
            $name = $value['constraint_name'];
393 1
            if ( ! isset($list[$name])) {
394 1
                if ( ! isset($value['on_delete']) || $value['on_delete'] == "RESTRICT") {
395
                    $value['on_delete'] = null;
396
                }
397 1
                if ( ! isset($value['on_update']) || $value['on_update'] == "RESTRICT") {
398
                    $value['on_update'] = null;
399
                }
400
401 1
                $list[$name] = [
402 1
                    'name' => $name,
403
                    'local' => [],
404
                    'foreign' => [],
405 1
                    'foreignTable' => $value['table'],
406 1
                    'onDelete' => $value['on_delete'],
407 1
                    'onUpdate' => $value['on_update'],
408 1
                    'deferrable' => $value['deferrable'],
409 1
                    'deferred'=> $value['deferred'],
410
                ];
411
            }
412 1
            $list[$name]['local'][] = $value['from'];
413 1
            $list[$name]['foreign'][] = $value['to'];
414
        }
415
416 1
        $result = [];
417 1
        foreach ($list as $constraint) {
418 1
            $result[] = new ForeignKeyConstraint(
419 1
                array_values($constraint['local']), $constraint['foreignTable'],
420 1
                array_values($constraint['foreign']), $constraint['name'],
421
                [
422 1
                    'onDelete' => $constraint['onDelete'],
423 1
                    'onUpdate' => $constraint['onUpdate'],
424 1
                    'deferrable' => $constraint['deferrable'],
425 1
                    'deferred'=> $constraint['deferred'],
426
                ]
427
            );
428
        }
429
430 1
        return $result;
431
    }
432
433
    /**
434
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey
435
     * @param \Doctrine\DBAL\Schema\Table|string         $table
436
     *
437
     * @return \Doctrine\DBAL\Schema\TableDiff
438
     *
439
     * @throws \Doctrine\DBAL\DBALException
440
     */
441
    private function getTableDiffForAlterForeignKey(ForeignKeyConstraint $foreignKey, $table)
0 ignored issues
show
Unused Code introduced by
The parameter $foreignKey is not used and could be removed. ( Ignorable by Annotation )

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

441
    private function getTableDiffForAlterForeignKey(/** @scrutinizer ignore-unused */ ForeignKeyConstraint $foreignKey, $table)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
442
    {
443
        if ( ! $table instanceof Table) {
444
            $tableDetails = $this->tryMethod('listTableDetails', $table);
445
            if (false === $table) {
0 ignored issues
show
introduced by
The condition false === $table is always false.
Loading history...
446
                throw new DBALException(sprintf('Sqlite schema manager requires to modify foreign keys table definition "%s".', $table));
447
            }
448
449
            $table = $tableDetails;
450
        }
451
452
        $tableDiff = new TableDiff($table->getName());
453
        $tableDiff->fromTable = $table;
0 ignored issues
show
Documentation Bug introduced by
It seems like $table can also be of type false. However, the property $fromTable is declared as type Doctrine\DBAL\Schema\Table. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
454
455
        return $tableDiff;
456
    }
457
458 32
    private function parseColumnCollationFromSQL(string $column, string $sql) : ?string
459
    {
460 32
        $pattern = '{(?:\W' . preg_quote($column) . '\W|\W' . preg_quote($this->_platform->quoteSingleIdentifier($column))
461 32
            . '\W)[^,(]+(?:\([^()]+\)[^,]*)?(?:(?:DEFAULT|CHECK)\s*(?:\(.*?\))?[^,]*)*COLLATE\s+["\']?([^\s,"\')]+)}is';
462
463 32
        if (preg_match($pattern, $sql, $match) !== 1) {
464 21
            return null;
465
        }
466
467 14
        return $match[1];
468
    }
469
470 62
    private function parseColumnCommentFromSQL(string $column, string $sql) : ?string
471
    {
472 62
        $pattern = '{[\s(,](?:\W' . preg_quote($this->_platform->quoteSingleIdentifier($column)) . '\W|\W' . preg_quote($column)
473 62
            . '\W)(?:\(.*?\)|[^,(])*?,?((?:(?!\n))(?:\s*--[^\n]*\n?)+)}i';
474
475 62
        if (preg_match($pattern, $sql, $match) !== 1) {
476 46
            return null;
477
        }
478
479 27
        $comment = preg_replace('{^\s*--}m', '', rtrim($match[1], "\n"));
480
481 27
        return '' === $comment ? null : $comment;
482
    }
483
}
484