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 ( 6d277d...c73de3 )
by Robert
11:50
created

Schema::findConstraints()   C

Complexity

Conditions 9
Paths 33

Size

Total Lines 59
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 19.125

Importance

Changes 0
Metric Value
dl 0
loc 59
ccs 17
cts 34
cp 0.5
rs 6.9133
c 0
b 0
f 0
cc 9
eloc 30
nc 33
nop 1
crap 19.125

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @link http://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license http://www.yiiframework.com/license/
6
 */
7
8
namespace yii\db\mysql;
9
10
use yii\db\Expression;
11
use yii\db\TableSchema;
12
use yii\db\ColumnSchema;
13
14
/**
15
 * Schema is the class for retrieving metadata from a MySQL database (version 4.1.x and 5.x).
16
 *
17
 * @author Qiang Xue <[email protected]>
18
 * @since 2.0
19
 */
20
class Schema extends \yii\db\Schema
21
{
22
    /**
23
     * @var array mapping from physical column types (keys) to abstract column types (values)
24
     */
25
    public $typeMap = [
26
        'tinyint' => self::TYPE_SMALLINT,
27
        'bit' => self::TYPE_INTEGER,
28
        'smallint' => self::TYPE_SMALLINT,
29
        'mediumint' => self::TYPE_INTEGER,
30
        'int' => self::TYPE_INTEGER,
31
        'integer' => self::TYPE_INTEGER,
32
        'bigint' => self::TYPE_BIGINT,
33
        'float' => self::TYPE_FLOAT,
34
        'double' => self::TYPE_DOUBLE,
35
        'real' => self::TYPE_FLOAT,
36
        'decimal' => self::TYPE_DECIMAL,
37
        'numeric' => self::TYPE_DECIMAL,
38
        'tinytext' => self::TYPE_TEXT,
39
        'mediumtext' => self::TYPE_TEXT,
40
        'longtext' => self::TYPE_TEXT,
41
        'longblob' => self::TYPE_BINARY,
42
        'blob' => self::TYPE_BINARY,
43
        'text' => self::TYPE_TEXT,
44
        'varchar' => self::TYPE_STRING,
45
        'string' => self::TYPE_STRING,
46
        'char' => self::TYPE_CHAR,
47
        'datetime' => self::TYPE_DATETIME,
48
        'year' => self::TYPE_DATE,
49
        'date' => self::TYPE_DATE,
50
        'time' => self::TYPE_TIME,
51
        'timestamp' => self::TYPE_TIMESTAMP,
52
        'enum' => self::TYPE_STRING,
53
        'varbinary' => self::TYPE_BINARY,
54
    ];
55
56
57
    /**
58
     * Quotes a table name for use in a query.
59
     * A simple table name has no schema prefix.
60
     * @param string $name table name
61
     * @return string the properly quoted table name
62
     */
63 303
    public function quoteSimpleTableName($name)
64
    {
65 303
        return strpos($name, '`') !== false ? $name : "`$name`";
66
    }
67
68
    /**
69
     * Quotes a column name for use in a query.
70
     * A simple column name has no prefix.
71
     * @param string $name column name
72
     * @return string the properly quoted column name
73
     */
74 310
    public function quoteSimpleColumnName($name)
75
    {
76 310
        return strpos($name, '`') !== false || $name === '*' ? $name : "`$name`";
77
    }
78
79
    /**
80
     * Creates a query builder for the MySQL database.
81
     * @return QueryBuilder query builder instance
82
     */
83 149
    public function createQueryBuilder()
84
    {
85 149
        return new QueryBuilder($this->db);
86
    }
87
88
    /**
89
     * Loads the metadata for the specified table.
90
     * @param string $name table name
91
     * @return TableSchema driver dependent table metadata. Null if the table does not exist.
92
     */
93 150
    protected function loadTableSchema($name)
94
    {
95 150
        $table = new TableSchema;
96 150
        $this->resolveTableNames($table, $name);
97
98 150
        if ($this->findColumns($table)) {
99 147
            $this->findConstraints($table);
100
101 147
            return $table;
102
        } else {
103 7
            return null;
104
        }
105
    }
106
107
    /**
108
     * Resolves the table name and schema name (if any).
109
     * @param TableSchema $table the table metadata object
110
     * @param string $name the table name
111
     */
112 150
    protected function resolveTableNames($table, $name)
113
    {
114 150
        $parts = explode('.', str_replace('`', '', $name));
115 150
        if (isset($parts[1])) {
116
            $table->schemaName = $parts[0];
117
            $table->name = $parts[1];
118
            $table->fullName = $table->schemaName . '.' . $table->name;
119
        } else {
120 150
            $table->fullName = $table->name = $parts[0];
121
        }
122 150
    }
123
124
    /**
125
     * Loads the column information into a [[ColumnSchema]] object.
126
     * @param array $info column information
127
     * @return ColumnSchema the column schema object
128
     */
129 147
    protected function loadColumnSchema($info)
130
    {
131 147
        $column = $this->createColumnSchema();
132
133 147
        $column->name = $info['field'];
134 147
        $column->allowNull = $info['null'] === 'YES';
135 147
        $column->isPrimaryKey = strpos($info['key'], 'PRI') !== false;
136 147
        $column->autoIncrement = stripos($info['extra'], 'auto_increment') !== false;
137 147
        $column->comment = $info['comment'];
138
139 147
        $column->dbType = $info['type'];
140 147
        $column->unsigned = stripos($column->dbType, 'unsigned') !== false;
141
142 147
        $column->type = self::TYPE_STRING;
143 147
        if (preg_match('/^(\w+)(?:\(([^\)]+)\))?/', $column->dbType, $matches)) {
144 147
            $type = strtolower($matches[1]);
145 147
            if (isset($this->typeMap[$type])) {
146 147
                $column->type = $this->typeMap[$type];
147 147
            }
148 147
            if (!empty($matches[2])) {
149 147
                if ($type === 'enum') {
150 14
                    preg_match_all("/'[^']*'/", $matches[2], $values);
151 14
                    foreach ($values[0] as $i => $value) {
152 14
                        $values[$i] = trim($value, "'");
153 14
                    }
154 14
                    $column->enumValues = $values;
0 ignored issues
show
Documentation Bug introduced by
It seems like $values can be null. However, the property $enumValues is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
155 14
                } else {
156 147
                    $values = explode(',', $matches[2]);
157 147
                    $column->size = $column->precision = (int) $values[0];
158 147
                    if (isset($values[1])) {
159 64
                        $column->scale = (int) $values[1];
160 64
                    }
161 147
                    if ($column->size === 1 && $type === 'bit') {
162 5
                        $column->type = 'boolean';
163 147
                    } elseif ($type === 'bit') {
164 14
                        if ($column->size > 32) {
165
                            $column->type = 'bigint';
166 14
                        } elseif ($column->size === 32) {
167
                            $column->type = 'integer';
168
                        }
169 14
                    }
170
                }
171 147
            }
172 147
        }
173
174 147
        $column->phpType = $this->getColumnPhpType($column);
175
176 147
        if (!$column->isPrimaryKey) {
177 143
            if ($column->type === 'timestamp' && $info['default'] === 'CURRENT_TIMESTAMP') {
178 14
                $column->defaultValue = new Expression('CURRENT_TIMESTAMP');
179 143
            } elseif (isset($type) && $type === 'bit') {
180 15
                $column->defaultValue = bindec(trim($info['default'], 'b\''));
181 15
            } else {
182 142
                $column->defaultValue = $column->phpTypecast($info['default']);
183
            }
184 143
        }
185
186 147
        return $column;
187
    }
188
189
    /**
190
     * Collects the metadata of table columns.
191
     * @param TableSchema $table the table metadata
192
     * @return bool whether the table exists in the database
193
     * @throws \Exception if DB query fails
194
     */
195 150
    protected function findColumns($table)
196
    {
197 150
        $sql = 'SHOW FULL COLUMNS FROM ' . $this->quoteTableName($table->fullName);
198
        try {
199 150
            $columns = $this->db->createCommand($sql)->queryAll();
200 150
        } catch (\Exception $e) {
201 7
            $previous = $e->getPrevious();
202 7
            if ($previous instanceof \PDOException && strpos($previous->getMessage(), 'SQLSTATE[42S02') !== false) {
203
                // table does not exist
204
                // https://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html#error_er_bad_table_error
205 7
                return false;
206
            }
207
            throw $e;
208
        }
209 147
        foreach ($columns as $info) {
210 147
            if ($this->db->slavePdo->getAttribute(\PDO::ATTR_CASE) !== \PDO::CASE_LOWER) {
211 146
                $info = array_change_key_case($info, CASE_LOWER);
212 146
            }
213 147
            $column = $this->loadColumnSchema($info);
214 147
            $table->columns[$column->name] = $column;
215 147
            if ($column->isPrimaryKey) {
216 135
                $table->primaryKey[] = $column->name;
217 135
                if ($column->autoIncrement) {
218 105
                    $table->sequenceName = '';
219 105
                }
220 135
            }
221 147
        }
222
223 147
        return true;
224
    }
225
226
    /**
227
     * Gets the CREATE TABLE sql string.
228
     * @param TableSchema $table the table metadata
229
     * @return string $sql the result of 'SHOW CREATE TABLE'
230
     */
231 1
    protected function getCreateTableSql($table)
232
    {
233 1
        $row = $this->db->createCommand('SHOW CREATE TABLE ' . $this->quoteTableName($table->fullName))->queryOne();
234 1
        if (isset($row['Create Table'])) {
235 1
            $sql = $row['Create Table'];
236 1
        } else {
237
            $row = array_values($row);
238
            $sql = $row[1];
239
        }
240
241 1
        return $sql;
242
    }
243
244
    /**
245
     * Collects the foreign key column details for the given table.
246
     * @param TableSchema $table the table metadata
247
     * @throws \Exception
248
     */
249 147
    protected function findConstraints($table)
250
    {
251
        $sql = <<<SQL
252
SELECT
253
    kcu.constraint_name,
254
    kcu.column_name,
255
    kcu.referenced_table_name,
256
    kcu.referenced_column_name
257
FROM information_schema.referential_constraints AS rc
258
JOIN information_schema.key_column_usage AS kcu ON
259
    (
260
        kcu.constraint_catalog = rc.constraint_catalog OR
261
        (kcu.constraint_catalog IS NULL AND rc.constraint_catalog IS NULL)
262
    ) AND
263
    kcu.constraint_schema = rc.constraint_schema AND
264
    kcu.constraint_name = rc.constraint_name
265
WHERE rc.constraint_schema = database() AND kcu.table_schema = database()
266
AND rc.table_name = :tableName AND kcu.table_name = :tableName1
267 147
SQL;
268
269
        try {
270 147
            $rows = $this->db->createCommand($sql, [':tableName' => $table->name, ':tableName1' => $table->name])->queryAll();
271 147
            $constraints = [];
272
273 147
            foreach ($rows as $row) {
274 67
                $constraints[$row['constraint_name']]['referenced_table_name'] = $row['referenced_table_name'];
275 67
                $constraints[$row['constraint_name']]['columns'][$row['column_name']] = $row['referenced_column_name'];
276 147
            }
277
278 147
            $table->foreignKeys = [];
279 147
            foreach ($constraints as $name => $constraint) {
280 67
                $table->foreignKeys[$name] = array_merge(
281 67
                    [$constraint['referenced_table_name']],
282 67
                    $constraint['columns']
283 67
                );
284 147
            }
285 147
        } catch (\Exception $e) {
286
            $previous = $e->getPrevious();
287
            if (!$previous instanceof \PDOException || strpos($previous->getMessage(), 'SQLSTATE[42S02') === false) {
288
                throw $e;
289
            }
290
291
            // table does not exist, try to determine the foreign keys using the table creation sql
292
            $sql = $this->getCreateTableSql($table);
293
            $regexp = '/FOREIGN KEY\s+\(([^\)]+)\)\s+REFERENCES\s+([^\(^\s]+)\s*\(([^\)]+)\)/mi';
294
            if (preg_match_all($regexp, $sql, $matches, PREG_SET_ORDER)) {
295
                foreach ($matches as $match) {
296
                    $fks = array_map('trim', explode(',', str_replace('`', '', $match[1])));
297
                    $pks = array_map('trim', explode(',', str_replace('`', '', $match[3])));
298
                    $constraint = [str_replace('`', '', $match[2])];
299
                    foreach ($fks as $k => $name) {
300
                        $constraint[$name] = $pks[$k];
301
                    }
302
                    $table->foreignKeys[md5(serialize($constraint))] = $constraint;
303
                }
304
                $table->foreignKeys = array_values($table->foreignKeys);
305
            }
306
        }
307 147
    }
308
309
    /**
310
     * Returns all unique indexes for the given table.
311
     * Each array element is of the following structure:
312
     *
313
     * ```php
314
     * [
315
     *     'IndexName1' => ['col1' [, ...]],
316
     *     'IndexName2' => ['col2' [, ...]],
317
     * ]
318
     * ```
319
     *
320
     * @param TableSchema $table the table metadata
321
     * @return array all unique indexes for the given table.
322
     */
323 1
    public function findUniqueIndexes($table)
324
    {
325 1
        $sql = $this->getCreateTableSql($table);
326 1
        $uniqueIndexes = [];
327
328 1
        $regexp = '/UNIQUE KEY\s+([^\(\s]+)\s*\(([^\(\)]+)\)/mi';
329 1
        if (preg_match_all($regexp, $sql, $matches, PREG_SET_ORDER)) {
330 1
            foreach ($matches as $match) {
331 1
                $indexName = str_replace('`', '', $match[1]);
332 1
                $indexColumns = array_map('trim', explode(',', str_replace('`', '', $match[2])));
333 1
                $uniqueIndexes[$indexName] = $indexColumns;
334 1
            }
335 1
        }
336
337 1
        return $uniqueIndexes;
338
    }
339
340
    /**
341
     * Returns all table names in the database.
342
     * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema.
343
     * @return array all table names in the database. The names have NO schema name prefix.
344
     */
345 6
    protected function findTableNames($schema = '')
346
    {
347 6
        $sql = 'SHOW TABLES';
348 6
        if ($schema !== '') {
349
            $sql .= ' FROM ' . $this->quoteSimpleTableName($schema);
350
        }
351
352 6
        return $this->db->createCommand($sql)->queryColumn();
353
    }
354
355
    /**
356
     * @inheritdoc
357
     */
358 2
    public function createColumnSchemaBuilder($type, $length = null)
359
    {
360 2
        return new ColumnSchemaBuilder($type, $length, $this->db);
361
    }
362
}
363