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 ( ecf3ef...78a151 )
by Robert
11:40
created

Schema   C

Complexity

Total Complexity 59

Size/Duplication

Total Lines 391
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 14

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 59
lcom 1
cbo 14
dl 0
loc 391
ccs 0
cts 231
cp 0
rs 5.849
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A findTableNames() 0 14 3
C loadTableSchema() 0 45 7
A loadTablePrimaryKey() 0 13 2
B loadTableForeignKeys() 0 26 4
A loadTableIndexes() 0 4 1
A loadTableUniques() 0 4 1
A loadTableChecks() 0 4 1
A loadTableDefaultValues() 0 4 1
A releaseSavepoint() 0 4 1
A createQueryBuilder() 0 4 1
C loadColumnSchema() 0 65 24
A getPdoType() 0 14 2
B setTransactionIsolationLevel() 0 19 5
A createColumnSchemaBuilder() 0 4 1
B loadTableConstraints() 0 32 5

How to fix   Complexity   

Complex Class

Complex classes like Schema 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 Schema, and based on these observations, apply Extract Interface, too.

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\cubrid;
9
10
use yii\base\NotSupportedException;
11
use yii\db\Constraint;
12
use yii\db\ConstraintFinderInterface;
13
use yii\db\ConstraintFinderTrait;
14
use yii\db\Expression;
15
use yii\db\ForeignKeyConstraint;
16
use yii\db\IndexConstraint;
17
use yii\db\TableSchema;
18
use yii\db\Transaction;
19
use yii\helpers\ArrayHelper;
20
21
/**
22
 * Schema is the class for retrieving metadata from a CUBRID database (version 9.3.x and higher).
23
 *
24
 * @author Carsten Brandt <[email protected]>
25
 * @since 2.0
26
 */
27
class Schema extends \yii\db\Schema implements ConstraintFinderInterface
28
{
29
    use ConstraintFinderTrait;
30
31
    /**
32
     * @var array mapping from physical column types (keys) to abstract column types (values)
33
     * Please refer to [CUBRID manual](http://www.cubrid.org/manual/91/en/sql/datatype.html) for
34
     * details on data types.
35
     */
36
    public $typeMap = [
37
        // Numeric data types
38
        'short' => self::TYPE_SMALLINT,
39
        'smallint' => self::TYPE_SMALLINT,
40
        'int' => self::TYPE_INTEGER,
41
        'integer' => self::TYPE_INTEGER,
42
        'bigint' => self::TYPE_BIGINT,
43
        'numeric' => self::TYPE_DECIMAL,
44
        'decimal' => self::TYPE_DECIMAL,
45
        'float' => self::TYPE_FLOAT,
46
        'real' => self::TYPE_FLOAT,
47
        'double' => self::TYPE_DOUBLE,
48
        'double precision' => self::TYPE_DOUBLE,
49
        'monetary' => self::TYPE_MONEY,
50
        // Date/Time data types
51
        'date' => self::TYPE_DATE,
52
        'time' => self::TYPE_TIME,
53
        'timestamp' => self::TYPE_TIMESTAMP,
54
        'datetime' => self::TYPE_DATETIME,
55
        // String data types
56
        'char' => self::TYPE_CHAR,
57
        'varchar' => self::TYPE_STRING,
58
        'char varying' => self::TYPE_STRING,
59
        'nchar' => self::TYPE_CHAR,
60
        'nchar varying' => self::TYPE_STRING,
61
        'string' => self::TYPE_STRING,
62
        // BLOB/CLOB data types
63
        'blob' => self::TYPE_BINARY,
64
        'clob' => self::TYPE_BINARY,
65
        // Bit string data types
66
        'bit' => self::TYPE_INTEGER,
67
        'bit varying' => self::TYPE_INTEGER,
68
        // Collection data types (considered strings for now)
69
        'set' => self::TYPE_STRING,
70
        'multiset' => self::TYPE_STRING,
71
        'list' => self::TYPE_STRING,
72
        'sequence' => self::TYPE_STRING,
73
        'enum' => self::TYPE_STRING,
74
    ];
75
    /**
76
     * @var array map of DB errors and corresponding exceptions
77
     * If left part is found in DB error message exception class from the right part is used.
78
     */
79
    public $exceptionMap = [
80
        'Operation would have caused one or more unique constraint violations' => 'yii\db\IntegrityException',
81
    ];
82
83
    /**
84
     * @inheritDoc
85
     */
86
    protected $tableQuoteCharacter = '"';
87
88
    /**
89
     * @inheritDoc
90
     */
91
    protected function findTableNames($schema = '')
92
    {
93
        $pdo = $this->db->getSlavePdo();
94
        $tables = $pdo->cubrid_schema(\PDO::CUBRID_SCH_TABLE);
95
        $tableNames = [];
96
        foreach ($tables as $table) {
97
            // do not list system tables
98
            if ($table['TYPE'] != 0) {
99
                $tableNames[] = $table['NAME'];
100
            }
101
        }
102
103
        return $tableNames;
104
    }
105
106
    /**
107
     * @inheritDoc
108
     */
109
    protected function loadTableSchema($name)
110
    {
111
        $pdo = $this->db->getSlavePdo();
112
113
        $tableInfo = $pdo->cubrid_schema(\PDO::CUBRID_SCH_TABLE, $name);
114
115
        if (!isset($tableInfo[0]['NAME'])) {
116
            return null;
117
        }
118
119
        $table = new TableSchema();
120
        $table->fullName = $table->name = $tableInfo[0]['NAME'];
121
122
        $sql = 'SHOW FULL COLUMNS FROM ' . $this->quoteSimpleTableName($table->name);
123
        $columns = $this->db->createCommand($sql)->queryAll();
124
125
        foreach ($columns as $info) {
126
            $column = $this->loadColumnSchema($info);
127
            $table->columns[$column->name] = $column;
128
        }
129
130
        $primaryKeys = $pdo->cubrid_schema(\PDO::CUBRID_SCH_PRIMARY_KEY, $table->name);
131
        foreach ($primaryKeys as $key) {
132
            $column = $table->columns[$key['ATTR_NAME']];
133
            $column->isPrimaryKey = true;
134
            $table->primaryKey[] = $column->name;
135
            if ($column->autoIncrement) {
136
                $table->sequenceName = '';
137
            }
138
        }
139
140
        $foreignKeys = $pdo->cubrid_schema(\PDO::CUBRID_SCH_IMPORTED_KEYS, $table->name);
141
        foreach ($foreignKeys as $key) {
142
            if (isset($table->foreignKeys[$key['FK_NAME']])) {
143
                $table->foreignKeys[$key['FK_NAME']][$key['FKCOLUMN_NAME']] = $key['PKCOLUMN_NAME'];
144
            } else {
145
                $table->foreignKeys[$key['FK_NAME']] = [
146
                    $key['PKTABLE_NAME'],
147
                    $key['FKCOLUMN_NAME'] => $key['PKCOLUMN_NAME'],
148
                ];
149
            }
150
        }
151
152
        return $table;
153
    }
154
155
    /**
156
     * @inheritDoc
157
     */
158
    protected function loadTablePrimaryKey($tableName)
159
    {
160
        $primaryKey = $this->db->getSlavePdo()->cubrid_schema(\PDO::CUBRID_SCH_PRIMARY_KEY, $tableName);
161
        if (empty($primaryKey)) {
162
            return null;
163
        }
164
165
        ArrayHelper::multisort($primaryKey, 'KEY_SEQ', SORT_ASC, SORT_NUMERIC);
166
        return new Constraint([
167
            'name' => $primaryKey[0]['KEY_NAME'],
168
            'columnNames' => ArrayHelper::getColumn($primaryKey, 'ATTR_NAME'),
169
        ]);
170
    }
171
172
    /**
173
     * @inheritDoc
174
     */
175
    protected function loadTableForeignKeys($tableName)
176
    {
177
        static $actionTypes = [
178
            0 => 'CASCADE',
179
            1 => 'RESTRICT',
180
            2 => 'NO ACTION',
181
            3 => 'SET NULL',
182
        ];
183
184
        $foreignKeys = $this->db->getSlavePdo()->cubrid_schema(\PDO::CUBRID_SCH_IMPORTED_KEYS, $tableName);
185
        $foreignKeys = ArrayHelper::index($foreignKeys, null, 'FK_NAME');
186
        ArrayHelper::multisort($foreignKeys, 'KEY_SEQ', SORT_ASC, SORT_NUMERIC);
187
        $result = [];
188
        foreach ($foreignKeys as $name => $foreignKey) {
189
            $result[] = new ForeignKeyConstraint([
190
                'name' => $name,
191
                'columnNames' => ArrayHelper::getColumn($foreignKey, 'FKCOLUMN_NAME'),
192
                'foreignTableName' => $foreignKey[0]['PKTABLE_NAME'],
193
                'foreignColumnNames' => ArrayHelper::getColumn($foreignKey, 'PKCOLUMN_NAME'),
194
                'onDelete' => isset($actionTypes[$foreignKey[0]['DELETE_RULE']]) ? $actionTypes[$foreignKey[0]['DELETE_RULE']] : null,
195
                'onUpdate' => isset($actionTypes[$foreignKey[0]['UPDATE_RULE']]) ? $actionTypes[$foreignKey[0]['UPDATE_RULE']] : null,
196
            ]);
197
        }
198
199
        return $result;
200
    }
201
202
    /**
203
     * @inheritDoc
204
     */
205
    protected function loadTableIndexes($tableName)
206
    {
207
        return $this->loadTableConstraints($tableName, 'indexes');
208
    }
209
210
    /**
211
     * @inheritDoc
212
     */
213
    protected function loadTableUniques($tableName)
214
    {
215
        return $this->loadTableConstraints($tableName, 'uniques');
216
    }
217
218
    /**
219
     * @inheritDoc
220
     * @throws NotSupportedException if this method is called.
221
     */
222
    protected function loadTableChecks($tableName)
0 ignored issues
show
Unused Code introduced by
The parameter $tableName is not used and could be removed.

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

Loading history...
223
    {
224
        throw new NotSupportedException('CUBRID does not support check constraints.');
225
    }
226
227
    /**
228
     * @inheritDoc
229
     * @throws NotSupportedException if this method is called.
230
     */
231
    protected function loadTableDefaultValues($tableName)
0 ignored issues
show
Unused Code introduced by
The parameter $tableName is not used and could be removed.

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

Loading history...
232
    {
233
        throw new NotSupportedException('CUBRID does not support default value constraints.');
234
    }
235
236
    /**
237
     * {@inheritdoc}
238
     */
239
    public function releaseSavepoint($name)
240
    {
241
        // does nothing as cubrid does not support this
242
    }
243
244
    /**
245
     * Creates a query builder for the CUBRID database.
246
     * @return QueryBuilder query builder instance
247
     */
248
    public function createQueryBuilder()
249
    {
250
        return new QueryBuilder($this->db);
251
    }
252
253
    /**
254
     * Loads the column information into a [[ColumnSchema]] object.
255
     * @param array $info column information
256
     * @return \yii\db\ColumnSchema the column schema object
257
     */
258
    protected function loadColumnSchema($info)
259
    {
260
        $column = $this->createColumnSchema();
261
262
        $column->name = $info['Field'];
263
        $column->allowNull = $info['Null'] === 'YES';
264
        $column->isPrimaryKey = false; // primary key will be set by loadTableSchema() later
265
        $column->autoIncrement = stripos($info['Extra'], 'auto_increment') !== false;
266
267
        $column->dbType = $info['Type'];
268
        $column->unsigned = strpos($column->dbType, 'unsigned') !== false;
269
270
        $column->type = self::TYPE_STRING;
271
        if (preg_match('/^([\w ]+)(?:\(([^\)]+)\))?$/', $column->dbType, $matches)) {
272
            $type = strtolower($matches[1]);
273
            $column->dbType = $type . (isset($matches[2]) ? "({$matches[2]})" : '');
274
            if (isset($this->typeMap[$type])) {
275
                $column->type = $this->typeMap[$type];
276
            }
277
            if (!empty($matches[2])) {
278
                if ($type === 'enum') {
279
                    $values = preg_split('/\s*,\s*/', $matches[2]);
280
                    foreach ($values as $i => $value) {
281
                        $values[$i] = trim($value, "'");
282
                    }
283
                    $column->enumValues = $values;
284
                } else {
285
                    $values = explode(',', $matches[2]);
286
                    $column->size = $column->precision = (int) $values[0];
287
                    if (isset($values[1])) {
288
                        $column->scale = (int) $values[1];
289
                    }
290
                    if ($column->size === 1 && $type === 'bit') {
291
                        $column->type = 'boolean';
292
                    } elseif ($type === 'bit') {
293
                        if ($column->size > 32) {
294
                            $column->type = 'bigint';
295
                        } elseif ($column->size === 32) {
296
                            $column->type = 'integer';
297
                        }
298
                    }
299
                }
300
            }
301
        }
302
303
        $column->phpType = $this->getColumnPhpType($column);
304
305
        if ($column->isPrimaryKey) {
306
            return $column;
307
        }
308
309
        if ($column->type === 'timestamp' && $info['Default'] === 'SYS_TIMESTAMP' ||
310
            $column->type === 'datetime' && $info['Default'] === 'SYS_DATETIME' ||
311
            $column->type === 'date' && $info['Default'] === 'SYS_DATE' ||
312
            $column->type === 'time' && $info['Default'] === 'SYS_TIME'
313
        ) {
314
            $column->defaultValue = new Expression($info['Default']);
315
        } elseif (isset($type) && $type === 'bit') {
316
            $column->defaultValue = hexdec(trim($info['Default'], 'X\''));
317
        } else {
318
            $column->defaultValue = $column->phpTypecast($info['Default']);
319
        }
320
321
        return $column;
322
    }
323
324
    /**
325
     * Determines the PDO type for the given PHP data value.
326
     * @param mixed $data the data whose PDO type is to be determined
327
     * @return int the PDO type
328
     * @see http://www.php.net/manual/en/pdo.constants.php
329
     */
330
    public function getPdoType($data)
331
    {
332
        static $typeMap = [
333
            // php type => PDO type
334
            'boolean' => \PDO::PARAM_INT, // PARAM_BOOL is not supported by CUBRID PDO
335
            'integer' => \PDO::PARAM_INT,
336
            'string' => \PDO::PARAM_STR,
337
            'resource' => \PDO::PARAM_LOB,
338
            'NULL' => \PDO::PARAM_NULL,
339
        ];
340
        $type = gettype($data);
341
342
        return isset($typeMap[$type]) ? $typeMap[$type] : \PDO::PARAM_STR;
343
    }
344
345
    /**
346
     * {@inheritdoc}
347
     * @see http://www.cubrid.org/manual/91/en/sql/transaction.html#database-concurrency
348
     */
349
    public function setTransactionIsolationLevel($level)
350
    {
351
        // translate SQL92 levels to CUBRID levels:
352
        switch ($level) {
353
            case Transaction::SERIALIZABLE:
354
                $level = '6'; // SERIALIZABLE
355
                break;
356
            case Transaction::REPEATABLE_READ:
357
                $level = '5'; // REPEATABLE READ CLASS with REPEATABLE READ INSTANCES
358
                break;
359
            case Transaction::READ_COMMITTED:
360
                $level = '4'; // REPEATABLE READ CLASS with READ COMMITTED INSTANCES
361
                break;
362
            case Transaction::READ_UNCOMMITTED:
363
                $level = '3'; // REPEATABLE READ CLASS with READ UNCOMMITTED INSTANCES
364
                break;
365
        }
366
        parent::setTransactionIsolationLevel($level);
367
    }
368
369
    /**
370
     * {@inheritdoc}
371
     */
372
    public function createColumnSchemaBuilder($type, $length = null)
373
    {
374
        return new ColumnSchemaBuilder($type, $length, $this->db);
375
    }
376
377
    /**
378
     * Loads multiple types of constraints and returns the specified ones.
379
     * @param string $tableName table name.
380
     * @param string $returnType return type:
381
     * - indexes
382
     * - uniques
383
     * @return mixed constraints.
384
     */
385
    private function loadTableConstraints($tableName, $returnType)
386
    {
387
        $constraints = $this->db->getSlavePdo()->cubrid_schema(\PDO::CUBRID_SCH_CONSTRAINT, $tableName);
388
        $constraints = ArrayHelper::index($constraints, null, ['TYPE', 'NAME']);
389
        ArrayHelper::multisort($constraints, 'KEY_ORDER', SORT_ASC, SORT_NUMERIC);
390
        $result = [
391
            'indexes' => [],
392
            'uniques' => [],
393
        ];
394
        foreach ($constraints as $type => $names) {
395
            foreach ($names as $name => $constraint) {
396
                $isUnique = in_array((int) $type, [0, 2], true);
397
                $result['indexes'][] = new IndexConstraint([
398
                    'isPrimary' => (bool) $constraint[0]['PRIMARY_KEY'],
399
                    'isUnique' => $isUnique,
400
                    'name' => $name,
401
                    'columnNames' => ArrayHelper::getColumn($constraint, 'ATTR_NAME'),
402
                ]);
403
                if ($isUnique) {
404
                    $result['uniques'][] = new Constraint([
405
                        'name' => $name,
406
                        'columnNames' => ArrayHelper::getColumn($constraint, 'ATTR_NAME'),
407
                    ]);
408
                }
409
            }
410
        }
411
        foreach ($result as $type => $data) {
412
            $this->setTableMetadata($tableName, $type, $data);
413
        }
414
415
        return $result[$returnType];
416
    }
417
}
418