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 |
||
28 | class Schema extends \yii\db\Schema |
||
29 | { |
||
30 | |||
31 | private $_lastInsertID = null; |
||
32 | |||
33 | /** |
||
34 | * @var array map of DB errors and corresponding exceptions |
||
35 | * If left part is found in DB error message exception class from the right part is used. |
||
36 | */ |
||
37 | public $exceptionMap = [ |
||
38 | 'SQLSTATE[23' => 'yii\db\IntegrityException', |
||
39 | 'SQLSTATE[HY000]: General error: -803 violation of PRIMARY' => 'yii\db\IntegrityException', |
||
40 | ]; |
||
41 | public $reservedWords = [ |
||
42 | 'ADD', |
||
43 | 'ADMIN', |
||
44 | 'ALL', |
||
45 | 'ALTER', |
||
46 | 'AND', |
||
47 | 'ANY', |
||
48 | 'AS', |
||
49 | 'AT', |
||
50 | 'AVG', |
||
51 | 'BEGIN', |
||
52 | 'BETWEEN', |
||
53 | 'BIGINT', |
||
54 | 'BIT_LENGTH', |
||
55 | 'BLOB', |
||
56 | 'BOTH', |
||
57 | 'BOOLEAN', |
||
58 | 'BY', |
||
59 | 'CASE', |
||
60 | 'CAST', |
||
61 | 'CHAR', |
||
62 | 'CHAR_LENGTH', |
||
63 | 'CHARACTER', |
||
64 | 'CHARACTER_LENGTH', |
||
65 | 'CHECK', |
||
66 | 'CLOSE', |
||
67 | 'COLLATE', |
||
68 | 'COLUMN', |
||
69 | 'COMMIT', |
||
70 | 'CONNECT', |
||
71 | 99 | 'CONSTRAINT', |
|
72 | 'CORR', |
||
73 | 99 | 'COUNT', |
|
74 | 'COVAR_POP', |
||
75 | 'CREATE', |
||
76 | 'CROSS', |
||
77 | 'CURRENT', |
||
78 | 'CURRENT_CONNECTION', |
||
79 | 2 | 'CURRENT_DATE', |
|
80 | 'CURRENT_ROLE', |
||
81 | 2 | 'CURRENT_TIME', |
|
82 | 'CURRENT_TIMESTAMP', |
||
83 | 'CURRENT_TRANSACTION', |
||
84 | 157 | 'CURRENT_USER', |
|
85 | 'CURSOR', |
||
86 | 157 | 'DATE', |
|
87 | 'DAY', |
||
88 | 'DEC', |
||
89 | 'DECIMAL', |
||
90 | 157 | 'DECLARE', |
|
91 | 157 | 'DEFAULT', |
|
92 | 43 | 'DELETE', |
|
93 | 'DELETING', |
||
94 | 'DETERMINISTIC', |
||
95 | 156 | 'DISCONNECT', |
|
96 | 'DISTINCT', |
||
97 | 'DOUBLE', |
||
98 | 173 | 'DROP', |
|
99 | 'ELSE', |
||
100 | 173 | 'END', |
|
101 | 6 | 'ESCAPE', |
|
102 | 'EXECUTE', |
||
103 | 173 | 'EXISTS', |
|
104 | 'EXTERNAL', |
||
105 | 'EXRACT', |
||
106 | 106 | 'FALSE', |
|
107 | 'FETCH', |
||
108 | 106 | 'FILTER', |
|
109 | 106 | 'FLOAT', |
|
110 | 106 | 'FOR', |
|
111 | 104 | 'FOREIGN', |
|
112 | 104 | 'FROM', |
|
113 | 'FULL', |
||
114 | 7 | 'FUNCTION', |
|
115 | 'GDSCODE', |
||
116 | 'GLOBAL', |
||
117 | 93 | 'GRANT', |
|
118 | 'GROUP', |
||
119 | 93 | 'HAVING', |
|
120 | 'HOUR', |
||
121 | 'IN', |
||
122 | 'INDEX', |
||
123 | 'INNER', |
||
124 | 'INSENSITIVE', |
||
125 | 'INSERT', |
||
126 | 'INSERTING', |
||
127 | 93 | 'INT', |
|
128 | 'INTEGER', |
||
129 | 93 | 'INTO', |
|
130 | 'IS', |
||
131 | 'JOIN', |
||
132 | 'LEADING', |
||
133 | 'LEFT', |
||
134 | 'LIKE', |
||
135 | 'LONG', |
||
136 | 'LOWER', |
||
137 | 106 | 'MAX', |
|
138 | 'MAXIMUM_SEGMENT', |
||
139 | 106 | 'MERGE', |
|
140 | 106 | 'MIN', |
|
141 | 'MINUTE', |
||
142 | 'MONTH', |
||
143 | 'NATIONAL', |
||
144 | 'NATURAL', |
||
145 | 106 | 'NCHAR', |
|
146 | 106 | 'NO', |
|
147 | 'NOT', |
||
148 | 106 | 'NULL', |
|
149 | 'NUMERIC', |
||
150 | 'OCTET_LENGTH', |
||
151 | 'OF', |
||
152 | 'OFFSET', |
||
153 | 'ON', |
||
154 | 'OPEN', |
||
155 | 'OR', |
||
156 | 106 | 'ORDER', |
|
157 | 'OUTER', |
||
158 | 'OVER', |
||
159 | 'PARAMETER', |
||
160 | 'PASSWORD', |
||
161 | 'PLAN', |
||
162 | 'POSITION', |
||
163 | 'POST_EVENT', |
||
164 | 'PRECISION', |
||
165 | 'PRIMARY', |
||
166 | 'PROCEDURE', |
||
167 | 'RDB$DB_KEY', |
||
168 | 'RDB$RECORD_VERSION', |
||
169 | 'REAL', |
||
170 | 'RECORD_VERSION', |
||
171 | 'RECREATE', |
||
172 | 'RECURSIVE', |
||
173 | 'REFERENCES', |
||
174 | 106 | 'REGR_AVGX', |
|
175 | 'REGR_AVGY', |
||
176 | 'REGR_COUNT', |
||
177 | 'REGR_INTERCEPT', |
||
178 | 'REGR_R2', |
||
179 | 'REGR_SLOPE', |
||
180 | 'REGR_SXX', |
||
181 | 'REGR_SXY', |
||
182 | 'REGR_SYY', |
||
183 | 'RELEASE', |
||
184 | 106 | 'RETURN', |
|
185 | 'RETURNING_VALUES', |
||
186 | 106 | 'RETURNS', |
|
187 | 'REVOKE', |
||
188 | 106 | 'RIGHT', |
|
189 | 106 | 'ROLLBACK', |
|
190 | 106 | 'ROW', |
|
191 | 'ROWS', |
||
192 | 'ROW_COUNT', |
||
193 | 'SAVEPOINT', |
||
194 | 'SCROLL', |
||
195 | 'SECOND', |
||
196 | 'SELECT', |
||
197 | 'SENSITIVE', |
||
198 | 'SET', |
||
199 | 'SIMILAR', |
||
200 | 'SOME', |
||
201 | 104 | 'SQLCODE', |
|
202 | 'SQLSTATE', |
||
203 | 104 | 'START', |
|
204 | 'STDDEV_POP', |
||
205 | 'STDDEV_SAMP', |
||
206 | 'SUM', |
||
207 | 104 | 'TABLE', |
|
208 | 104 | 'THEN', |
|
209 | 104 | 'TIME', |
|
210 | 104 | 'TIMESTAMP', |
|
211 | 104 | 'TO', |
|
212 | 'TRAILING', |
||
213 | 104 | 'TRIGGER', |
|
214 | 104 | 'TRIM', |
|
215 | 104 | 'TRUE', |
|
216 | 87 | 'UNION', |
|
217 | 87 | 'UNIQUE', |
|
218 | 79 | 'UNKNOWN', |
|
219 | 13 | 'UPDATE', |
|
220 | 13 | 'UPDATING', |
|
221 | 'UPPER', |
||
222 | 'USER', |
||
223 | 104 | 'USING', |
|
224 | 104 | 'VALUE', |
|
225 | 104 | 'VALUES', |
|
226 | 'VARCHAR', |
||
227 | 'VARIABLE', |
||
228 | 104 | 'VARYING', |
|
229 | 'VAR_POP', |
||
230 | 'VAR_SAMP', |
||
231 | 'VIEW', |
||
232 | 'WHEN', |
||
233 | 'WHERE', |
||
234 | 'WHILE', |
||
235 | 104 | 'WITH', |
|
236 | 'YEAR', |
||
237 | 104 | ]; |
|
238 | |||
239 | /** |
||
240 | * @var array mapping from physical column types (keys) to abstract column types (values) |
||
241 | */ |
||
242 | public $typeMap = [ |
||
243 | 'bigint' => self::TYPE_BIGINT, |
||
244 | 'char' => self::TYPE_CHAR, |
||
245 | 'varchar' => self::TYPE_STRING, |
||
246 | 104 | 'timestamp' => self::TYPE_TIMESTAMP, |
|
247 | 'decimal' => self::TYPE_DECIMAL, |
||
248 | 104 | 'float' => self::TYPE_FLOAT, |
|
249 | 104 | 'blob' => self::TYPE_BINARY, |
|
250 | 104 | 'integer' => self::TYPE_INTEGER, |
|
251 | 104 | 'blob sub_type text' => self::TYPE_TEXT, |
|
252 | 104 | 'numeric' => self::TYPE_DECIMAL, |
|
253 | 104 | 'double precision' => self::TYPE_DOUBLE, |
|
254 | 'smallint' => self::TYPE_SMALLINT, |
||
255 | 104 | ]; |
|
256 | |||
257 | 104 | /** |
|
258 | 104 | * Creates a query builder for the database. |
|
259 | * This method may be overridden by child classes to create a DBMS-specific query builder. |
||
260 | 63 | * @return QueryBuilder query builder instance |
|
261 | 63 | */ |
|
262 | public function createQueryBuilder() |
||
266 | 104 | ||
267 | 103 | /** |
|
268 | * @inheritdoc |
||
269 | 104 | */ |
|
270 | public function createColumnSchemaBuilder($type, $length = null) |
||
274 | |||
275 | public function quoteSimpleTableName($name) |
||
288 | |||
289 | public function quoteSimpleColumnName($name) |
||
296 | |||
297 | 104 | protected function loadTableSchema($name) |
|
307 | 104 | ||
308 | 16 | public function getPdoType($data) |
|
322 | 3 | ||
323 | 47 | /** |
|
324 | 46 | * |
|
325 | 46 | * @param TableSchema $table |
|
326 | 46 | * @param string $name |
|
327 | 46 | */ |
|
328 | 46 | protected function resolveTableNames($table, $name) |
|
340 | |||
341 | 15 | /** |
|
342 | * Collects the table column metadata. |
||
343 | * |
||
344 | 104 | * @param TableSchema $table the table metadata |
|
345 | * @return boolean whether the table exists in the database |
||
346 | 104 | */ |
|
347 | 104 | protected function findColumns($table) |
|
431 | |||
432 | 5 | /** |
|
433 | * @return ColumnSchema |
||
434 | * @throws \yii\base\InvalidConfigException |
||
435 | */ |
||
436 | protected function createColumnSchema() |
||
440 | |||
441 | /** |
||
442 | * Creates a table column. |
||
443 | * |
||
444 | * @param array $column column metadata |
||
445 | * @return ColumnSchema normalized column metadata |
||
446 | */ |
||
447 | protected function loadColumnSchema($column) |
||
570 | |||
571 | /** |
||
572 | * Collects the foreign key column details for the given table. |
||
573 | * |
||
574 | * @param TableSchema $table the table metadata |
||
575 | */ |
||
576 | protected function findConstraints($table) |
||
615 | |||
616 | protected function findTableNames($schema = '') |
||
635 | |||
636 | /** |
||
637 | * Returns all unique indexes for the given table. |
||
638 | * Each array element is of the following structure: |
||
639 | * |
||
640 | * ~~~ |
||
641 | * [ |
||
642 | * 'IndexName1' => ['col1' [, ...]], |
||
643 | * 'IndexName2' => ['col2' [, ...]], |
||
644 | * ] |
||
645 | * ~~~ |
||
646 | * |
||
647 | * @param TableSchema $table the table metadata |
||
648 | * @return array all unique indexes for the given table. |
||
649 | * @since 2.0.4 |
||
650 | */ |
||
651 | public function findUniqueIndexes($table) |
||
668 | |||
669 | /** |
||
670 | * Sets the isolation level of the current transaction. |
||
671 | * @param string $level The transaction isolation level to use for this transaction. |
||
672 | * This can be one of [[Transaction::READ_UNCOMMITTED]], [[Transaction::READ_COMMITTED]], [[Transaction::REPEATABLE_READ]] |
||
673 | * and [[Transaction::SERIALIZABLE]] but also a string containing DBMS specific syntax to be used |
||
674 | * after `SET TRANSACTION ISOLATION LEVEL`. |
||
675 | * @see http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels |
||
676 | */ |
||
677 | public function setTransactionIsolationLevel($level) |
||
689 | |||
690 | /** |
||
691 | * @inheritdoc |
||
692 | */ |
||
693 | public function insert($table, $columns) |
||
725 | |||
726 | /** |
||
727 | * @inheritdoc |
||
728 | */ |
||
729 | public function getLastInsertID($sequenceName = '') |
||
744 | } |
||
745 |
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 theid
property of an instance of theAccount
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.