Total Complexity | 71 |
Total Lines | 402 |
Duplicated Lines | 0 % |
Changes | 3 | ||
Bugs | 1 | Features | 2 |
Complex classes like DBHandler 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.
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 DBHandler, and based on these observations, apply Extract Interface, too.
1 | <?php namespace Hafiz\Libraries; |
||
17 | class DBHandler |
||
18 | { |
||
19 | /** |
||
20 | * @var array|BaseConnection|string|null |
||
21 | */ |
||
22 | protected $db = null; |
||
23 | |||
24 | /** |
||
25 | * DBHandler constructor. |
||
26 | * |
||
27 | * @param string|null $group |
||
28 | */ |
||
29 | public function __construct(string $group = null) |
||
30 | { |
||
31 | try { |
||
32 | $this->db = Database::connect($group); |
||
33 | $this->db->initialize(); |
||
34 | } catch (Throwable $exception) { |
||
35 | CLI::error($exception->getMessage()); |
||
36 | die(); |
||
|
|||
37 | } |
||
38 | } |
||
39 | |||
40 | /** |
||
41 | * |
||
42 | */ |
||
43 | public function generateDBMigration(): void |
||
44 | { |
||
45 | $tables = $this->getTableNames(); |
||
46 | foreach ($tables as $table) { |
||
47 | $tableInfo = $this->getTableInfos($table); |
||
48 | |||
49 | $file = new FileHandler(); |
||
50 | |||
51 | $file->writeTable($table, $tableInfo[0], $tableInfo[1]); |
||
52 | } |
||
53 | } |
||
54 | |||
55 | /** |
||
56 | * Return a list of All tables |
||
57 | * Name from a specific database group |
||
58 | * or default on |
||
59 | * |
||
60 | * @return array |
||
61 | */ |
||
62 | public function getTableNames(): array |
||
63 | { |
||
64 | $tables = $this->db->listTables() ?? []; |
||
65 | |||
66 | if (empty($tables)) { |
||
67 | CLI::error(lang('Recharge.TablesNotFound')); |
||
68 | exit(1); |
||
69 | } |
||
70 | |||
71 | return $tables; |
||
72 | } |
||
73 | |||
74 | /** |
||
75 | * return a list of all fields and |
||
76 | * key generated from a table |
||
77 | * |
||
78 | * @param string $table |
||
79 | * |
||
80 | * @return array |
||
81 | */ |
||
82 | public function getTableInfos(string $table): array |
||
83 | { |
||
84 | $fields = $this->generateField($table); |
||
85 | |||
86 | $indexes = $this->generateKeys($table); |
||
87 | |||
88 | $relations = $this->generateForeignKeys($table); |
||
89 | |||
90 | return ['attributes' => $fields, |
||
91 | 'keys' => $indexes . "\n" . $relations |
||
92 | ]; |
||
93 | } |
||
94 | |||
95 | /** |
||
96 | * Generate Field array form a table |
||
97 | * |
||
98 | * @param string $table |
||
99 | * |
||
100 | * @return string |
||
101 | */ |
||
102 | protected function generateField(string $table): ?string |
||
103 | { |
||
104 | $query = $this->db->query("DESCRIBE $table")->getResult(); |
||
105 | $fieldString = ''; |
||
106 | |||
107 | foreach ($query as $field) { |
||
108 | $singleField = "\n\t\t'$field->Field' => ["; |
||
109 | //Type |
||
110 | if (preg_match('/^([a-z]+)/', $field->Type, $matches) > 0) |
||
111 | $singleField .= "\n\t\t\t'type' => '" . strtoupper($matches[1]) . "',"; |
||
112 | |||
113 | //Constraint |
||
114 | if (preg_match('/\((.+)\)/', $field->Type, $matches) > 0) { |
||
115 | //integer , varchar |
||
116 | if (is_numeric($matches[1])) |
||
117 | $singleField .= "\n\t\t\t'constraint' => " . $matches[1] . ","; |
||
118 | |||
119 | //float , double |
||
120 | elseif (preg_match('/[\d]+\s?,[\d]+\s?/', $matches[1]) > 0) |
||
121 | $singleField .= "\n\t\t\t'constraint' => '" . $matches[1] . "',"; |
||
122 | |||
123 | //Enum Fields |
||
124 | else { |
||
125 | $values = explode(',', str_replace("'", "", $matches[1])); |
||
126 | |||
127 | if (count($values) == 1) |
||
128 | $singleField .= "\n\t\t\t'constraint' => [" . $this->getGluedString($values) . "],"; |
||
129 | |||
130 | else |
||
131 | $singleField .= "\n\t\t\t'constraint' => " . $this->getGluedString($values) . ","; |
||
132 | } |
||
133 | } |
||
134 | |||
135 | //if field need null |
||
136 | $singleField .= "\n\t\t\t'null' => " . (($field->Null == 'YES') ? 'true,' : 'false,'); |
||
137 | |||
138 | if (!is_null($field->Default) && (strpos($field->Default, 'current_timestamp()') === FALSE)) |
||
139 | $singleField .= "\n\t\t\t'default' => '$field->Default',"; |
||
140 | |||
141 | //unsigned |
||
142 | if (strpos($field->Type, 'unsigned') !== false) |
||
143 | $singleField .= "\n\t\t\t'unsigned' => true,"; |
||
144 | |||
145 | //autoincrement |
||
146 | if (strpos($field->Extra, 'auto_increment') !== false) |
||
147 | $singleField .= "\n\t\t\t'auto_increment' => true,"; |
||
148 | |||
149 | $singleField .= "\n\t\t],"; |
||
150 | $fieldString .= $singleField; |
||
151 | } |
||
152 | |||
153 | return $fieldString; |
||
154 | } |
||
155 | |||
156 | /** |
||
157 | * Glue a array into a single string |
||
158 | * |
||
159 | * @param array $arr |
||
160 | * |
||
161 | * @param bool $is_assoc |
||
162 | * |
||
163 | * @return string |
||
164 | * @author hafijul233 |
||
165 | * |
||
166 | */ |
||
167 | protected function getGluedString(array $arr, bool $is_assoc = false): string |
||
168 | { |
||
169 | |||
170 | //array consist of one element |
||
171 | if (count($arr) == 1) |
||
172 | return "'" . strval(array_shift($arr)) . "'"; |
||
173 | |||
174 | else { |
||
175 | |||
176 | $str = ''; |
||
177 | if (!$is_assoc) { |
||
178 | foreach ($arr as $item) { |
||
179 | if (strlen($item) > 0) |
||
180 | $str .= "'$item', "; |
||
181 | } |
||
182 | |||
183 | } else { |
||
184 | foreach ($arr as $index => $item) { |
||
185 | if (strlen($item) > 0) |
||
186 | $str .= "'$index' => '$item',"; |
||
187 | } |
||
188 | } |
||
189 | |||
190 | return "[ " . rtrim($str, ', ') . "]"; |
||
191 | } |
||
192 | } |
||
193 | |||
194 | /** |
||
195 | * @param string $table |
||
196 | * |
||
197 | * @return string|null |
||
198 | */ |
||
199 | protected function generateKeys(string $table): ?string |
||
200 | { |
||
201 | $index = $this->db->getIndexData($table); |
||
202 | |||
203 | $keys = []; |
||
204 | $keys['primary'] = ''; |
||
205 | $keys['foreign'] = ''; |
||
206 | $keys['unique'] = ''; |
||
207 | |||
208 | foreach ($index as $key) { |
||
209 | switch ($key->type) { |
||
210 | case 'PRIMARY' : |
||
211 | { |
||
212 | $keys['primary'] = "\n\t\t\$this->forge->addPrimaryKey(" . |
||
213 | $this->getGluedString($key->fields) . ");"; |
||
214 | break; |
||
215 | } |
||
216 | case 'UNIQUE' : |
||
217 | { |
||
218 | $keys['unique'] .= "\n\t\t\$this->forge->addUniqueKey(" . |
||
219 | $this->getGluedString($key->fields) . ");"; |
||
220 | break; |
||
221 | } |
||
222 | default : |
||
223 | { |
||
224 | $keys['foreign'] .= "\n\t\t\$this->forge->addKey(" . |
||
225 | $this->getGluedString($key->fields) . ");"; |
||
226 | break; |
||
227 | } |
||
228 | } |
||
229 | } |
||
230 | return implode("\n", $keys); |
||
231 | } |
||
232 | |||
233 | /** |
||
234 | * @param string $table |
||
235 | * @return string|null |
||
236 | */ |
||
237 | protected function generateForeignKeys(string $table): ?string |
||
238 | { |
||
239 | $keys = $this->db->getForeignKeyData($table); |
||
240 | $keyArray = []; |
||
241 | foreach ($keys as $key) |
||
242 | array_push($keyArray, "\n\t\t\$this->forge->addForeignKey('$key->column_name','$key->foreign_table_name','$key->foreign_column_name','CASCADE','CASCADE');"); |
||
243 | |||
244 | return implode('', array_unique($keyArray)); |
||
245 | } |
||
246 | |||
247 | /** |
||
248 | * @param string $table |
||
249 | * @return bool|null |
||
250 | */ |
||
251 | public function checkTableExist(string $table): ?bool |
||
252 | { |
||
253 | if (!$this->db->tableExists($table)) { |
||
254 | CLI::error(lang('Recharge.TableNotExists')); |
||
255 | exit(1); |
||
256 | } |
||
257 | |||
258 | return true; |
||
259 | } |
||
260 | |||
261 | /** |
||
262 | * @param string $table |
||
263 | * @return string|null |
||
264 | */ |
||
265 | public function generateRowArray(string $table): ?string |
||
266 | { |
||
267 | $result = $this->db->table($table)->get()->getResult(); |
||
268 | $container = ""; |
||
269 | foreach ($result as $row) { |
||
270 | $temp = "\n\t\t\t["; |
||
271 | foreach ($row as $index => $value) { |
||
272 | $temp .= "'$index' => '" . addslashes($value) . "', "; |
||
273 | } |
||
274 | $temp .= "],"; |
||
275 | $container .= $temp; |
||
276 | } |
||
277 | |||
278 | return $container; |
||
279 | } |
||
280 | |||
281 | /** |
||
282 | * @param string $table |
||
283 | * @return array |
||
284 | */ |
||
285 | public function getEntityProperties(string $table): array |
||
286 | { |
||
287 | $attributes = []; |
||
288 | $dates = []; |
||
289 | $casts = []; |
||
290 | |||
291 | $fields = $this->db->getFieldData($table); |
||
292 | |||
293 | foreach ($fields as $field) { |
||
294 | $attributes[] = $field->name; |
||
295 | |||
296 | //property dates |
||
297 | if ($field->type == 'datetime') { |
||
298 | $dates[] = $field->name; |
||
299 | $casts[$field->name] = (($field->nullable) ? "?" : '') . "datetime"; |
||
300 | } |
||
301 | |||
302 | //property cast |
||
303 | if ($field->type == 'tinyint') |
||
304 | $casts[$field->name] = (($field->nullable) ? "?" : '') . "boolean"; |
||
305 | |||
306 | } |
||
307 | |||
308 | return [ |
||
309 | 'attributes' => str_replace(['[', ']'], '', $this->getGluedString($attributes)), |
||
310 | 'dates' => str_replace(['[', ']'], '', $this->getGluedString($dates)), |
||
311 | 'casts' => str_replace(['[', ']'], '', $this->getGluedString($casts, true)), |
||
312 | ]; |
||
313 | } |
||
314 | |||
315 | /** |
||
316 | * @param string $table |
||
317 | * @return array |
||
318 | */ |
||
319 | public function getModelProperties(string $table): array |
||
346 | ]; |
||
347 | |||
348 | } |
||
349 | |||
350 | /** |
||
351 | * Takes the information from getFieldData() and creates the basic |
||
352 | * validation rules for those fields. |
||
353 | * |
||
354 | * @param array $fields |
||
355 | * |
||
356 | * @return mixed|string |
||
357 | */ |
||
358 | public function validationRules(array $fields) |
||
419 | } |
||
420 | } |
||
421 |
In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.