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 |
||
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 = []) |
|
134 | |||
135 | /** |
||
136 | * Adds a `NOT NULL` constraint to the column. |
||
137 | * @return $this |
||
138 | */ |
||
139 | 7 | public function notNull() |
|
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() |
||
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) |
|
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) |
|
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) |
|
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() |
|
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) |
||
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) |
|
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() |
|
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() |
|
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() |
|
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() |
|
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() |
|
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() |
|
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() |
|
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() |
|
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() |
|
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) |
|
452 | } |
||
453 |