| 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.