GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( bcda8c...485b14 )
by Tarun
01:44
created

MigrationController::actionUpData()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
namespace tmukherjee13\migration\console\controllers;
3
4
use Yii;
5
use yii\console\controllers\MigrateController;
6
use yii\console\Exception;
7
use yii\db\Connection;
8
use yii\db\Query;
9
use yii\helpers\ArrayHelper;
10
use yii\helpers\Console;
11
use yii\helpers\FileHelper;
12
13
class MigrationController extends MigrateController
14
{
15
    use \tmukherjee13\migration\console\components\Formatter;
16
17
    /**
18
     * @inheritdoc
19
     */
20
    public $defaultAction = 'migrate';
21
22
    /**
23
     * @var string a migration table name
24
     */
25
    public $migrationTable = 'migration';
26
27
    /**
28
     * @var string a migration path
29
     */
30
    public $migrationPath = "@app/migrations";
31
32
    /**
33
     * @var string путь к данным
34
     */
35
    public $dataMigrationFolder = 'data';
36
37
    /**
38
     * @var bool использовать путь к данным
39
     */
40
    public $useDataMigrationFolder = true;
41
42
    /** @var string template file to use for generation */
43
    public $templateFile = "@tmukherjee13/migration";
44
45
    /**
46
     * @var string class name
47
     */
48
    protected $class = "";
49
50
    /**
51
     * @var string table name
52
     */
53
    protected $table = "";
54
55
    /**
56
     * @var string table columns
57
     */
58
    public $fields = "";
59
60
    /**
61
     * @var string file name
62
     */
63
    protected $fileName = '';
64
65
    /**
66
     * @var Connection|string the DB connection object or the application component ID of the DB connection.
67
     */
68
    public $db = 'db';
69
70
    /**
71
     * @inheritdoc
72
     */
73
    public function options($actionID)
74
    {
75
        return array_merge(parent::options($actionID), ['migrationTable', 'db']);
76
    }
77
78
    /**
79
     * @inheritdoc
80
     */
81
    public function beforeAction($action)
82
    {
83
84
        if (parent::beforeAction($action)) {
85
            if (is_string($this->db)) {
86
                $this->db = Yii::$app->get($this->db);
87
            }
88
            if (!$this->db instanceof Connection) {
89
                throw new Exception("The 'db' option must refer to the application component ID of a DB connection.");
90
            }
91
92
            $path = (string)Yii::getAlias($this->migrationPath);
93
94
95
            if (!is_dir($path)) {
96
                if ($action->id !== 'table') {
97
98
                    throw new Exception("Migration failed. Directory specified in migrationPath doesn't exist: {$this->migrationPath}");
99
                }
100
                FileHelper::createDirectory($path);
101
            }
102
            $this->migrationPath = $path;
103
104
            $version = Yii::getVersion();
105
            $this->stdout("Yii Database Migration Tool (based on Yii v{$version})\n", Console::FG_YELLOW);
106
107
            return true;
108
        }
109
        return false;
110
    }
111
112
    /**
113
     * Collects the foreign key column details for the given table.
114
     * @param TableSchema $table the table metadata
115
     */
116
    protected function findConstraints($table)
117
    {
118
        $sql = <<<SQL
119
            SELECT
120
                kcu.constraint_name,
121
                kcu.column_name,
122
                kcu.referenced_table_name,
123
                kcu.referenced_column_name,
124
                rc.DELETE_RULE,
125
                rc.UPDATE_RULE
126
127
            FROM information_schema.referential_constraints AS rc
128
            JOIN information_schema.key_column_usage AS kcu ON
129
                (
130
                    kcu.constraint_catalog = rc.constraint_catalog OR
131
                    (kcu.constraint_catalog IS NULL AND rc.constraint_catalog IS NULL)
132
                ) AND
133
                kcu.constraint_schema = rc.constraint_schema AND
134
                kcu.constraint_name = rc.constraint_name
135
            WHERE rc.constraint_schema = database() AND kcu.table_schema = database()
136
            AND rc.table_name = :tableName AND kcu.table_name = :tableName
137
SQL;
138
        try {
139
140
            $rows = $this->db->createCommand($sql, [':tableName' => $table->name])->queryAll();
141
142
            $constraints        = [];
143
            $table->foreignKeys = [];
144
            foreach ($rows as $row) {
145
                $constraints[$row['constraint_name']]['referenced_table_name']        = $row['referenced_table_name'];
146
                $constraints[$row['constraint_name']]['columns'][$row['column_name']] = $row['referenced_column_name'];
147
148
                $table->foreignKeys[$row['constraint_name']]['table']      = $row['referenced_table_name'];
149
                $table->foreignKeys[$row['constraint_name']]['column']     = $row['column_name'];
150
                $table->foreignKeys[$row['constraint_name']]['ref_column'] = $row['referenced_column_name'];
151
                $table->foreignKeys[$row['constraint_name']]['delete']     = $row['DELETE_RULE'];
152
                $table->foreignKeys[$row['constraint_name']]['update']     = $row['UPDATE_RULE'];
153
            }
154
155
            return $constraints;
156
        } catch (\Exception $e) {
157
            $previous = $e->getPrevious();
158
            if (!$previous instanceof \PDOException || strpos($previous->getMessage(), 'SQLSTATE[42S02') === false) {
159
                throw $e;
160
            }
161
162
            // table does not exist, try to determine the foreign keys using the table creation sql
163
            $sql    = $this->getCreateTableSql($table);
164
            $regexp = '/FOREIGN KEY\s+\(([^\)]+)\)\s+REFERENCES\s+([^\(^\s]+)\s*\(([^\)]+)\)/mi';
165
            if (preg_match_all($regexp, $sql, $matches, PREG_SET_ORDER)) {
166
                foreach ($matches as $match) {
167
                    $fks        = array_map('trim', explode(',', str_replace('`', '', $match[1])));
168
                    $pks        = array_map('trim', explode(',', str_replace('`', '', $match[3])));
169
                    $constraint = [str_replace('`', '', $match[2])];
170
                    foreach ($fks as $k => $name) {
171
                        $constraint[$name] = $pks[$k];
172
                    }
173
                    $table->foreignKeys[md5(serialize($constraint))] = $constraint;
174
                }
175
                $table->foreignKeys = array_values($table->foreignKeys);
176
            }
177
        }
178
    }
179
180
    /**
181
     * Gets the CREATE TABLE sql string.
182
     * @param TableSchema $table the table metadata
183
     * @return string $sql the result of 'SHOW CREATE TABLE'
184
     */
185
    protected function getCreateTableSql($table)
186
    {
187
        $row = $this->db->createCommand('SHOW CREATE TABLE ' . $this->quoteTableName($table->fullName))->queryOne();
188
        if (isset($row['Create Table'])) {
189
            $sql = $row['Create Table'];
190
        } else {
191
            $row = array_values($row);
192
            $sql = $row[1];
193
        }
194
        return $sql;
195
    }
196
197
    public function quoteTableName($name)
198
    {
199
        return strpos($name, '`') !== false ? $name : "`$name`";
200
    }
201
202
    /**
203
     * Up data
204
     *
205
     * @param int $limit
206
     * @return int
207
     */
208
    public function actionUpData($limit = 0)
209
    {
210
        $this->migrationPath .= DIRECTORY_SEPARATOR . $this->dataMigrationFolder;
211
        return parent::actionUp($limit);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (actionUp() instead of actionUpData()). Are you sure this is correct? If so, you might want to change this to $this->actionUp().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
212
    }
213
214
    /**
215
     * Creates migration based on table
216
     * @method actionTable
217
     * @param  array       $tables Name of the table to create migration
218
     * @return mixed
219
     * @author Tarun Mukherjee (https://github.com/tmukherjee13)
220
     */
221
222
    public function actionTable(array $tables)
223
    {
224
225
        if ($this->confirm('Create the migration ' . "?")) {
226
227
            foreach ($tables as $key => $tableName) {
228
229
                $this->class = 'create_table_' . $tableName;
230
231
                try {
232
233
                    $table = $this->db->getTableSchema($tableName);
234
                } catch (Exception $e) {
235
                    throw new Exception("There has been an error processing the file. Please try after some time.");
236
                }
237
238
                if (empty($table)) {
239
                    throw new Exception("Table doesn't exists");
240
                }
241
                $this->findConstraints($table);
242
243
                $this->getCreateTableSql($table);
244
245
                $compositePrimaryKeyCols = array();
246
247
                $addForeignKeys  = "";
248
                $dropForeignKeys = "";
249
                $up              = "";
250
251
                $this->table = $this->getTableName($table);
252
253
                foreach ($table->columns as $col) {
254
                    $up .= "\t\t\t" . '\'' . $col->name . '\'=>"' . $this->getColType($col) . '",' . "\n";
255
                    if ($col->isPrimaryKey) {
256
                        // Add column to composite primary key array
257
                        $compositePrimaryKeyCols[] = $col->name;
258
                    }
259
                }
260
261
                $ukeys = $this->db->schema->findUniqueIndexes($table);
262
                if (!empty($ukeys)) {
263
                    $indexArr =[];
264
                    foreach ($ukeys as $key => $value) {
265
                        $indexKey = $key;
266
                        foreach ($value as $id => $field) {
267
                            $indexArr[] = $field;
268
                        }
269
                    }
270
                    $indexStr = implode(',', $indexArr);
271
                    $up .= "\t\t" . '$this->createIndex(\'idx_' . $indexKey . "', '" . $this->getTableName($table) . "', '$indexStr', TRUE);\n";
0 ignored issues
show
Bug introduced by
The variable $indexKey does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
272
273
                }
274
275
                if (!empty($table->foreignKeys)):
276
277
                    foreach ($table->foreignKeys as $fkName => $fk) {
278
                        $addForeignKeys .= "\t\t" . '$this->addForeignKey("' . $fkName . '", "' . $table->name . '", "' . $fk['column'] . '","' . $fk['table'] . '","' . $fk['ref_column'] . '", "' . $fk['delete'] . '", "' . $fk['update'] . '");' . "\n";
279
                        $dropForeignKeys .= '$this->dropForeignKey(' . "'$fkName', '$table->name');";
280
                    }
281
282
                endif;
283
284
                $this->fields = $table->columns;
285
286
                $fields = $this->parseFields();
287
288
                $this->prepareFile(['up' => '', 'down' => '', 'foreignKeys' => $table->foreignKeys, 'fields' => $fields]) . "\n\n";
289
290
            }
291
292
        }
293
        return;
294
    }
295
296
    /**
297
     * Returns the name of the data migration file created
298
     * @param array $tables the list of tables
299
     * @return integer|null
300
     */
301
    public function actionData(array $tables)
302
    {
303
304
        if ($this->confirm('Create the migration ' . "?", true)) {
305
            foreach ($tables as $key => $args) {
306
307
                $table              = $args;
308
                $this->class        = 'insert_data_into_' . $table;
309
                $this->table        = $table;
310
                $this->templateFile = '@tmukherjee13/migration/views/dataTemplate.php';
311
312
                $columns = $this->db->getTableSchema($table);
313
                $prefix  = $this->db->tablePrefix;
314
                $table   = str_replace($prefix, '', $table);
0 ignored issues
show
Unused Code introduced by
$table 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...
315
                $table   = $columns;
316
317
                $this->table = $this->getTableName($table);
318
319
                $prepared_columns = '';
0 ignored issues
show
Unused Code introduced by
$prepared_columns 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...
320
                $up               = '';
0 ignored issues
show
Unused Code introduced by
$up 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...
321
                $down             = '';
0 ignored issues
show
Unused Code introduced by
$down 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...
322
                $prepared_data    = [];
323
324
                $name = $this->getFileName();
0 ignored issues
show
Unused Code introduced by
$name 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...
325
326
                if (!empty($table)) {
327
328
                    $query = new Query;
329
                    $query->select('*')
330
                        ->from($table->name);
331
                    $command = $query->createCommand();
332
                    $data    = $command->queryAll();
333
334
                    $pcolumns = '';
335
                    foreach ($columns->columns as $column) {
336
                        $pcolumns .= "'" . $column->name . "',";
337
                    }
338
                    foreach ($data as $row) {
339
                        array_push($prepared_data, $row);
340
                    }
341
342
                    if (empty($prepared_data)) {
343
                        $this->stdout("\nTable '{$table->name}' doesn't contain any data.\n\n", Console::FG_RED);
344
                    } else {
345
                        $pcolumns = $this->prepareColumns($pcolumns);
346
                        $prows    = $this->prepareData($prepared_data);
347
348
                        if ($this->useDataMigrationFolder) {
349
                            $path = $this->migrationPath . DIRECTORY_SEPARATOR . $this->dataMigrationFolder;
350
                            FileHelper::createDirectory($path);
351
                            $this->migrationPath = $path;
352
                        }
353
                        $this->prepareFile(['columns' => $pcolumns, 'rows' => $prows]);
354
                    }
355
                    // return self::EXIT_CODE_ERROR;
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% 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...
356
                }
357
            }
358
            return self::EXIT_CODE_NORMAL;
359
        }
360
    }
361
362
    /**
363
     * Returns the name of the database migration file created
364
     * @param string $args the schema name
365
     * @return integer
366
     */
367
    public function actionSchema($args)
368
    {
369
370
        $schema      = $args;
371
        $this->class = 'dump_database_' . $schema;
372
373
        // $tables = $this->db->schema->getTableNames($schema);
0 ignored issues
show
Unused Code Comprehensibility introduced by
57% 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...
374
375
        $tables          = $this->db->schema->getTableSchemas($schema);
376
        $addForeignKeys  = '';
0 ignored issues
show
Unused Code introduced by
$addForeignKeys 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...
377
        $dropForeignKeys = '';
0 ignored issues
show
Unused Code introduced by
$dropForeignKeys 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...
378
        $up              = '';
0 ignored issues
show
Unused Code introduced by
$up 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...
379
        $down            = '';
0 ignored issues
show
Unused Code introduced by
$down 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...
380
        $hasPrimaryKey   = false;
0 ignored issues
show
Unused Code introduced by
$hasPrimaryKey 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...
381
        $name            = $this->getFileName();
0 ignored issues
show
Unused Code introduced by
$name 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...
382
        $tablePrefix     = $this->db->tablePrefix;
0 ignored issues
show
Unused Code introduced by
$tablePrefix 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...
383
        $generateTables  = [];
384
385
        foreach ($tables as $table) {
386
            if ($table->name === $this->db->tablePrefix . $this->migrationTable) {
387
                continue;
388
            }
389
            $generateTables[] = $table->name;
390
        }
391
        $this->actionTable($generateTables);
392
        return self::EXIT_CODE_NORMAL;
393
394
    }
395
396
    public function getFileName()
397
    {
398
        return 'm' . gmdate('ymd_His') . '_' . $this->class;
399
    }
400
401
    public function setFileName()
402
    {
403
        $this->fileName = $this->getFileName();
404
    }
405
406
    public function prepareFile($data)
407
    {
408
        $file = $this->migrationPath . DIRECTORY_SEPARATOR . $this->getFileName() . '.php';
409
        try {
410
411
            $data['table']     = $this->table;
412
            $data['className'] = $this->getFileName();
413
            $content           = $this->renderFile(Yii::getAlias($this->templateFile), $data);
0 ignored issues
show
Bug introduced by
It seems like \Yii::getAlias($this->templateFile) targeting yii\BaseYii::getAlias() can also be of type boolean; however, yii\base\Controller::renderFile() 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...
414
            file_put_contents($file, $content);
415
            $this->stdout("\nNew migration {$this->getFileName()} successfully created.\nRun yii migrate to apply migrations.\n", Console::FG_GREEN);
416
            return $file;
417
        } catch (Exception $e) {
418
            throw new Exception("There has been an error processing the file. Please try after some time.");
419
        }
420
    }
421
422
    
423
424
    /**
425
     * @inheritdoc
426
     */
427
    protected function getMigrationHistory($limit)
428
    {
429
        if ($this->db->schema->getTableSchema($this->migrationTable, true) === null) {
430
            $this->createMigrationHistoryTable();
431
        }
432
        $query = new Query;
433
        $rows  = $query->select(['version', 'apply_time'])
434
            ->from($this->migrationTable)
435
            ->orderBy('apply_time DESC, version DESC')
436
            ->limit($limit)
437
            ->createCommand($this->db)
0 ignored issues
show
Bug introduced by
It seems like $this->db can also be of type string; however, yii\db\Query::createCommand() does only seem to accept object<yii\db\Connection>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
438
            ->queryAll();
439
        $history = ArrayHelper::map($rows, 'version', 'apply_time');
440
        unset($history[self::BASE_MIGRATION]);
441
442
        return $history;
443
    }
444
445
    /**
446
     * @inheritdoc
447
     */
448
    protected function addMigrationHistory($version)
449
    {
450
        $command = $this->db->createCommand();
451
        $command->insert($this->migrationTable, [
452
            'version'    => $version,
453
            'apply_time' => time(),
454
        ])->execute();
455
    }
456
457
    /**
458
     * @inheritdoc
459
     */
460
    protected function removeMigrationHistory($version)
461
    {
462
        $command = $this->db->createCommand();
463
        $command->delete($this->migrationTable, [
464
            'version' => $version,
465
        ])->execute();
466
    }
467
468
    /**
469
     * @inheritdoc
470
     */
471
    protected function parseFields()
472
    {
473
        $fields = [];
474
475
        foreach ($this->fields as $column => $schema) {
0 ignored issues
show
Bug introduced by
The expression $this->fields of type string is not traversable.
Loading history...
476
            $chunks = [];
477
478
            $columns = $this->formatCol($schema);
479
480
            foreach ($columns as $key => $chunk) {
481
                if (!preg_match('/^(.+?)\(([^)]+)\)$/', $chunk)) {
482
                    $chunk .= '()';
483
                }
484
                $chunks[] = $chunk;
485
            }
486
            $fields[] = [
487
                'property'   => $column,
488
                'decorators' => implode('->', $chunks),
489
            ];
490
        }
491
        return $fields;
492
    }
493
}
494