hafijul233 /
ci-recharge
| 1 | <?php namespace Hafiz\Libraries; |
||||
| 2 | |||||
| 3 | use CodeIgniter\CLI\CLI; |
||||
| 4 | use CodeIgniter\Database\BaseConnection; |
||||
| 5 | use Config\Database; |
||||
| 6 | use Throwable; |
||||
| 7 | |||||
| 8 | /** |
||||
| 9 | * @class DBHandler |
||||
| 10 | * Handle all db collection and table |
||||
| 11 | * column generate |
||||
| 12 | * |
||||
| 13 | * @author hafijul233 |
||||
| 14 | * |
||||
| 15 | * @package Hafiz\Libraries |
||||
| 16 | */ |
||||
| 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(); |
||||
|
0 ignored issues
–
show
|
|||||
| 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() ?? []; |
||||
|
0 ignored issues
–
show
The method
listTables() does not exist on null.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. Loading history...
|
|||||
| 65 | |||||
| 66 | if (empty($tables)) { |
||||
| 67 | CLI::error(lang('Recharge.TablesNotFound')); |
||||
| 68 | exit(1); |
||||
|
0 ignored issues
–
show
In this branch, the function will implicitly return
null which is incompatible with the type-hinted return array. Consider adding a return statement or allowing null as return value.
For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example: interface ReturnsInt {
public function returnsIntHinted(): int;
}
class MyClass implements ReturnsInt {
public function returnsIntHinted(): int
{
if (foo()) {
return 123;
}
// here: null is implicitly returned
}
}
Loading history...
|
|||||
| 69 | } |
||||
| 70 | |||||
| 71 | return $tables; |
||||
|
0 ignored issues
–
show
|
|||||
| 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(); |
||||
|
0 ignored issues
–
show
The method
getResult() does not exist on CodeIgniter\Database\Query.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. Loading history...
|
|||||
| 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); |
||||
|
0 ignored issues
–
show
|
|||||
| 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 |
||||
| 320 | { |
||||
| 321 | $primary_ids = []; |
||||
| 322 | $attributes = []; |
||||
| 323 | |||||
| 324 | $fields = $this->db->getFieldData($table); |
||||
| 325 | |||||
| 326 | foreach ($fields as $field) { |
||||
| 327 | if ($field->primary_key === 1) |
||||
| 328 | $primary_ids[] = $field->name; |
||||
| 329 | |||||
| 330 | elseif ($field->name == 'created_at' || $field->name == 'updated_at') |
||||
| 331 | continue; |
||||
| 332 | |||||
| 333 | else |
||||
| 334 | $attributes[] = $field->name; |
||||
| 335 | } |
||||
| 336 | |||||
| 337 | //Model only support single column in primary key getting the first one |
||||
| 338 | |||||
| 339 | $primary_id = (count($primary_ids) > 0) ? array_shift($primary_ids) : ''; |
||||
| 340 | $allowed_fields = array_merge($primary_ids, $attributes); |
||||
| 341 | |||||
| 342 | return [ |
||||
| 343 | 'primary_id' => $primary_id, |
||||
| 344 | 'attributes' => str_replace(['[', ']'], '', $this->getGluedString($allowed_fields)), |
||||
| 345 | 'rules' => $this->validationRules($fields), |
||||
|
0 ignored issues
–
show
It seems like
$fields can also be of type false; however, parameter $fields of Hafiz\Libraries\DBHandler::validationRules() does only seem to accept array, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 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) |
||||
| 359 | { |
||||
| 360 | if (empty($fields)) return '[]'; |
||||
| 361 | |||||
| 362 | $rules = []; |
||||
| 363 | |||||
| 364 | foreach ($fields as $field) { |
||||
| 365 | if (in_array($field->name, ['created_at', 'updated_at'])) |
||||
| 366 | continue; |
||||
| 367 | |||||
| 368 | $rule = []; |
||||
| 369 | |||||
| 370 | if ($field->nullable == false) { |
||||
| 371 | $rule[] = "required"; |
||||
| 372 | } else { |
||||
| 373 | $rule[] = "permit_empty"; |
||||
| 374 | } |
||||
| 375 | |||||
| 376 | switch ($field->type) { |
||||
| 377 | // Numeric Types |
||||
| 378 | case 'tinyint': |
||||
| 379 | case 'smallint': |
||||
| 380 | case 'mediumint': |
||||
| 381 | case 'int': |
||||
| 382 | case 'integer': |
||||
| 383 | case 'bigint': |
||||
| 384 | $rule[] = 'integer'; |
||||
| 385 | break; |
||||
| 386 | |||||
| 387 | case 'decimal': |
||||
| 388 | case 'dec': |
||||
| 389 | case 'numeric': |
||||
| 390 | case 'fixed': |
||||
| 391 | $rule[] = 'decimal'; |
||||
| 392 | break; |
||||
| 393 | |||||
| 394 | case 'float': |
||||
| 395 | case 'double': |
||||
| 396 | $rule[] = 'numeric'; |
||||
| 397 | break; |
||||
| 398 | |||||
| 399 | case 'date': |
||||
| 400 | $rule[] = 'valid_date'; |
||||
| 401 | break; |
||||
| 402 | |||||
| 403 | // Text Types |
||||
| 404 | case 'char': |
||||
| 405 | case 'varchar': |
||||
| 406 | case 'text': |
||||
| 407 | $rule[] = 'string'; |
||||
| 408 | break; |
||||
| 409 | } |
||||
| 410 | |||||
| 411 | if (!empty($field->max_length)) { |
||||
| 412 | $rule[] = "max_length[$field->max_length]"; |
||||
| 413 | } |
||||
| 414 | |||||
| 415 | $rules[$field->name] = implode('|', $rule); |
||||
| 416 | } |
||||
| 417 | |||||
| 418 | return $this->getGluedString($rules, true); |
||||
| 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.