Completed
Push — cache-closure ( 7d9053...380edd )
by Dmitry
35:54
created

Schema   B

Complexity

Total Complexity 52

Size/Duplication

Total Lines 522
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 92.98%

Importance

Changes 0
Metric Value
wmc 52
lcom 1
cbo 8
dl 0
loc 522
ccs 159
cts 171
cp 0.9298
rs 7.9487
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A createQueryBuilder() 0 4 1
A resolveTableNames() 0 14 3
A quoteSimpleTableName() 0 4 2
A loadTableSchema() 0 12 2
A findSchemaNames() 0 10 1
A findTableNames() 0 21 3
B findConstraints() 0 54 5
A getUniqueIndexInformation() 0 23 1
B loadColumnSchema() 0 24 4
A insert() 0 19 4
A findViewNames() 0 21 3
A getViewNames() 0 8 3
A findUniqueIndexes() 0 17 4
D findColumns() 0 98 16

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\pgsql;
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 PostgreSQL database
16
 * (version 9.x and above).
17
 *
18
 * @property string[] $viewNames All view names in the database. This property is read-only.
19
 *
20
 * @author Gevik Babakhani <[email protected]>
21
 * @since 2.0
22
 */
23
class Schema extends \yii\db\Schema
24
{
25
    /**
26
     * @var string the default schema used for the current session.
27
     */
28
    public $defaultSchema = 'public';
29
    /**
30
     * @var array mapping from physical column types (keys) to abstract
31
     * column types (values)
32
     * @see http://www.postgresql.org/docs/current/static/datatype.html#DATATYPE-TABLE
33
     */
34
    public $typeMap = [
35
        'bit' => self::TYPE_INTEGER,
36
        'bit varying' => self::TYPE_INTEGER,
37
        'varbit' => self::TYPE_INTEGER,
38
39
        'bool' => self::TYPE_BOOLEAN,
40
        'boolean' => self::TYPE_BOOLEAN,
41
42
        'box' => self::TYPE_STRING,
43
        'circle' => self::TYPE_STRING,
44
        'point' => self::TYPE_STRING,
45
        'line' => self::TYPE_STRING,
46
        'lseg' => self::TYPE_STRING,
47
        'polygon' => self::TYPE_STRING,
48
        'path' => self::TYPE_STRING,
49
50
        'character' => self::TYPE_CHAR,
51
        'char' => self::TYPE_CHAR,
52
        'bpchar' => self::TYPE_CHAR,
53
        'character varying' => self::TYPE_STRING,
54
        'varchar' => self::TYPE_STRING,
55
        'text' => self::TYPE_TEXT,
56
57
        'bytea' => self::TYPE_BINARY,
58
59
        'cidr' => self::TYPE_STRING,
60
        'inet' => self::TYPE_STRING,
61
        'macaddr' => self::TYPE_STRING,
62
63
        'real' => self::TYPE_FLOAT,
64
        'float4' => self::TYPE_FLOAT,
65
        'double precision' => self::TYPE_DOUBLE,
66
        'float8' => self::TYPE_DOUBLE,
67
        'decimal' => self::TYPE_DECIMAL,
68
        'numeric' => self::TYPE_DECIMAL,
69
70
        'money' => self::TYPE_MONEY,
71
72
        'smallint' => self::TYPE_SMALLINT,
73
        'int2' => self::TYPE_SMALLINT,
74
        'int4' => self::TYPE_INTEGER,
75
        'int' => self::TYPE_INTEGER,
76
        'integer' => self::TYPE_INTEGER,
77
        'bigint' => self::TYPE_BIGINT,
78
        'int8' => self::TYPE_BIGINT,
79
        'oid' => self::TYPE_BIGINT, // should not be used. it's pg internal!
80
81
        'smallserial' => self::TYPE_SMALLINT,
82
        'serial2' => self::TYPE_SMALLINT,
83
        'serial4' => self::TYPE_INTEGER,
84
        'serial' => self::TYPE_INTEGER,
85
        'bigserial' => self::TYPE_BIGINT,
86
        'serial8' => self::TYPE_BIGINT,
87
        'pg_lsn' => self::TYPE_BIGINT,
88
89
        'date' => self::TYPE_DATE,
90
        'interval' => self::TYPE_STRING,
91
        'time without time zone' => self::TYPE_TIME,
92
        'time' => self::TYPE_TIME,
93
        'time with time zone' => self::TYPE_TIME,
94
        'timetz' => self::TYPE_TIME,
95
        'timestamp without time zone' => self::TYPE_TIMESTAMP,
96
        'timestamp' => self::TYPE_TIMESTAMP,
97
        'timestamp with time zone' => self::TYPE_TIMESTAMP,
98
        'timestamptz' => self::TYPE_TIMESTAMP,
99
        'abstime' => self::TYPE_TIMESTAMP,
100
101
        'tsquery' => self::TYPE_STRING,
102
        'tsvector' => self::TYPE_STRING,
103
        'txid_snapshot' => self::TYPE_STRING,
104
105
        'unknown' => self::TYPE_STRING,
106
107
        'uuid' => self::TYPE_STRING,
108
        'json' => self::TYPE_STRING,
109
        'jsonb' => self::TYPE_STRING,
110
        'xml' => self::TYPE_STRING,
111
    ];
112
113
    /**
114
     * @var array list of ALL view names in the database
115
     */
116
    private $_viewNames = [];
117
118
119
    /**
120
     * Creates a query builder for the PostgreSQL database.
121
     * @return QueryBuilder query builder instance
122
     */
123 146
    public function createQueryBuilder()
124
    {
125 146
        return new QueryBuilder($this->db);
126
    }
127
128
    /**
129
     * Resolves the table name and schema name (if any).
130
     * @param TableSchema $table the table metadata object
131
     * @param string $name the table name
132
     */
133 139
    protected function resolveTableNames($table, $name)
134
    {
135 139
        $parts = explode('.', str_replace('"', '', $name));
136
137 139
        if (isset($parts[1])) {
138
            $table->schemaName = $parts[0];
139
            $table->name = $parts[1];
140
        } else {
141 139
            $table->schemaName = $this->defaultSchema;
142 139
            $table->name = $name;
143
        }
144
145 139
        $table->fullName = $table->schemaName !== $this->defaultSchema ? $table->schemaName . '.' . $table->name : $table->name;
146 139
    }
147
148
    /**
149
     * Quotes a table name for use in a query.
150
     * A simple table name has no schema prefix.
151
     * @param string $name table name
152
     * @return string the properly quoted table name
153
     */
154 187
    public function quoteSimpleTableName($name)
155
    {
156 187
        return strpos($name, '"') !== false ? $name : '"' . $name . '"';
157
    }
158
159
    /**
160
     * Loads the metadata for the specified table.
161
     * @param string $name table name
162
     * @return TableSchema|null driver dependent table metadata. Null if the table does not exist.
163
     */
164 139
    public function loadTableSchema($name)
165
    {
166 139
        $table = new TableSchema();
167 139
        $this->resolveTableNames($table, $name);
168 139
        if ($this->findColumns($table)) {
169 136
            $this->findConstraints($table);
170
171 136
            return $table;
172
        } else {
173 8
            return null;
174
        }
175
    }
176
177
    /**
178
     * Returns all schema names in the database, including the default one but not system schemas.
179
     * This method should be overridden by child classes in order to support this feature
180
     * because the default implementation simply throws an exception.
181
     * @return array all schema names in the database, except system schemas
182
     * @since 2.0.4
183
     */
184 1
    protected function findSchemaNames()
185
    {
186
        $sql = <<<SQL
187
SELECT ns.nspname AS schema_name
188
FROM pg_namespace ns
189
WHERE ns.nspname != 'information_schema' AND ns.nspname NOT LIKE 'pg_%'
190
ORDER BY ns.nspname
191 1
SQL;
192 1
        return $this->db->createCommand($sql)->queryColumn();
193
    }
194
195
    /**
196
     * Returns all table names in the database.
197
     * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema.
198
     * @return array all table names in the database. The names have NO schema name prefix.
199
     */
200 7
    protected function findTableNames($schema = '')
201
    {
202 7
        if ($schema === '') {
203 5
            $schema = $this->defaultSchema;
204 5
        }
205
        $sql = <<<SQL
206
SELECT c.relname AS table_name
207
FROM pg_class c
208
INNER JOIN pg_namespace ns ON ns.oid = c.relnamespace
209
WHERE ns.nspname = :schemaName AND c.relkind IN ('r','v','m','f')
210
ORDER BY c.relname
211 7
SQL;
212 7
        $command = $this->db->createCommand($sql, [':schemaName' => $schema]);
213 7
        $rows = $command->queryAll();
214 7
        $names = [];
215 7
        foreach ($rows as $row) {
216 7
            $names[] = $row['table_name'];
217 7
        }
218
219 7
        return $names;
220
    }
221
222
    /**
223
     * Returns all views names in the database.
224
     * @param string $schema the schema of the views. Defaults to empty string, meaning the current or default schema.
225
     * @return array all views names in the database. The names have NO schema name prefix.
226
     * @since 2.0.9
227
     */
228 2
    protected function findViewNames($schema = '')
229
    {
230 2
        if ($schema === '') {
231
            $schema = $this->defaultSchema;
232
        }
233
        $sql = <<<SQL
234
SELECT c.relname AS table_name
235
FROM pg_class c
236
INNER JOIN pg_namespace ns ON ns.oid = c.relnamespace
237
WHERE ns.nspname = :schemaName AND c.relkind = 'v'
238
ORDER BY c.relname
239 2
SQL;
240 2
        $command = $this->db->createCommand($sql, [':schemaName' => $schema]);
241 2
        $rows = $command->queryAll();
242 2
        $names = [];
243 2
        foreach ($rows as $row) {
244 2
            $names[] = $row['table_name'];
245 2
        }
246
247 2
        return $names;
248
    }
249
250
    /**
251
     * Returns all view names in the database.
252
     * @param string $schema the schema of the views. Defaults to empty string, meaning the current or default schema name.
253
     * If not empty, the returned view names will be prefixed with the schema name.
254
     * @param bool $refresh whether to fetch the latest available view names. If this is false,
255
     * view names fetched previously (if available) will be returned.
256
     * @return string[] all view names in the database.
257
     * @since 2.0.9
258
     */
259 2
    public function getViewNames($schema = '', $refresh = false)
260
    {
261 2
        if (!isset($this->_viewNames[$schema]) || $refresh) {
262 2
            $this->_viewNames[$schema] = $this->findViewNames($schema);
263 2
        }
264
265 2
        return $this->_viewNames[$schema];
266
    }
267
268
    /**
269
     * Collects the foreign key column details for the given table.
270
     * @param TableSchema $table the table metadata
271
     */
272 136
    protected function findConstraints($table)
273
    {
274
275 136
        $tableName = $this->quoteValue($table->name);
276 136
        $tableSchema = $this->quoteValue($table->schemaName);
277
278
        //We need to extract the constraints de hard way since:
279
        //http://www.postgresql.org/message-id/[email protected]
280
281
        $sql = <<<SQL
282
select
283
    ct.conname as constraint_name,
284
    a.attname as column_name,
285
    fc.relname as foreign_table_name,
286
    fns.nspname as foreign_table_schema,
287
    fa.attname as foreign_column_name
288
from
289
    (SELECT ct.conname, ct.conrelid, ct.confrelid, ct.conkey, ct.contype, ct.confkey, generate_subscripts(ct.conkey, 1) AS s
290
       FROM pg_constraint ct
291
    ) AS ct
292
    inner join pg_class c on c.oid=ct.conrelid
293
    inner join pg_namespace ns on c.relnamespace=ns.oid
294
    inner join pg_attribute a on a.attrelid=ct.conrelid and a.attnum = ct.conkey[ct.s]
295
    left join pg_class fc on fc.oid=ct.confrelid
296
    left join pg_namespace fns on fc.relnamespace=fns.oid
297
    left join pg_attribute fa on fa.attrelid=ct.confrelid and fa.attnum = ct.confkey[ct.s]
298
where
299
    ct.contype='f'
300 136
    and c.relname={$tableName}
301 136
    and ns.nspname={$tableSchema}
302
order by
303 136
    fns.nspname, fc.relname, a.attnum
304 136
SQL;
305
306 136
        $constraints = [];
307 136
        foreach ($this->db->createCommand($sql)->queryAll() as $constraint) {
308 54
            if ($constraint['foreign_table_schema'] !== $this->defaultSchema) {
309
                $foreignTable = $constraint['foreign_table_schema'] . '.' . $constraint['foreign_table_name'];
310
            } else {
311 54
                $foreignTable = $constraint['foreign_table_name'];
312
            }
313 54
            $name = $constraint['constraint_name'];
314 54
            if (!isset($constraints[$name])) {
315 54
                $constraints[$name] = [
316 54
                    'tableName' => $foreignTable,
317 54
                    'columns' => [],
318
                ];
319 54
            }
320 54
            $constraints[$name]['columns'][$constraint['column_name']] = $constraint['foreign_column_name'];
321 136
        }
322 136
        foreach ($constraints as $constraint) {
323 54
            $table->foreignKeys[] = array_merge([$constraint['tableName']], $constraint['columns']);
324 136
        }
325 136
    }
326
327
    /**
328
     * Gets information about given table unique indexes.
329
     * @param TableSchema $table the table metadata
330
     * @return array with index and column names
331
     */
332 1
    protected function getUniqueIndexInformation($table)
333
    {
334
        $sql = <<<SQL
335
SELECT
336
    i.relname as indexname,
337
    pg_get_indexdef(idx.indexrelid, k + 1, TRUE) AS columnname
338
FROM (
339
  SELECT *, generate_subscripts(indkey, 1) AS k
340
  FROM pg_index
341
) idx
342
INNER JOIN pg_class i ON i.oid = idx.indexrelid
343
INNER JOIN pg_class c ON c.oid = idx.indrelid
344
INNER JOIN pg_namespace ns ON c.relnamespace = ns.oid
345
WHERE idx.indisprimary = FALSE AND idx.indisunique = TRUE
346
AND c.relname = :tableName AND ns.nspname = :schemaName
347
ORDER BY i.relname, k
348 1
SQL;
349
350 1
        return $this->db->createCommand($sql, [
351 1
            ':schemaName' => $table->schemaName,
352 1
            ':tableName' => $table->name,
353 1
        ])->queryAll();
354
    }
355
356
    /**
357
     * Returns all unique indexes for the given table.
358
     * Each array element is of the following structure:
359
     *
360
     * ```php
361
     * [
362
     *     'IndexName1' => ['col1' [, ...]],
363
     *     'IndexName2' => ['col2' [, ...]],
364
     * ]
365
     * ```
366
     *
367
     * @param TableSchema $table the table metadata
368
     * @return array all unique indexes for the given table.
369
     */
370 1
    public function findUniqueIndexes($table)
371
    {
372 1
        $uniqueIndexes = [];
373
374 1
        $rows = $this->getUniqueIndexInformation($table);
375 1
        foreach ($rows as $row) {
376 1
            $column = $row['columnname'];
377 1
            if (!empty($column) && $column[0] === '"') {
378
                // postgres will quote names that are not lowercase-only
379
                // https://github.com/yiisoft/yii2/issues/10613
380 1
                $column = substr($column, 1, -1);
381 1
            }
382 1
            $uniqueIndexes[$row['indexname']][] = $column;
383 1
        }
384
385 1
        return $uniqueIndexes;
386
    }
387
388
    /**
389
     * Collects the metadata of table columns.
390
     * @param TableSchema $table the table metadata
391
     * @return bool whether the table exists in the database
392
     */
393 139
    protected function findColumns($table)
394
    {
395 139
        $tableName = $this->db->quoteValue($table->name);
396 139
        $schemaName = $this->db->quoteValue($table->schemaName);
397
        $sql = <<<SQL
398
SELECT
399
    d.nspname AS table_schema,
400
    c.relname AS table_name,
401
    a.attname AS column_name,
402
    t.typname AS data_type,
403
    a.attlen AS character_maximum_length,
404
    pg_catalog.col_description(c.oid, a.attnum) AS column_comment,
405
    a.atttypmod AS modifier,
406
    a.attnotnull = false AS is_nullable,
407
    CAST(pg_get_expr(ad.adbin, ad.adrelid) AS varchar) AS column_default,
408
    coalesce(pg_get_expr(ad.adbin, ad.adrelid) ~ 'nextval',false) AS is_autoinc,
409
    array_to_string((select array_agg(enumlabel) from pg_enum where enumtypid=a.atttypid)::varchar[],',') as enum_values,
410
    CASE atttypid
411
         WHEN 21 /*int2*/ THEN 16
412
         WHEN 23 /*int4*/ THEN 32
413
         WHEN 20 /*int8*/ THEN 64
414
         WHEN 1700 /*numeric*/ THEN
415
              CASE WHEN atttypmod = -1
416
               THEN null
417
               ELSE ((atttypmod - 4) >> 16) & 65535
418
               END
419
         WHEN 700 /*float4*/ THEN 24 /*FLT_MANT_DIG*/
420
         WHEN 701 /*float8*/ THEN 53 /*DBL_MANT_DIG*/
421
         ELSE null
422
      END   AS numeric_precision,
423
      CASE
424
        WHEN atttypid IN (21, 23, 20) THEN 0
425
        WHEN atttypid IN (1700) THEN
426
        CASE
427
            WHEN atttypmod = -1 THEN null
428
            ELSE (atttypmod - 4) & 65535
429
        END
430
           ELSE null
431
      END AS numeric_scale,
432
    CAST(
433
             information_schema._pg_char_max_length(information_schema._pg_truetypid(a, t), information_schema._pg_truetypmod(a, t))
434
             AS numeric
435
    ) AS size,
436
    a.attnum = any (ct.conkey) as is_pkey
437
FROM
438
    pg_class c
439
    LEFT JOIN pg_attribute a ON a.attrelid = c.oid
440
    LEFT JOIN pg_attrdef ad ON a.attrelid = ad.adrelid AND a.attnum = ad.adnum
441
    LEFT JOIN pg_type t ON a.atttypid = t.oid
442
    LEFT JOIN pg_namespace d ON d.oid = c.relnamespace
443
    LEFT join pg_constraint ct on ct.conrelid=c.oid and ct.contype='p'
444
WHERE
445
    a.attnum > 0 and t.typname != ''
446 139
    and c.relname = {$tableName}
447 139
    and d.nspname = {$schemaName}
448
ORDER BY
449 139
    a.attnum;
450 139
SQL;
451
452 139
        $columns = $this->db->createCommand($sql)->queryAll();
453 139
        if (empty($columns)) {
454 8
            return false;
455
        }
456 136
        foreach ($columns as $column) {
457 136
            if ($this->db->slavePdo->getAttribute(\PDO::ATTR_CASE) === \PDO::CASE_UPPER) {
458
                $column = array_change_key_case($column, CASE_LOWER);
459
            }
460 136
            $column = $this->loadColumnSchema($column);
461 136
            $table->columns[$column->name] = $column;
462 136
            if ($column->isPrimaryKey) {
463 116
                $table->primaryKey[] = $column->name;
464 116
                if ($table->sequenceName === null && preg_match("/nextval\\('\"?\\w+\"?\.?\"?\\w+\"?'(::regclass)?\\)/", $column->defaultValue) === 1) {
465 107
                    $table->sequenceName = preg_replace(['/nextval/', '/::/', '/regclass/', '/\'\)/', '/\(\'/'], '', $column->defaultValue);
0 ignored issues
show
Documentation Bug introduced by
It seems like preg_replace(array('/nex... $column->defaultValue) can also be of type array<integer,string>. However, the property $sequenceName is declared as type string. 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...
466 107
                }
467 116
                $column->defaultValue = null;
468 136
            } elseif ($column->defaultValue) {
469 85
                if ($column->type === 'timestamp' && $column->defaultValue === 'now()') {
470 21
                    $column->defaultValue = new Expression($column->defaultValue);
471 85
                } elseif ($column->type === 'boolean') {
472 80
                        $column->defaultValue = ($column->defaultValue === 'true');
473 85
                } elseif (stripos($column->dbType, 'bit') === 0 || stripos($column->dbType, 'varbit') === 0) {
474 21
                    $column->defaultValue = bindec(trim($column->defaultValue, 'B\''));
475 27
                } elseif (preg_match("/^'(.*?)'::/", $column->defaultValue, $matches)) {
476 21
                    $column->defaultValue = $matches[1];
477 27
                } elseif (preg_match('/^(?:\()?(.*?)(?(1)\))(?:::.+)?$/', $column->defaultValue, $matches)) {
478 5
                    if ($matches[1] === 'NULL') {
479
                        $column->defaultValue = null;
480
                    } else {
481 5
                        $column->defaultValue = $column->phpTypecast($matches[1]);
482
                    }
483 5
                } else {
484 25
                    $column->defaultValue = $column->phpTypecast($column->defaultValue);
485
                }
486 85
            }
487 136
        }
488
489 136
        return true;
490
    }
491
492
    /**
493
     * Loads the column information into a [[ColumnSchema]] object.
494
     * @param array $info column information
495
     * @return ColumnSchema the column schema object
496
     */
497 136
    protected function loadColumnSchema($info)
498
    {
499 136
        $column = $this->createColumnSchema();
500 136
        $column->allowNull = $info['is_nullable'];
501 136
        $column->autoIncrement = $info['is_autoinc'];
502 136
        $column->comment = $info['column_comment'];
503 136
        $column->dbType = $info['data_type'];
504 136
        $column->defaultValue = $info['column_default'];
505 136
        $column->enumValues = ($info['enum_values'] !== null) ? explode(',', str_replace(["''"], ["'"], $info['enum_values'])) : null;
0 ignored issues
show
Documentation Bug introduced by
It seems like $info['enum_values'] !==...'enum_values'])) : null 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...
506 136
        $column->unsigned = false; // has no meaning in PG
507 136
        $column->isPrimaryKey = $info['is_pkey'];
508 136
        $column->name = $info['column_name'];
509 136
        $column->precision = $info['numeric_precision'];
510 136
        $column->scale = $info['numeric_scale'];
511 136
        $column->size = $info['size'] === null ? null : (int) $info['size'];
512 136
        if (isset($this->typeMap[$column->dbType])) {
513 136
            $column->type = $this->typeMap[$column->dbType];
514 136
        } else {
515
            $column->type = self::TYPE_STRING;
516
        }
517 136
        $column->phpType = $this->getColumnPhpType($column);
518
519 136
        return $column;
520
    }
521
522
    /**
523
     * @inheritdoc
524
     */
525 27
    public function insert($table, $columns)
526
    {
527 27
        $params = [];
528 27
        $sql = $this->db->getQueryBuilder()->insert($table, $columns, $params);
529 27
        $returnColumns = $this->getTableSchema($table)->primaryKey;
530 27
        if (!empty($returnColumns)) {
531 19
            $returning = [];
532 19
            foreach ((array) $returnColumns as $name) {
533 19
                $returning[] = $this->quoteColumnName($name);
534 19
            }
535 19
            $sql .= ' RETURNING ' . implode(', ', $returning);
536 19
        }
537
538 27
        $command = $this->db->createCommand($sql, $params);
539 27
        $command->prepare(false);
540 27
        $result = $command->queryOne();
541
542 27
        return !$command->pdoStatement->rowCount() ? false : $result;
543
    }
544
}
545