Completed
Push — fix-unique-exists-expressions ( b0719b...8467f4 )
by Alexander
07:52
created

ColumnSchemaBuilder   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 432
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 2

Test Coverage

Coverage 92.11%

Importance

Changes 0
Metric Value
wmc 46
lcom 3
cbo 2
dl 0
loc 432
rs 8.3999
c 0
b 0
f 0
ccs 105
cts 114
cp 0.9211

25 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A notNull() 0 5 1
A unique() 0 5 1
A check() 0 5 1
A comment() 0 5 1
A after() 0 5 1
A first() 0 5 1
A defaultExpression() 0 5 1
A null() 0 5 1
A unsigned() 0 13 3
A append() 0 5 1
A buildNotNullString() 0 10 3
A buildUniqueString() 0 4 2
A buildCheckString() 0 4 2
A buildUnsignedString() 0 4 1
A buildAfterString() 0 4 1
A buildFirstString() 0 4 1
A buildAppendString() 0 4 2
A getTypeCategory() 0 4 2
A buildCommentString() 0 4 1
A buildLengthString() 0 10 4
A buildCompleteString() 0 16 2
A defaultValue() 0 9 2
C buildDefaultString() 0 27 8
A __toString() 0 11 2

How to fix   Complexity   

Complex Class

Complex classes like ColumnSchemaBuilder 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 ColumnSchemaBuilder, 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;
9
10
use Yii;
11
use yii\base\Object;
12
13
/**
14
 * ColumnSchemaBuilder helps to define database schema types using a PHP interface.
15
 *
16
 * See [[SchemaBuilderTrait]] for more detailed description and usage examples.
17
 *
18
 * @author Vasenin Matvey <[email protected]>
19
 * @since 2.0.6
20
 */
21
class ColumnSchemaBuilder extends Object
22
{
23
    // Internally used constants representing categories that abstract column types fall under.
24
    // See [[$categoryMap]] for mappings of abstract column types to category.
25
    // @since 2.0.8
26
    const CATEGORY_PK = 'pk';
27
    const CATEGORY_STRING = 'string';
28
    const CATEGORY_NUMERIC = 'numeric';
29
    const CATEGORY_TIME = 'time';
30
    const CATEGORY_OTHER = 'other';
31
32
    /**
33
     * @var string the column type definition such as INTEGER, VARCHAR, DATETIME, etc.
34
     */
35
    protected $type;
36
    /**
37
     * @var int|string|array column size or precision definition. This is what goes into the parenthesis after
38
     * the column type. This can be either a string, an integer or an array. If it is an array, the array values will
39
     * be joined into a string separated by comma.
40
     */
41
    protected $length;
42
    /**
43
     * @var bool|null whether the column is or not nullable. If this is `true`, a `NOT NULL` constraint will be added.
44
     * If this is `false`, a `NULL` constraint will be added.
45
     */
46
    protected $isNotNull;
47
    /**
48
     * @var bool whether the column values should be unique. If this is `true`, a `UNIQUE` constraint will be added.
49
     */
50
    protected $isUnique = false;
51
    /**
52
     * @var string the `CHECK` constraint for the column.
53
     */
54
    protected $check;
55
    /**
56
     * @var mixed default value of the column.
57
     */
58
    protected $default;
59
    /**
60
     * @var mixed SQL string to be appended to column schema definition.
61
     * @since 2.0.9
62
     */
63
    protected $append;
64
    /**
65
     * @var bool whether the column values should be unsigned. If this is `true`, an `UNSIGNED` keyword will be added.
66
     * @since 2.0.7
67
     */
68
    protected $isUnsigned = false;
69
    /**
70
     * @var string the column after which this column will be added.
71
     * @since 2.0.8
72
     */
73
    protected $after;
74
    /**
75
     * @var bool whether this column is to be inserted at the beginning of the table.
76
     * @since 2.0.8
77
     */
78
    protected $isFirst;
79
80
81
    /**
82
     * @var array mapping of abstract column types (keys) to type categories (values).
83
     * @since 2.0.8
84
     */
85
    public $categoryMap = [
86
        Schema::TYPE_PK => self::CATEGORY_PK,
87
        Schema::TYPE_UPK => self::CATEGORY_PK,
88
        Schema::TYPE_BIGPK => self::CATEGORY_PK,
89
        Schema::TYPE_UBIGPK => self::CATEGORY_PK,
90
        Schema::TYPE_CHAR => self::CATEGORY_STRING,
91
        Schema::TYPE_STRING => self::CATEGORY_STRING,
92
        Schema::TYPE_TEXT => self::CATEGORY_STRING,
93
        Schema::TYPE_SMALLINT => self::CATEGORY_NUMERIC,
94
        Schema::TYPE_INTEGER => self::CATEGORY_NUMERIC,
95
        Schema::TYPE_BIGINT => self::CATEGORY_NUMERIC,
96
        Schema::TYPE_FLOAT => self::CATEGORY_NUMERIC,
97
        Schema::TYPE_DOUBLE => self::CATEGORY_NUMERIC,
98
        Schema::TYPE_DECIMAL => self::CATEGORY_NUMERIC,
99
        Schema::TYPE_DATETIME => self::CATEGORY_TIME,
100
        Schema::TYPE_TIMESTAMP => self::CATEGORY_TIME,
101
        Schema::TYPE_TIME => self::CATEGORY_TIME,
102
        Schema::TYPE_DATE => self::CATEGORY_TIME,
103
        Schema::TYPE_BINARY => self::CATEGORY_OTHER,
104
        Schema::TYPE_BOOLEAN => self::CATEGORY_NUMERIC,
105
        Schema::TYPE_MONEY => self::CATEGORY_NUMERIC,
106
    ];
107
    /**
108
     * @var \yii\db\Connection the current database connection. It is used mainly to escape strings
109
     * safely when building the final column schema string.
110
     * @since 2.0.8
111
     */
112
    public $db;
113
    /**
114
     * @var string comment value of the column.
115
     * @since 2.0.8
116
     */
117
    public $comment;
118
119
    /**
120
     * Create a column schema builder instance giving the type and value precision.
121
     *
122
     * @param string $type type of the column. See [[$type]].
123
     * @param int|string|array $length length or precision of the column. See [[$length]].
124
     * @param \yii\db\Connection $db the current database connection. See [[$db]].
125
     * @param array $config name-value pairs that will be used to initialize the object properties
126
     */
127 20
    public function __construct($type, $length = null, $db = null, $config = [])
128
    {
129 20
        $this->type = $type;
130 20
        $this->length = $length;
131 20
        $this->db = $db;
132 20
        parent::__construct($config);
133 20
    }
134
135
    /**
136
     * Adds a `NOT NULL` constraint to the column.
137
     * @return $this
138
     */
139 7
    public function notNull()
140
    {
141 7
        $this->isNotNull = true;
142 7
        return $this;
143
    }
144
145
    /**
146
     * Adds a `NULL` constraint to the column
147
     * @return $this
148
     * @since 2.0.9
149
     */
150 6
    public function null()
151
    {
152 6
        $this->isNotNull = false;
153 6
        return $this;
154
    }
155
156
    /**
157
     * Adds a `UNIQUE` constraint to the column.
158
     * @return $this
159
     */
160
    public function unique()
161
    {
162
        $this->isUnique = true;
163
        return $this;
164
    }
165
166
    /**
167
     * Sets a `CHECK` constraint for the column.
168
     * @param string $check the SQL of the `CHECK` constraint to be added.
169
     * @return $this
170
     */
171 5
    public function check($check)
172
    {
173 5
        $this->check = $check;
174 5
        return $this;
175
    }
176
177
    /**
178
     * Specify the default value for the column.
179
     * @param mixed $default the default value.
180
     * @return $this
181
     */
182 6
    public function defaultValue($default)
183
    {
184 6
        if ($default === null) {
185 5
            $this->null();
186
        }
187
188 6
        $this->default = $default;
189 6
        return $this;
190
    }
191
192
    /**
193
     * Specifies the comment for column.
194
     * @param string $comment the comment
195
     * @return $this
196
     * @since 2.0.8
197
     */
198 7
    public function comment($comment)
199
    {
200 7
        $this->comment = $comment;
201 7
        return $this;
202
    }
203
204
    /**
205
     * Marks column as unsigned.
206
     * @return $this
207
     * @since 2.0.7
208
     */
209 9
    public function unsigned()
210
    {
211 9
        switch ($this->type) {
212 9
            case Schema::TYPE_PK:
213 5
                $this->type = Schema::TYPE_UPK;
214 5
                break;
215 9
            case Schema::TYPE_BIGPK:
216 5
                $this->type = Schema::TYPE_UBIGPK;
217 5
                break;
218
        }
219 9
        $this->isUnsigned = true;
220 9
        return $this;
221
    }
222
223
    /**
224
     * Adds an `AFTER` constraint to the column.
225
     * Note: MySQL, Oracle and Cubrid support only.
226
     * @param string $after the column after which $this column will be added.
227
     * @return $this
228
     * @since 2.0.8
229
     */
230 3
    public function after($after)
231
    {
232 3
        $this->after = $after;
233 3
        return $this;
234
    }
235
236
    /**
237
     * Adds an `FIRST` constraint to the column.
238
     * Note: MySQL, Oracle and Cubrid support only.
239
     * @return $this
240
     * @since 2.0.8
241
     */
242 5
    public function first()
243
    {
244 5
        $this->isFirst = true;
245 5
        return $this;
246
    }
247
248
    /**
249
     * Specify the default SQL expression for the column.
250
     * @param string $default the default value expression.
251
     * @return $this
252
     * @since 2.0.7
253
     */
254
    public function defaultExpression($default)
255
    {
256
        $this->default = new Expression($default);
257
        return $this;
258
    }
259
260
    /**
261
     * Specify additional SQL to be appended to column definition.
262
     * Position modifiers will be appended after column definition in databases that support them.
263
     * @param string $sql the SQL string to be appended.
264
     * @return $this
265
     * @since 2.0.9
266
     */
267 5
    public function append($sql)
268
    {
269 5
        $this->append = $sql;
270 5
        return $this;
271
    }
272
273
    /**
274
     * Builds the full string for the column's schema
275
     * @return string
276
     */
277 11
    public function __toString()
278
    {
279 11
        switch ($this->getTypeCategory()) {
280 11
            case self::CATEGORY_PK:
281 4
                $format = '{type}{check}{comment}{append}';
282 4
                break;
283
            default:
284 11
                $format = '{type}{length}{notnull}{unique}{default}{check}{comment}{append}';
285
        }
286 11
        return $this->buildCompleteString($format);
287
    }
288
289
    /**
290
     * Builds the length/precision part of the column.
291
     * @return string
292
     */
293 18
    protected function buildLengthString()
294
    {
295 18
        if ($this->length === null || $this->length === []) {
296 12
            return '';
297
        }
298 9
        if (is_array($this->length)) {
299 2
            $this->length = implode(',', $this->length);
300
        }
301 9
        return "({$this->length})";
302
    }
303
304
    /**
305
     * Builds the not null constraint for the column.
306
     * @return string returns 'NOT NULL' if [[isNotNull]] is true,
307
     * 'NULL' if [[isNotNull]] is false or an empty string otherwise.
308
     */
309 18
    protected function buildNotNullString()
310
    {
311 18
        if ($this->isNotNull === true) {
312 5
            return ' NOT NULL';
313 17
        } elseif ($this->isNotNull === false) {
314 3
            return ' NULL';
315
        } else {
316 16
            return '';
317
        }
318
    }
319
320
    /**
321
     * Builds the unique constraint for the column.
322
     * @return string returns string 'UNIQUE' if [[isUnique]] is true, otherwise it returns an empty string.
323
     */
324 18
    protected function buildUniqueString()
325
    {
326 18
        return $this->isUnique ? ' UNIQUE' : '';
327
    }
328
329
    /**
330
     * Builds the default value specification for the column.
331
     * @return string string with default value of column.
332
     */
333 18
    protected function buildDefaultString()
334
    {
335 18
        if ($this->default === null) {
336 17
            return $this->isNotNull === false ? ' DEFAULT NULL' : '';
337
        }
338
339 4
        $string = ' DEFAULT ';
340 4
        switch (gettype($this->default)) {
341 4
            case 'integer':
342 2
                $string .= (string) $this->default;
343 2
                break;
344 2
            case 'double':
345
                // ensure type cast always has . as decimal separator in all locales
346
                $string .= str_replace(',', '.', (string) $this->default);
347
                break;
348 2
            case 'boolean':
349 1
                $string .= $this->default ? 'TRUE' : 'FALSE';
350 1
                break;
351 1
            case 'object':
352 1
                $string .= (string) $this->default;
353 1
                break;
354
            default:
355
                $string .= "'{$this->default}'";
356
        }
357
358 4
        return $string;
359
    }
360
361
    /**
362
     * Builds the check constraint for the column.
363
     * @return string a string containing the CHECK constraint.
364
     */
365 18
    protected function buildCheckString()
366
    {
367 18
        return $this->check !== null ? " CHECK ({$this->check})" : '';
368
    }
369
370
    /**
371
     * Builds the unsigned string for column. Defaults to unsupported.
372
     * @return string a string containing UNSIGNED keyword.
373
     * @since 2.0.7
374
     */
375 11
    protected function buildUnsignedString()
376
    {
377 11
        return '';
378
    }
379
380
    /**
381
     * Builds the after constraint for the column. Defaults to unsupported.
382
     * @return string a string containing the AFTER constraint.
383
     * @since 2.0.8
384
     */
385 17
    protected function buildAfterString()
386
    {
387 17
        return '';
388
    }
389
390
    /**
391
     * Builds the first constraint for the column. Defaults to unsupported.
392
     * @return string a string containing the FIRST constraint.
393
     * @since 2.0.8
394
     */
395 1
    protected function buildFirstString()
396
    {
397 1
        return '';
398
    }
399
400
    /**
401
     * Builds the custom string that's appended to column definition.
402
     * @return string custom string to append.
403
     * @since 2.0.9
404
     */
405 18
    protected function buildAppendString()
406
    {
407 18
        return $this->append !== null ? ' ' . $this->append : '';
408
    }
409
410
    /**
411
     * Returns the category of the column type.
412
     * @return string a string containing the column type category name.
413
     * @since 2.0.8
414
     */
415 18
    protected function getTypeCategory()
416
    {
417 18
        return isset($this->categoryMap[$this->type]) ? $this->categoryMap[$this->type] : null;
418
    }
419
420
    /**
421
     * Builds the comment specification for the column.
422
     * @return string a string containing the COMMENT keyword and the comment itself
423
     * @since 2.0.8
424
     */
425 17
    protected function buildCommentString()
426
    {
427 17
        return '';
428
    }
429
430
    /**
431
     * Returns the complete column definition from input format
432
     * @param string $format the format of the definition.
433
     * @return string a string containing the complete column definition.
434
     * @since 2.0.8
435
     */
436 18
    protected function buildCompleteString($format)
437
    {
438
        $placeholderValues = [
439 18
            '{type}' => $this->type,
440 18
            '{length}' => $this->buildLengthString(),
441 18
            '{unsigned}' => $this->buildUnsignedString(),
442 18
            '{notnull}' => $this->buildNotNullString(),
443 18
            '{unique}' => $this->buildUniqueString(),
444 18
            '{default}' => $this->buildDefaultString(),
445 18
            '{check}' => $this->buildCheckString(),
446 18
            '{comment}' => $this->buildCommentString(),
447 18
            '{pos}' => $this->isFirst ? $this->buildFirstString() : $this->buildAfterString(),
448 18
            '{append}' => $this->buildAppendString(),
449
        ];
450 18
        return strtr($format, $placeholderValues);
451
    }
452
}
453