Total Complexity | 53 |
Total Lines | 373 |
Duplicated Lines | 0 % |
Changes | 1 | ||
Bugs | 0 | Features | 0 |
Complex classes like Updater 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 Updater, and based on these observations, apply Extract Interface, too.
1 | <?php /** @noinspection PhpUnnecessaryCurlyVarSyntaxInspection */ |
||
16 | class Updater { |
||
17 | |||
18 | protected $update_tables = []; |
||
19 | |||
20 | /** |
||
21 | * @var classConfig $config |
||
22 | */ |
||
23 | protected $config; |
||
24 | /** |
||
25 | * @var db_mysql $db |
||
26 | */ |
||
27 | protected $db; |
||
28 | |||
29 | protected $upd_log = ''; |
||
30 | |||
31 | public $new_version = 0; |
||
32 | protected $old_server_status; |
||
33 | |||
34 | // Does updater terminate successfully |
||
35 | public $successTermination = false; |
||
36 | |||
37 | public function __construct() { |
||
38 | $this->config = SN::$gc->config; |
||
39 | $this->db = SN::$gc->db; |
||
40 | |||
41 | $this->new_version = floatval($this->config->db_version); |
||
42 | |||
43 | // Closing any transaction that can be opened to this moment |
||
44 | $this->upd_do_query('ROLLBACK;', true); |
||
45 | |||
46 | $this->config->reset(); |
||
47 | $this->config->db_loadAll(); |
||
48 | |||
49 | $this->config->db_prefix = $this->db->db_prefix; // Left for compatibility reasons. Deprecated |
||
50 | $this->config->cache_prefix = SN::$cache_prefix; |
||
51 | |||
52 | $this->config->debug = 0; |
||
53 | |||
54 | $this->checkVersionSupport(); |
||
55 | |||
56 | ini_set('memory_limit', '1G'); |
||
57 | set_time_limit($this->config->upd_lock_time + 10); |
||
58 | $this->upd_do_query('SET FOREIGN_KEY_CHECKS=0;', true); |
||
59 | |||
60 | $this->upd_log_message('Update started. Disabling server'); |
||
61 | $this->old_server_status = $this->config->pass()->game_disable; |
||
62 | $this->config->db_saveItem('game_disable', GAME_DISABLE_UPDATE); |
||
63 | $this->upd_log_message('Server disabled.'); |
||
64 | |||
65 | $this->upd_log_message('Now looking DB for upgrades...'); |
||
66 | } |
||
67 | |||
68 | public function __destruct() { |
||
69 | if ($this->successTermination) { |
||
70 | $this->upd_log_message('Upgrade complete.'); |
||
71 | } else { |
||
72 | $this->upd_log_message('Upgrade was aborted! DB can be in invalid state!'); |
||
73 | } |
||
74 | |||
75 | $this->upd_do_query('SET FOREIGN_KEY_CHECKS=1;', true); |
||
76 | |||
77 | SN::$cache->unset_by_prefix('lng_'); |
||
78 | |||
79 | if ($this->new_version) { |
||
80 | $this->config->pass()->db_version = $this->new_version; |
||
81 | $this->upd_log_message("<span style='color: green;'>DB version is now {$this->new_version}</span>"); |
||
82 | } else { |
||
83 | $this->upd_log_message("DB version didn't changed from {$this->config->db_version}"); |
||
84 | } |
||
85 | |||
86 | $this->config->db_loadAll(); |
||
87 | /* |
||
88 | if($user['authlevel'] >= 3) { |
||
89 | print(str_replace("\r\n", '<br>', $upd_log)); |
||
90 | } |
||
91 | */ |
||
92 | $this->db->schema()->clear(); |
||
93 | |||
94 | $this->upd_log_message('Restoring server status'); |
||
95 | $this->config->pass()->game_disable = $this->old_server_status; |
||
96 | } |
||
97 | |||
98 | public function upd_log_message($message) { |
||
99 | global $sys_log_disabled, $debug; |
||
100 | |||
101 | if (!$sys_log_disabled) { |
||
102 | $this->upd_log .= "{$message}\r\n"; |
||
103 | $debug->warning($message, 'Database Update', 103); |
||
104 | } |
||
105 | } |
||
106 | |||
107 | public function upd_log_version_update() { |
||
108 | $this->upd_add_more_time(); |
||
109 | $this->upd_log_message("Detected outdated version {$this->new_version}. Upgrading..."); |
||
110 | } |
||
111 | |||
112 | public function upd_check_key($key, $default_value, $condition = false) { |
||
113 | global $sys_log_disabled; |
||
114 | |||
115 | $this->config->pass()->$key; |
||
116 | if ($condition || !isset($this->config->$key)) { |
||
117 | $this->upd_add_more_time(); |
||
118 | if (!$sys_log_disabled) { |
||
119 | $this->upd_log_message("Updating config key '{$key}' with value '{$default_value}'"); |
||
120 | } |
||
121 | $this->config->pass()->$key = $default_value; |
||
122 | } else { |
||
123 | $this->config->pass()->$key = null; |
||
124 | } |
||
125 | } |
||
126 | |||
127 | |||
128 | /** |
||
129 | * @param string $table_name |
||
130 | * @param string|array $declaration |
||
131 | * @param string $tableOptions |
||
132 | * |
||
133 | * @return bool|mysqli_result |
||
134 | */ |
||
135 | public function upd_create_table($table_name, $declaration, $tableOptions = '') { |
||
136 | $result = null; |
||
137 | |||
138 | if (!$this->isTableExists($table_name)) { |
||
139 | if (is_array($declaration)) { |
||
140 | $declaration = implode(',', $declaration); |
||
141 | } |
||
142 | $declaration = trim($declaration); |
||
143 | if (substr($declaration, 0, 1) != '(') { |
||
144 | $declaration = "($declaration)"; |
||
145 | } |
||
146 | $tableOptions = trim($tableOptions); |
||
147 | if (!empty($tableOptions)) { |
||
148 | $declaration .= $tableOptions; |
||
149 | } |
||
150 | $result = $this->upd_do_query("CREATE TABLE IF NOT EXISTS `{$this->config->db_prefix}{$table_name}` {$declaration}"); |
||
151 | $error = SN::$db->db_error(); |
||
152 | if ($error) { |
||
153 | die("Creating error for table `{$table_name}`: {$error}<br />" . dump($declaration)); |
||
|
|||
154 | } |
||
155 | |||
156 | $this->db->schema()->clear(); |
||
157 | } |
||
158 | |||
159 | return $result; |
||
160 | } |
||
161 | |||
162 | /** |
||
163 | * @param string $table |
||
164 | * @param string|string[] $alters |
||
165 | * @param bool $condition |
||
166 | * |
||
167 | * @return bool|mysqli_result|null |
||
168 | */ |
||
169 | public function upd_alter_table($table, $alters, $condition = true) { |
||
170 | if (!$condition) { |
||
171 | return null; |
||
172 | } |
||
173 | |||
174 | $this->upd_add_more_time(); |
||
175 | $alters_print = is_array($alters) ? dump($alters) : $alters; |
||
176 | $this->upd_log_message("Altering table '{$table}' with alterations {$alters_print}"); |
||
177 | |||
178 | if (!is_array($alters)) { |
||
179 | $alters = array($alters); |
||
180 | } |
||
181 | |||
182 | $alters = implode(',', $alters); |
||
183 | // $alters = preg_replace('/({{(.+)}})/U', 'lvh1_$2', $alters); |
||
184 | $qry = "ALTER TABLE {$this->config->db_prefix}{$table} {$alters};"; |
||
185 | |||
186 | $result = $this->upd_do_query($qry); |
||
187 | $error = SN::$db->db_error(); |
||
188 | if ($error) { |
||
189 | die("Altering error for table `{$table}`: {$error}<br />{$alters_print}"); |
||
190 | } |
||
191 | |||
192 | $this->db->schema()->clear(); |
||
193 | |||
194 | return $result; |
||
195 | } |
||
196 | |||
197 | public function upd_drop_table($table_name) { |
||
198 | $this->db->db_sql_query("DROP TABLE IF EXISTS {$this->config->db_prefix}{$table_name};"); |
||
199 | $this->db->schema()->clear(); |
||
200 | } |
||
201 | |||
202 | /** |
||
203 | * @param $table |
||
204 | * @param $index |
||
205 | * |
||
206 | * @return bool|mysqli_result|null |
||
207 | */ |
||
208 | public function indexDropIfExists($table, $index) { |
||
209 | return $this->upd_alter_table($table, ["DROP KEY `{$index}`",], $this->isIndexExists($table, $index)); |
||
210 | } |
||
211 | |||
212 | /** |
||
213 | * @param $table |
||
214 | * @param $constraint |
||
215 | * |
||
216 | * @return bool|mysqli_result|null |
||
217 | */ |
||
218 | public function constraintDropIfExists($table, $constraint) { |
||
219 | return $this->upd_alter_table($table, ["DROP FOREIGN KEY `{$constraint}`",], $this->isConstrainExists($table, $constraint)); |
||
220 | } |
||
221 | |||
222 | /** |
||
223 | * Replace index in table |
||
224 | * |
||
225 | * @param string $table Table name |
||
226 | * @param string $index Index name |
||
227 | * @param string[] $fields Field names to make index on |
||
228 | * @param ?callable $dropForeign |
||
229 | * @param ?callable $createForeign |
||
230 | * |
||
231 | * @return void |
||
232 | */ |
||
233 | public function indexReplace($table, $index, $fields, $dropForeign = null, $createForeign = null) { |
||
234 | $this->transactionStart(); |
||
235 | $this->upd_do_query('SET FOREIGN_KEY_CHECKS=0;', true); |
||
236 | |||
237 | if (is_callable($dropForeign)) { |
||
238 | $dropForeign(); |
||
239 | } |
||
240 | |||
241 | $this->indexDropIfExists($table, $index); |
||
242 | $queryFields = implode(',', array_map(function ($value) { return "`{$value}`"; }, $fields)); |
||
243 | if ($queryFields) { |
||
244 | $this->upd_alter_table( |
||
245 | $table, |
||
246 | ["ADD KEY `{$index}` (" . $queryFields . ")"], |
||
247 | !$this->isIndexExists($table, $index) |
||
248 | ); |
||
249 | } |
||
250 | |||
251 | if (is_callable($createForeign)) { |
||
252 | $createForeign(); |
||
253 | } |
||
254 | |||
255 | $this->upd_do_query('SET FOREIGN_KEY_CHECKS=1;', true); |
||
256 | $this->transactionCommit(); |
||
257 | } |
||
258 | |||
259 | public function upd_add_more_time($time = 0) { |
||
260 | global $sys_log_disabled; |
||
261 | |||
262 | $time = $time ?: $this->config->upd_lock_time; |
||
263 | if (!$sys_log_disabled) { |
||
264 | $this->config->pass()->var_db_update_end = SN_TIME_NOW + $time; |
||
265 | } |
||
266 | set_time_limit($time); |
||
267 | } |
||
268 | |||
269 | /** |
||
270 | * @param int $id |
||
271 | * |
||
272 | * @return bool |
||
273 | */ |
||
274 | public function updPatchExists($id) { |
||
275 | $q = $this->upd_do_query("SELECT 1 FROM `{{server_patches}}` WHERE `id` = " . intval($id), true); |
||
276 | |||
277 | return !empty(db_fetch($q)); |
||
278 | } |
||
279 | |||
280 | /** |
||
281 | * @param int $id |
||
282 | */ |
||
283 | public function updPatchRegister($id) { |
||
284 | $this->upd_do_query("INSERT INTO `{{server_patches}}` SET `id` = " . intval($id)); |
||
285 | } |
||
286 | |||
287 | /** |
||
288 | * @param int $patchId |
||
289 | * @param callable $callable |
||
290 | * @param bool $preCheck - [PATCH_REGISTER|PATCH_PRE_CHECK] |
||
291 | */ |
||
292 | public function updPatchApply($patchId, $callable, $preCheck = PATCH_REGISTER) { |
||
293 | if (!$this->updPatchExists($patchId)) { |
||
294 | $callable(); |
||
295 | |||
296 | if ($preCheck == PATCH_REGISTER) { |
||
297 | $this->updPatchRegister($patchId); |
||
298 | } |
||
299 | } |
||
300 | } |
||
301 | |||
302 | /** |
||
303 | * @param string $query |
||
304 | * @param bool $no_log |
||
305 | * |
||
306 | * @return bool|mysqli_result |
||
307 | */ |
||
308 | public function upd_do_query($query, $no_log = false) { |
||
309 | $this->upd_add_more_time(); |
||
310 | |||
311 | if (!$no_log) { |
||
312 | $this->upd_log_message("Performing query '{$query}'"); |
||
313 | } |
||
314 | |||
315 | if (strpos($query, '{{') !== false) { |
||
316 | foreach ($this->db->schema()->getSnTables() as $tableName => $cork) { |
||
317 | $query = str_replace("{{{$tableName}}}", $this->db->db_prefix . $tableName, $query); |
||
318 | } |
||
319 | } |
||
320 | $result = $this->db->db_sql_query($query) or die('Query error for ' . $query . ': ' . SN::$db->db_error()); |
||
321 | |||
322 | return $result; |
||
323 | } |
||
324 | |||
325 | protected function checkVersionSupport() { |
||
326 | if ($this->config->db_version < DB_VERSION_MIN) { |
||
327 | // print("This version does not supports upgrades from SN below v{$minVersion}. Please, use SN v42 to upgrade old database.<br /> |
||
328 | //Эта версия игры не поддерживает обновление движка версий ниже v{$minVersion}. Пожалуйста, используйте SN v42 для апгрейда со старых версий игры.<br />"); |
||
329 | die( |
||
330 | 'Internal error! Updater detects DB version LESSER then can be handled!<br /> |
||
331 | Possible you have VERY out-of-date SuperNova version<br /> |
||
332 | Use first SuperNova version not greater then ' . DB_VERSION_MIN . ' to make preliminary upgrade and then use newest version again<br /> |
||
333 | List of available releases <a href="https://github.com/supernova-ws/SuperNova/releases">GIT repository</a>' |
||
334 | ); |
||
335 | } elseif ($this->config->db_version > DB_VERSION) { |
||
336 | $this->config->pass()->var_db_update_end = SN_TIME_NOW; |
||
337 | die( |
||
338 | 'Internal error! Updater detects DB version greater then can be handled!<br /> |
||
339 | Possible you have out-of-date SuperNova version<br /> |
||
340 | Please upgrade your server from <a href="https://github.com/supernova-ws/SuperNova">GIT repository</a>' |
||
341 | ); |
||
342 | } |
||
343 | } |
||
344 | |||
345 | /** |
||
346 | * @param $table |
||
347 | * @param $field |
||
348 | * |
||
349 | * @return DbFieldDescription |
||
350 | */ |
||
351 | public function getFieldDescription($table, $field) { |
||
352 | return $this->db->schema()->getTableSchema($table)->fields[$field]; |
||
353 | } |
||
354 | |||
355 | /** |
||
356 | * @param $table |
||
357 | * @param $index |
||
358 | * |
||
359 | * @return DbIndexDescription |
||
360 | */ |
||
361 | public function getIndexDescription($table, $index) { |
||
362 | return $this->db->schema()->getTableSchema($table)->indexes[$index]; |
||
363 | } |
||
364 | |||
365 | public function isTableExists($table) { |
||
366 | return $this->db->schema()->isSnTableExists($table); |
||
367 | } |
||
368 | |||
369 | public function isFieldExists($table, $field) { |
||
370 | return $this->db->schema()->isFieldExists($table, $field); |
||
371 | } |
||
372 | |||
373 | public function isIndexExists($table, $index) { |
||
374 | return $this->db->schema()->isIndexExists($table, $index); |
||
375 | } |
||
376 | |||
377 | public function isConstrainExists($table, $index) { |
||
379 | } |
||
380 | |||
381 | public function transactionStart() { |
||
382 | // $this->upd_do_query('START TRANSACTION;', true); |
||
383 | $this->db->transactionStart(); |
||
384 | } |
||
385 | |||
386 | public function transactionCommit() { |
||
387 | // $this->upd_do_query('COMMIT;', true); |
||
388 | $this->db->transactionCommit(); |
||
389 | } |
||
390 | |||
391 | } |
||
392 |
In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.