Total Complexity | 56 |
Total Lines | 367 |
Duplicated Lines | 0 % |
Changes | 1 | ||
Bugs | 0 | Features | 0 |
Complex classes like mysql 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 mysql, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
22 | class mysql { |
||
23 | private static mysqli $connection; |
||
24 | |||
25 | /** |
||
26 | * @internal Only for BPT self usage , Don't use it in your source! |
||
27 | */ |
||
28 | public static function init (): void { |
||
29 | $host = settings::$db['host'] ?? 'localhost'; |
||
30 | $port = settings::$db['port'] ?? 3306; |
||
31 | $user = settings::$db['user'] ?? settings::$db['username'] ?? 'unknown'; |
||
32 | $pass = settings::$db['pass'] ?? settings::$db['password'] ?? 'unknown'; |
||
33 | $dbname = settings::$db['dbname']; |
||
34 | self::$connection = new mysqli($host, $user, $pass, $dbname, $port); |
||
35 | if (self::$connection->connect_errno) { |
||
36 | logger::write('SQL connection has problem : ' . self::$connection->connect_error, loggerTypes::ERROR); |
||
37 | throw new bptException('SQL_CONNECTION_PROBLEM'); |
||
38 | } |
||
39 | if (!lock::exist('BPT-MYSQL')) { |
||
40 | self::install(); |
||
41 | } |
||
42 | } |
||
43 | |||
44 | private static function install (): void { |
||
45 | self::pureQuery(" |
||
46 | CREATE TABLE `users` |
||
47 | ( |
||
48 | `id` BIGINT(20) NOT NULL, |
||
49 | `username` VARCHAR(32) NULL DEFAULT NULL, |
||
50 | `lang_code` VARCHAR(3) NULL DEFAULT NULL, |
||
51 | `first_active` INT(11) NOT NULL DEFAULT '0', |
||
52 | `last_active` INT(11) NOT NULL DEFAULT '0', |
||
53 | `referral` BIGINT(20) NULL DEFAULT NULL, |
||
54 | `blocked` BOOLEAN NOT NULL DEFAULT FALSE, |
||
55 | `step` VARCHAR(64) NOT NULL DEFAULT 'main', |
||
56 | `value` TEXT NULL DEFAULT NULL, |
||
57 | PRIMARY KEY (`id`) |
||
58 | ) ENGINE = InnoDB;"); |
||
59 | lock::set('BPT-MYSQL'); |
||
60 | } |
||
61 | |||
62 | /** |
||
63 | * @internal Only for BPT self usage , Don't use it in your source! |
||
64 | */ |
||
65 | public static function process (): void { |
||
66 | if (isset(BPT::$update->message)) { |
||
67 | self::processMessage(BPT::$update->message); |
||
|
|||
68 | } |
||
69 | elseif (isset(BPT::$update->edited_message)) { |
||
70 | self::processMessage(BPT::$update->edited_message); |
||
71 | } |
||
72 | elseif (isset(BPT::$update->callback_query)) { |
||
73 | self::processCallbackQuery(BPT::$update->callback_query); |
||
74 | } |
||
75 | elseif (isset(BPT::$update->inline_query)) { |
||
76 | self::processInlineQuery(BPT::$update->inline_query); |
||
77 | } |
||
78 | elseif (isset(BPT::$update->my_chat_member)) { |
||
79 | self::processMyChatMember(BPT::$update->my_chat_member); |
||
80 | } |
||
81 | } |
||
82 | |||
83 | private static function processMessage (message $update): void { |
||
84 | $type = $update->chat->type; |
||
85 | if ($type === chatType::PRIVATE) { |
||
86 | $user_id = $update->from->id; |
||
87 | $first_active = $last_active = time(); |
||
88 | $referral = null; |
||
89 | $username = $update->from->username; |
||
90 | $lang_code = $update->from->language_code; |
||
91 | if (isset($update->commend) && isset($update->commend_payload) && $update->commend === 'start' && str_starts_with($update->commend_payload, 'ref_')) { |
||
92 | if (tools::isShorted(substr($update->commend_payload, 4))) { |
||
93 | $referral = tools::shortDecode(substr($update->commend_payload, 4)); |
||
94 | } |
||
95 | } |
||
96 | self::query("INSERT INTO `users`(`id`, `username`, `lang_code`, `first_active`, `last_active`, `referral`) VALUES (?,?,?,?,?,?) on duplicate key update `last_active` = ?, `username` = ?", [ |
||
97 | $user_id, |
||
98 | $username, |
||
99 | $lang_code, |
||
100 | $first_active, |
||
101 | $last_active, |
||
102 | $referral, |
||
103 | $last_active, |
||
104 | $username |
||
105 | ]); |
||
106 | } |
||
107 | } |
||
108 | |||
109 | private static function processCallbackQuery (callbackQuery $update): void { |
||
110 | $type = $update->message->chat->type; |
||
111 | if ($type === chatType::PRIVATE) { |
||
112 | $user_id = $update->from->id; |
||
113 | $last_active = time(); |
||
114 | $username = $update->from->username; |
||
115 | self::update('users', ['last_active' => $last_active, 'username' => $username], ['id' => $user_id], 1); |
||
116 | } |
||
117 | } |
||
118 | |||
119 | private static function processInlineQuery (inlineQuery $update): void { |
||
120 | $type = $update->chat_type; |
||
121 | if ($type === chatType::PRIVATE || $type === chatType::SENDER) { |
||
122 | $user_id = $update->from->id; |
||
123 | $last_active = time(); |
||
124 | $username = $update->from->username; |
||
125 | self::update('users', ['last_active' => $last_active, 'username' => $username], ['id' => $user_id], 1); |
||
126 | } |
||
127 | } |
||
128 | |||
129 | private static function processMyChatMember (chatMemberUpdated $update): void { |
||
130 | $type = $update->chat->type; |
||
131 | if ($type === chatType::PRIVATE) { |
||
132 | if ($update->new_chat_member->status === chatMemberStatus::MEMBER) { |
||
133 | self::update('users', ['blocked' => false], ['id' => $update->from->id], 1); |
||
134 | } |
||
135 | else { |
||
136 | self::update('users', ['blocked' => true], ['id' => $update->from->id], 1); |
||
137 | } |
||
138 | } |
||
139 | } |
||
140 | |||
141 | /** |
||
142 | * Get real mysqli connections |
||
143 | * |
||
144 | * @return mysqli |
||
145 | */ |
||
146 | public static function getMysqli (): mysqli { |
||
147 | return self::$connection; |
||
148 | } |
||
149 | |||
150 | /** |
||
151 | * Get affected rows |
||
152 | * |
||
153 | * @return int|string |
||
154 | */ |
||
155 | public static function affected_rows (): int|string { |
||
157 | } |
||
158 | |||
159 | /** |
||
160 | * Get inserted id |
||
161 | * |
||
162 | * @return int|string |
||
163 | */ |
||
164 | public static function insert_id (): int|string { |
||
165 | return self::$connection->insert_id; |
||
166 | } |
||
167 | |||
168 | /** |
||
169 | * Escape string with real_escape_string of mysqli class |
||
170 | * |
||
171 | * @param string $text |
||
172 | * |
||
173 | * @return string |
||
174 | */ |
||
175 | public static function escapeString (string $text): string { |
||
176 | return self::$connection->real_escape_string($text); |
||
177 | } |
||
178 | |||
179 | /** |
||
180 | * Run query as what is it |
||
181 | * |
||
182 | * The library doesnt do anything on it |
||
183 | * |
||
184 | * It's like calling mysqli->query(); |
||
185 | * |
||
186 | * @param string $query |
||
187 | * |
||
188 | * @return mysqli_result|bool |
||
189 | */ |
||
190 | public static function pureQuery (string $query): mysqli_result|bool { |
||
191 | return self::$connection->query($query); |
||
192 | } |
||
193 | |||
194 | /** |
||
195 | * Run query with safe execution |
||
196 | * |
||
197 | * Replace inputs with `?` in query to be replaced safely with $vars in order |
||
198 | * |
||
199 | * e.g. : mysql::query('select * from `users` where `id` = ? limit 1',[123456789]); |
||
200 | * |
||
201 | * @param string $query |
||
202 | * @param array $vars default [] or empty |
||
203 | * @param bool $need_result set if you want result be returned, default : true |
||
204 | * |
||
205 | * @return mysqli_result|bool |
||
206 | */ |
||
207 | public static function query (string $query, array $vars = [], bool $need_result = true): mysqli_result|bool { |
||
208 | $prepare = self::$connection->prepare($query); |
||
209 | if ($prepare->execute($vars)) { |
||
210 | return $need_result ? $prepare->get_result() : true; |
||
211 | } |
||
212 | else { |
||
213 | logger::write(loggerTypes::WARNING, $prepare->error); |
||
214 | return false; |
||
215 | } |
||
216 | } |
||
217 | |||
218 | private static function makeArrayReady (string &$query, array $array, string $operator = ' AND '): array { |
||
219 | $first = true; |
||
220 | $values = []; |
||
221 | foreach ($array as $name => $value) { |
||
222 | if ($first) { |
||
223 | $first = false; |
||
224 | } |
||
225 | else { |
||
226 | $query .= $operator; |
||
227 | } |
||
228 | $query .= " `$name` = ?"; |
||
229 | $values[] = $value; |
||
230 | } |
||
231 | return $values; |
||
232 | } |
||
233 | |||
234 | private static function makeQueryReady (string &$query, array $where = null, int $count = null, int $offset = null): array { |
||
235 | $values = []; |
||
236 | if (!empty($where)) { |
||
237 | $query .= " WHERE"; |
||
238 | $values = self::makeArrayReady($query, $where); |
||
239 | } |
||
240 | if (!empty($count)) { |
||
241 | $query .= !empty($offset) ? " LIMIT $offset,$count" : " LIMIT $count"; |
||
242 | } |
||
243 | elseif (!empty($offset)) { |
||
244 | $query .= " OFFSET $offset"; |
||
245 | } |
||
246 | return $values; |
||
247 | } |
||
248 | |||
249 | /** |
||
250 | * Run delete query |
||
251 | * |
||
252 | * e.g. : `mysql::delete('users',['id'=>123456789],1);` |
||
253 | * |
||
254 | * @param string $table table name |
||
255 | * @param array|null $where Set your ifs default : null |
||
256 | * @param int|null $count Set if you want to delete specific amount of row default : null |
||
257 | * @param int|null $offset Set if you want to delete rows after specific row default : null |
||
258 | * |
||
259 | * @return mysqli_result|bool |
||
260 | */ |
||
261 | public static function delete (string $table, array $where = null, int $count = null, int $offset = null): mysqli_result|bool { |
||
265 | } |
||
266 | |||
267 | /** |
||
268 | * Run update query |
||
269 | * |
||
270 | * e.g. : mysql::update('users',['step'=>'panel'],['id'=>123456789],1); |
||
271 | * |
||
272 | * @param string $table table name |
||
273 | * @param array $modify Set the data's you want to modify |
||
274 | * @param array|null $where Set your ifs default : null |
||
275 | * @param int|null $count Set if you want to update specific amount of row default : null |
||
276 | * @param int|null $offset Set if you want to update rows after specific row default : null |
||
277 | * |
||
278 | * @return mysqli_result|bool |
||
279 | */ |
||
280 | public static function update (string $table, array $modify, array $where = null, int $count = null, int $offset = null): mysqli_result|bool { |
||
281 | $query = "UPDATE `$table` SET"; |
||
282 | $values = self::makeArrayReady($query, $modify, ', '); |
||
283 | $res = self::makeQueryReady($query, $where, $count, $offset); |
||
284 | return self::query($query, array_merge($values, $res), false); |
||
285 | } |
||
286 | |||
287 | /** |
||
288 | * Run insert query |
||
289 | * |
||
290 | * e.g. : `mysql::insert('users',['id','column1','column2','column3'],[123456789,'value1','value2','value3']);` |
||
291 | * |
||
292 | * @param string $table table name |
||
293 | * @param string|array $columns sets columns that you want to fill |
||
294 | * @param array|string $values sets value that you want to set |
||
295 | * |
||
296 | * @return mysqli_result|bool |
||
297 | */ |
||
298 | public static function insert (string $table, string|array $columns, array|string $values): mysqli_result|bool { |
||
299 | $query = "INSERT INTO `$table`("; |
||
300 | $query .= '`' . (is_string($columns) ? $columns : implode('`,`', $columns)) . '`) VALUES ('; |
||
301 | if (is_string($values)) $values = [$values]; |
||
302 | $query .= '?' . str_repeat(',?', count($values) - 1) . ')'; |
||
303 | return self::query($query, $values, false); |
||
304 | } |
||
305 | |||
306 | /** |
||
307 | * Run select query |
||
308 | * |
||
309 | * e.g. : mysql::select('users','*',['id'=>123456789],1); |
||
310 | * e.g. : mysql::select('users',['step','referrals'],['id'=>123456789],1); |
||
311 | * |
||
312 | * @param string $table table name |
||
313 | * @param array|string $columns sets column that you want to retrieve , set '*' to retrieve all , default : '*' |
||
314 | * @param array|null $where Set your ifs default : null |
||
315 | * @param int|null $count Set if you want to select specific amount of row default : null |
||
316 | * @param int|null $offset Set if you want to select rows after specific row default : null |
||
317 | * |
||
318 | * @return mysqli_result|bool |
||
319 | */ |
||
320 | public static function select (string $table, array|string $columns = '*', array $where = null, int $count = null, int $offset = null): mysqli_result|bool { |
||
331 | } |
||
332 | |||
333 | /** |
||
334 | * Same as mysql::select but return first result as array |
||
335 | * |
||
336 | * mysql::selectArray('users','*',['id'=>123456789]); |
||
337 | * |
||
338 | * @param string $table table name |
||
339 | * @param array|string $columns sets column that you want to retrieve , set '*' to retrieve all , default : '*' |
||
340 | * @param array|null $where Set your ifs default : null |
||
341 | * |
||
342 | * @return null|bool|array |
||
343 | */ |
||
344 | public static function selectArray (string $table, array|string $columns = '*', array $where = null): bool|array|null { |
||
350 | } |
||
351 | |||
352 | /** |
||
353 | * Same as mysql::select but return first result as object(stdClass) |
||
354 | * |
||
355 | * mysql::selectObject('users','*',['id'=>123456789]); |
||
356 | * |
||
357 | * @param string $table table name |
||
358 | * @param array|string $columns sets column that you want to retrieve , set '*' to retrieve all , default : '*' |
||
359 | * @param array|null $where Set your ifs default : null |
||
360 | */ |
||
361 | public static function selectObject (string $table, array|string $columns = '*', array $where = null) { |
||
367 | } |
||
368 | |||
369 | /** |
||
370 | * Same as mysql::select but return each row as generator |
||
371 | * |
||
372 | * e.g. : mysql::selectEach('users','*',['id'=>123456789],1); |
||
373 | * e.g. : mysql::selectEach('users',['id']); |
||
374 | * |
||
375 | * @param string $table table name |
||
376 | * @param array|string $columns sets column that you want to retrieve , set '*' to retrieve all , default : '*' |
||
377 | * @param array|null $where Set your ifs default : null |
||
378 | * @param int|null $count Set if you want to select specific amount of row default : null |
||
379 | * @param int|null $offset Set if you want to select rows after specific row default : null |
||
380 | * |
||
381 | * @return bool|Generator |
||
382 | */ |
||
383 | public static function selectEach (string $table, array|string $columns = '*', array $where = null, int $count = null, int $offset = null): bool|Generator { |
||
389 | } |
||
390 | } |