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 |
||
21 | class Schema extends \yii\db\Schema |
||
22 | { |
||
23 | /** |
||
24 | * @var string the default schema used for the current session. |
||
25 | */ |
||
26 | public $defaultSchema = 'public'; |
||
27 | /** |
||
28 | * @var array mapping from physical column types (keys) to abstract |
||
29 | * column types (values) |
||
30 | * @see http://www.postgresql.org/docs/current/static/datatype.html#DATATYPE-TABLE |
||
31 | */ |
||
32 | public $typeMap = [ |
||
33 | 'bit' => self::TYPE_INTEGER, |
||
34 | 'bit varying' => self::TYPE_INTEGER, |
||
35 | 'varbit' => self::TYPE_INTEGER, |
||
36 | |||
37 | 'bool' => self::TYPE_BOOLEAN, |
||
38 | 'boolean' => self::TYPE_BOOLEAN, |
||
39 | |||
40 | 'box' => self::TYPE_STRING, |
||
41 | 'circle' => self::TYPE_STRING, |
||
42 | 'point' => self::TYPE_STRING, |
||
43 | 'line' => self::TYPE_STRING, |
||
44 | 'lseg' => self::TYPE_STRING, |
||
45 | 'polygon' => self::TYPE_STRING, |
||
46 | 'path' => self::TYPE_STRING, |
||
47 | |||
48 | 'character' => self::TYPE_CHAR, |
||
49 | 'char' => self::TYPE_CHAR, |
||
50 | 'bpchar' => self::TYPE_CHAR, |
||
51 | 'character varying' => self::TYPE_STRING, |
||
52 | 'varchar' => self::TYPE_STRING, |
||
53 | 'text' => self::TYPE_TEXT, |
||
54 | |||
55 | 'bytea' => self::TYPE_BINARY, |
||
56 | |||
57 | 'cidr' => self::TYPE_STRING, |
||
58 | 'inet' => self::TYPE_STRING, |
||
59 | 'macaddr' => self::TYPE_STRING, |
||
60 | |||
61 | 'real' => self::TYPE_FLOAT, |
||
62 | 'float4' => self::TYPE_FLOAT, |
||
63 | 'double precision' => self::TYPE_DOUBLE, |
||
64 | 'float8' => self::TYPE_DOUBLE, |
||
65 | 'decimal' => self::TYPE_DECIMAL, |
||
66 | 'numeric' => self::TYPE_DECIMAL, |
||
67 | |||
68 | 'money' => self::TYPE_MONEY, |
||
69 | |||
70 | 'smallint' => self::TYPE_SMALLINT, |
||
71 | 'int2' => self::TYPE_SMALLINT, |
||
72 | 'int4' => self::TYPE_INTEGER, |
||
73 | 'int' => self::TYPE_INTEGER, |
||
74 | 'integer' => self::TYPE_INTEGER, |
||
75 | 'bigint' => self::TYPE_BIGINT, |
||
76 | 'int8' => self::TYPE_BIGINT, |
||
77 | 'oid' => self::TYPE_BIGINT, // should not be used. it's pg internal! |
||
78 | |||
79 | 'smallserial' => self::TYPE_SMALLINT, |
||
80 | 'serial2' => self::TYPE_SMALLINT, |
||
81 | 'serial4' => self::TYPE_INTEGER, |
||
82 | 'serial' => self::TYPE_INTEGER, |
||
83 | 'bigserial' => self::TYPE_BIGINT, |
||
84 | 'serial8' => self::TYPE_BIGINT, |
||
85 | 'pg_lsn' => self::TYPE_BIGINT, |
||
86 | |||
87 | 'date' => self::TYPE_DATE, |
||
88 | 'interval' => self::TYPE_STRING, |
||
89 | 'time without time zone' => self::TYPE_TIME, |
||
90 | 'time' => self::TYPE_TIME, |
||
91 | 'time with time zone' => self::TYPE_TIME, |
||
92 | 'timetz' => self::TYPE_TIME, |
||
93 | 'timestamp without time zone' => self::TYPE_TIMESTAMP, |
||
94 | 'timestamp' => self::TYPE_TIMESTAMP, |
||
95 | 'timestamp with time zone' => self::TYPE_TIMESTAMP, |
||
96 | 'timestamptz' => self::TYPE_TIMESTAMP, |
||
97 | 'abstime' => self::TYPE_TIMESTAMP, |
||
98 | |||
99 | 'tsquery' => self::TYPE_STRING, |
||
100 | 'tsvector' => self::TYPE_STRING, |
||
101 | 'txid_snapshot' => self::TYPE_STRING, |
||
102 | |||
103 | 'unknown' => self::TYPE_STRING, |
||
104 | |||
105 | 'uuid' => self::TYPE_STRING, |
||
106 | 'json' => self::TYPE_STRING, |
||
107 | 'jsonb' => self::TYPE_STRING, |
||
108 | 'xml' => self::TYPE_STRING, |
||
109 | ]; |
||
110 | /** |
||
111 | * @var array list of ALL view names in the database |
||
112 | */ |
||
113 | private $_viewNames = []; |
||
114 | |||
115 | |||
116 | /** |
||
117 | * Creates a query builder for the PostgreSQL database. |
||
118 | * @return QueryBuilder query builder instance |
||
119 | */ |
||
120 | 129 | public function createQueryBuilder() |
|
124 | |||
125 | /** |
||
126 | * Resolves the table name and schema name (if any). |
||
127 | * @param TableSchema $table the table metadata object |
||
128 | * @param string $name the table name |
||
129 | */ |
||
130 | 120 | protected function resolveTableNames($table, $name) |
|
144 | |||
145 | /** |
||
146 | * Quotes a table name for use in a query. |
||
147 | * A simple table name has no schema prefix. |
||
148 | * @param string $name table name |
||
149 | * @return string the properly quoted table name |
||
150 | */ |
||
151 | 166 | public function quoteSimpleTableName($name) |
|
155 | |||
156 | /** |
||
157 | * Loads the metadata for the specified table. |
||
158 | * @param string $name table name |
||
159 | * @return TableSchema|null driver dependent table metadata. Null if the table does not exist. |
||
160 | */ |
||
161 | 120 | public function loadTableSchema($name) |
|
173 | |||
174 | /** |
||
175 | * Returns all schema names in the database, including the default one but not system schemas. |
||
176 | * This method should be overridden by child classes in order to support this feature |
||
177 | * because the default implementation simply throws an exception. |
||
178 | * @return array all schema names in the database, except system schemas |
||
179 | * @since 2.0.4 |
||
180 | */ |
||
181 | 1 | protected function findSchemaNames() |
|
191 | |||
192 | /** |
||
193 | * Returns all table names in the database. |
||
194 | * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema. |
||
195 | * @return array all table names in the database. The names have NO schema name prefix. |
||
196 | */ |
||
197 | 7 | protected function findTableNames($schema = '') |
|
218 | |||
219 | /** |
||
220 | * Returns all views names in the database. |
||
221 | * @param string $schema the schema of the views. Defaults to empty string, meaning the current or default schema. |
||
222 | * @return array all views names in the database. The names have NO schema name prefix. |
||
223 | * @since 2.0.9 |
||
224 | */ |
||
225 | 2 | protected function findViewNames($schema = '') |
|
226 | { |
||
227 | 2 | if ($schema === '') { |
|
228 | $schema = $this->defaultSchema; |
||
229 | } |
||
230 | $sql = <<<SQL |
||
231 | SELECT c.relname AS table_name |
||
232 | FROM pg_class c |
||
233 | INNER JOIN pg_namespace ns ON ns.oid = c.relnamespace |
||
234 | WHERE ns.nspname = :schemaName AND c.relkind = 'v' |
||
235 | ORDER BY c.relname |
||
236 | 2 | SQL; |
|
237 | 2 | $command = $this->db->createCommand($sql, [':schemaName' => $schema]); |
|
238 | 2 | $rows = $command->queryAll(); |
|
239 | 2 | $names = []; |
|
240 | 2 | foreach ($rows as $row) { |
|
241 | 2 | $names[] = $row['table_name']; |
|
242 | 2 | } |
|
243 | |||
244 | 2 | return $names; |
|
245 | } |
||
246 | |||
247 | /** |
||
248 | * Returns all view names in the database. |
||
249 | * @param string $schema the schema of the views. Defaults to empty string, meaning the current or default schema name. |
||
250 | * If not empty, the returned view names will be prefixed with the schema name. |
||
251 | * @param boolean $refresh whether to fetch the latest available view names. If this is false, |
||
252 | * view names fetched previously (if available) will be returned. |
||
253 | * @return string[] all view names in the database. |
||
254 | * @since 2.0.9 |
||
255 | */ |
||
256 | 2 | public function getViewNames($schema = '', $refresh = false) |
|
257 | { |
||
258 | 2 | if (!isset($this->_viewNames[$schema]) || $refresh) { |
|
259 | 2 | $this->_viewNames[$schema] = $this->findViewNames($schema); |
|
260 | 2 | } |
|
261 | |||
262 | 2 | return $this->_viewNames[$schema]; |
|
263 | } |
||
264 | |||
265 | /** |
||
266 | * Collects the foreign key column details for the given table. |
||
267 | * @param TableSchema $table the table metadata |
||
268 | */ |
||
269 | 117 | protected function findConstraints($table) |
|
323 | |||
324 | /** |
||
325 | * Gets information about given table unique indexes. |
||
326 | * @param TableSchema $table the table metadata |
||
327 | * @return array with index and column names |
||
328 | */ |
||
329 | protected function getUniqueIndexInformation($table) |
||
352 | |||
353 | /** |
||
354 | * Returns all unique indexes for the given table. |
||
355 | * Each array element is of the following structure: |
||
356 | * |
||
357 | * ```php |
||
358 | * [ |
||
359 | * 'IndexName1' => ['col1' [, ...]], |
||
360 | * 'IndexName2' => ['col2' [, ...]], |
||
361 | * ] |
||
362 | * ``` |
||
363 | * |
||
364 | * @param TableSchema $table the table metadata |
||
365 | * @return array all unique indexes for the given table. |
||
366 | */ |
||
367 | public function findUniqueIndexes($table) |
||
378 | |||
379 | /** |
||
380 | * Collects the metadata of table columns. |
||
381 | * @param TableSchema $table the table metadata |
||
382 | * @return boolean whether the table exists in the database |
||
383 | */ |
||
384 | 120 | protected function findColumns($table) |
|
479 | |||
480 | /** |
||
481 | * Loads the column information into a [[ColumnSchema]] object. |
||
482 | * @param array $info column information |
||
483 | * @return ColumnSchema the column schema object |
||
484 | */ |
||
485 | 117 | protected function loadColumnSchema($info) |
|
509 | |||
510 | /** |
||
511 | * @inheritdoc |
||
512 | */ |
||
513 | 25 | public function insert($table, $columns) |
|
532 | } |
||
533 |
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.