1 | <?php |
||||
2 | /** @noinspection PhpDeprecationInspection */ |
||||
3 | /** @noinspection SqlResolve */ |
||||
4 | |||||
5 | /** @noinspection PhpUnnecessaryCurlyVarSyntaxInspection */ |
||||
6 | |||||
7 | use DBAL\db_mysql; |
||||
8 | use Player\userOptions; |
||||
9 | use Common\Vector; |
||||
10 | use Core\GlobalContainer; |
||||
11 | use Unit\DBStaticUnit; |
||||
12 | |||||
13 | /** |
||||
14 | * Class SN |
||||
15 | * |
||||
16 | * Singleton |
||||
17 | */ |
||||
18 | class SN { |
||||
19 | /** |
||||
20 | * Flag that something was rendered |
||||
21 | * |
||||
22 | * @var bool |
||||
23 | */ |
||||
24 | public static $gSomethingWasRendered = false; |
||||
25 | |||||
26 | /** |
||||
27 | * @var GlobalContainer $gc |
||||
28 | */ |
||||
29 | public static $gc; |
||||
30 | |||||
31 | /** |
||||
32 | * Основная БД для доступа к данным |
||||
33 | * |
||||
34 | * @var db_mysql $db |
||||
35 | */ |
||||
36 | public static $db; |
||||
37 | public static $db_name = ''; |
||||
38 | |||||
39 | /** |
||||
40 | * Настройки из файла конфигурации |
||||
41 | * |
||||
42 | * @var string |
||||
43 | */ |
||||
44 | public static $cache_prefix = 'sn_'; |
||||
45 | public static $sn_secret_word = ''; |
||||
46 | |||||
47 | /** |
||||
48 | * Конфигурация игры |
||||
49 | * |
||||
50 | * @var classConfig $config |
||||
51 | */ |
||||
52 | public static $config; |
||||
53 | |||||
54 | |||||
55 | /** |
||||
56 | * Кэш игры |
||||
57 | * |
||||
58 | * @var classCache $cache |
||||
59 | */ |
||||
60 | public static $cache; |
||||
61 | |||||
62 | /** |
||||
63 | * @var classLocale $lang |
||||
64 | */ |
||||
65 | public static $lang; |
||||
66 | |||||
67 | |||||
68 | /** |
||||
69 | * @var core_auth $auth |
||||
70 | */ |
||||
71 | public static $auth = null; |
||||
72 | |||||
73 | |||||
74 | public static $user = array(); |
||||
75 | /** |
||||
76 | * @var userOptions |
||||
77 | */ |
||||
78 | public static $user_options; |
||||
79 | |||||
80 | /** @var ?debug $debug */ |
||||
81 | public static $debug = null; |
||||
82 | |||||
83 | |||||
84 | public static $options = array(); |
||||
85 | |||||
86 | /** |
||||
87 | * Is header already rendered? |
||||
88 | * |
||||
89 | * @var bool $headerRendered |
||||
90 | */ |
||||
91 | public static $headerRendered = false; |
||||
92 | |||||
93 | /** @var bool $sys_user_logged_in Is user logged in? TODO - move to user-related */ |
||||
94 | public static $sys_user_logged_in = false; |
||||
95 | |||||
96 | /* |
||||
97 | TODO Кэш: |
||||
98 | 1. Всегда дешевле использовать процессор, чем локальную память |
||||
99 | 2. Всегда дешевле использовать локальную память, чем общую память всех процессов |
||||
100 | 3. Всегда дешевле использовать общую память всех процессов, чем обращаться к БД |
||||
101 | |||||
102 | Кэш - многоуровневый: локальная память-общая память-БД |
||||
103 | БД может быть сверх-кэширующей - см. HyperNova. Это реализуется на уровне СН-драйвера БД |
||||
104 | Предусмотреть вариант, когда уровни кэширования совпадают, например когда нет xCache и используется общая память |
||||
105 | */ |
||||
106 | //public static $cache; // Кэширующий объект - либо встроенная память, либо кэш в памяти с блокировками - находится внутри $db!!!! |
||||
107 | //public static $db; // Объект-БД - либо кэширующий объект с блокировками, либо БД |
||||
108 | |||||
109 | // protected static $info = array(); // Кэш информации - инфо о юнитах, инфо о группах итд |
||||
110 | |||||
111 | // TODO Автоматически заполнять эту таблицу. В случае кэша в памяти - делать show table при обращении к таблице |
||||
112 | public static $location_info = array( |
||||
113 | LOC_USER => array( |
||||
114 | P_TABLE_NAME => 'users', |
||||
115 | P_ID => 'id', |
||||
116 | P_OWNER_INFO => array(), |
||||
117 | ), |
||||
118 | |||||
119 | LOC_PLANET => array( |
||||
120 | P_TABLE_NAME => 'planets', |
||||
121 | P_ID => 'id', |
||||
122 | P_OWNER_INFO => array( |
||||
123 | LOC_USER => array( |
||||
124 | P_LOCATION => LOC_USER, |
||||
125 | P_OWNER_FIELD => 'id_owner', |
||||
126 | ), |
||||
127 | ), |
||||
128 | ), |
||||
129 | |||||
130 | LOC_UNIT => array( |
||||
131 | P_TABLE_NAME => 'unit', |
||||
132 | P_ID => 'unit_id', |
||||
133 | P_OWNER_INFO => array( |
||||
134 | LOC_USER => array( |
||||
135 | P_LOCATION => LOC_USER, |
||||
136 | P_OWNER_FIELD => 'unit_player_id', |
||||
137 | ), |
||||
138 | ), |
||||
139 | ), |
||||
140 | |||||
141 | LOC_QUE => array( |
||||
142 | P_TABLE_NAME => 'que', |
||||
143 | P_ID => 'que_id', |
||||
144 | P_OWNER_INFO => array( |
||||
145 | array( |
||||
146 | P_LOCATION => LOC_USER, |
||||
147 | P_OWNER_FIELD => 'que_player_id', |
||||
148 | ), |
||||
149 | |||||
150 | array( |
||||
151 | P_LOCATION => LOC_PLANET, |
||||
152 | P_OWNER_FIELD => 'que_planet_id_origin', |
||||
153 | ), |
||||
154 | |||||
155 | array( |
||||
156 | P_LOCATION => LOC_PLANET, |
||||
157 | P_OWNER_FIELD => 'que_planet_id', |
||||
158 | ), |
||||
159 | ), |
||||
160 | ), |
||||
161 | |||||
162 | LOC_FLEET => array( |
||||
163 | P_TABLE_NAME => 'fleets', |
||||
164 | P_ID => 'fleet_id', |
||||
165 | P_OWNER_INFO => array( |
||||
166 | array( |
||||
167 | P_LOCATION => LOC_USER, |
||||
168 | P_OWNER_FIELD => 'fleet_owner', |
||||
169 | ), |
||||
170 | |||||
171 | array( |
||||
172 | P_LOCATION => LOC_USER, |
||||
173 | P_OWNER_FIELD => 'fleet_target_owner', |
||||
174 | ), |
||||
175 | |||||
176 | array( |
||||
177 | P_LOCATION => LOC_PLANET, |
||||
178 | P_OWNER_FIELD => 'fleet_start_planet_id', |
||||
179 | ), |
||||
180 | |||||
181 | array( |
||||
182 | P_LOCATION => LOC_PLANET, |
||||
183 | P_OWNER_FIELD => 'fleet_end_planet_id', |
||||
184 | ), |
||||
185 | ), |
||||
186 | ), |
||||
187 | ); |
||||
188 | |||||
189 | /** |
||||
190 | * @var callable[] $afterInit |
||||
191 | */ |
||||
192 | public static $afterInit = []; |
||||
193 | |||||
194 | public function __construct() { |
||||
195 | |||||
196 | } |
||||
197 | |||||
198 | |||||
199 | public static function log_file($message, $spaces = 0) { |
||||
200 | if (self::$debug) { |
||||
201 | self::$debug->log_file($message, $spaces); |
||||
202 | } |
||||
203 | } |
||||
204 | |||||
205 | |||||
206 | /** |
||||
207 | * Возвращает информацию о записи по её ID |
||||
208 | * |
||||
209 | * @param int $location_type |
||||
210 | * @param int|array $record_id_unsafe |
||||
211 | * <p>int - ID записи</p> |
||||
212 | * <p>array - запись пользователя с установленным полем P_ID</p> |
||||
213 | * |
||||
214 | * @return array|false |
||||
215 | * <p>false - Нет записи с указанным ID</p> |
||||
216 | * <p>array - запись</p> |
||||
217 | */ |
||||
218 | public static function db_get_record_by_id($location_type, $record_id_unsafe) { |
||||
219 | $id_field = static::$location_info[$location_type][P_ID]; |
||||
220 | $record_id_safe = idval(is_array($record_id_unsafe) && isset($record_id_unsafe[$id_field]) ? $record_id_unsafe[$id_field] : $record_id_unsafe); |
||||
221 | |||||
222 | return static::db_get_record_list($location_type, "`{$id_field}` = {$record_id_safe}", true); |
||||
223 | } |
||||
224 | |||||
225 | public static function db_get_record_list($location_type, $filter = '', $fetch = false, $no_return = false) { |
||||
226 | $location_info = &static::$location_info[$location_type]; |
||||
227 | $id_field = $location_info[P_ID]; |
||||
228 | $tableName = $location_info[P_TABLE_NAME]; |
||||
229 | |||||
230 | $result = false; |
||||
231 | |||||
232 | // $sqlResult = static::db_query_select( |
||||
233 | // "SELECT * FROM {{{$tableName}}}" . (($filter = trim($filter)) ? " WHERE {$filter}" : '') |
||||
234 | // ); |
||||
235 | $query = "SELECT * FROM {{{$tableName}}}" . (($filter = trim($filter)) ? " WHERE {$filter}" : ''); |
||||
236 | $query .= db_mysql::db_transaction_check(db_mysql::DB_TRANSACTION_WHATEVER) ? ' FOR UPDATE' : ''; |
||||
237 | |||||
238 | $sqlResult = self::$db->doquery($query, false); |
||||
239 | |||||
240 | while ($row = db_fetch($sqlResult)) { |
||||
0 ignored issues
–
show
Deprecated Code
introduced
by
![]() |
|||||
241 | $result[$row[$id_field]] = $row; |
||||
242 | if ($fetch) { |
||||
243 | break; |
||||
244 | } |
||||
245 | } |
||||
246 | |||||
247 | if ($no_return) { |
||||
248 | return true; |
||||
249 | } else { |
||||
250 | return $fetch ? (is_array($result) ? reset($result) : false) : $result; |
||||
251 | } |
||||
252 | } |
||||
253 | |||||
254 | public static function db_upd_record_by_id($location_type, $record_id, $set) { |
||||
255 | if (!($record_id = idval($record_id)) || !($set = trim($set))) { |
||||
256 | return false; |
||||
257 | } |
||||
258 | |||||
259 | $location_info = &static::$location_info[$location_type]; |
||||
260 | $id_field = $location_info[P_ID]; |
||||
261 | $table_name = $location_info[P_TABLE_NAME]; |
||||
262 | if ($result = self::$db->doquery("UPDATE {{{$table_name}}} SET {$set} WHERE `{$id_field}` = {$record_id}", false)) // TODO Как-то вернуть может быть LIMIT 1 ? |
||||
263 | { |
||||
264 | if (static::$db->db_affected_rows()) { |
||||
265 | // Обновляем данные только если ряд был затронут |
||||
266 | DBStaticUnit::cache_clear(); |
||||
267 | } |
||||
268 | } |
||||
269 | |||||
270 | return $result; |
||||
271 | } |
||||
272 | |||||
273 | public static function db_upd_record_list($location_type, $condition, $set) { |
||||
274 | if (!($set = trim($set))) { |
||||
275 | return false; |
||||
276 | } |
||||
277 | |||||
278 | $condition = trim($condition); |
||||
279 | $table_name = static::$location_info[$location_type][P_TABLE_NAME]; |
||||
280 | |||||
281 | if ($result = self::$db->doquery("UPDATE {{{$table_name}}} SET " . $set . ($condition ? ' WHERE ' . $condition : ''))) { |
||||
282 | |||||
283 | if (static::$db->db_affected_rows()) { // Обновляем данные только если ряд был затронут |
||||
284 | // Поскольку нам неизвестно, что и как обновилось - сбрасываем кэш этого типа полностью |
||||
285 | DBStaticUnit::cache_clear(); |
||||
286 | } |
||||
287 | } |
||||
288 | |||||
289 | return $result; |
||||
290 | } |
||||
291 | |||||
292 | public static function db_ins_record($location_type, $set) { |
||||
293 | $set = trim($set); |
||||
294 | $table_name = static::$location_info[$location_type][P_TABLE_NAME]; |
||||
295 | if ($result = self::$db->doquery("INSERT INTO `{{{$table_name}}}` SET {$set}")) { |
||||
296 | if (static::$db->db_affected_rows()) // Обновляем данные только если ряд был затронут |
||||
297 | { |
||||
298 | $record_id = SN::$db->db_insert_id(); |
||||
299 | // Вытаскиваем запись целиком, потому что в $set могли быть "данные по умолчанию" |
||||
300 | $result = static::db_get_record_by_id($location_type, $record_id); |
||||
0 ignored issues
–
show
It seems like
$record_id can also be of type string ; however, parameter $record_id_unsafe of SN::db_get_record_by_id() does only seem to accept array|integer , 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
![]() |
|||||
301 | // Очищаем второстепенные кэши - потому что вставленная запись могла повлиять на результаты запросов или локация или еще чего |
||||
302 | DBStaticUnit::cache_clear(); |
||||
303 | } |
||||
304 | } |
||||
305 | |||||
306 | return $result; |
||||
307 | } |
||||
308 | |||||
309 | public static function db_del_record_by_id($location_type, $safe_record_id) { |
||||
310 | if (!($safe_record_id = idval($safe_record_id))) { |
||||
311 | return false; |
||||
312 | } |
||||
313 | |||||
314 | $location_info = &static::$location_info[$location_type]; |
||||
315 | $id_field = $location_info[P_ID]; |
||||
316 | $table_name = $location_info[P_TABLE_NAME]; |
||||
317 | if ($result = self::$db->doquery("DELETE FROM `{{{$table_name}}}` WHERE `{$id_field}` = {$safe_record_id}")) { |
||||
318 | if (static::$db->db_affected_rows()) // Обновляем данные только если ряд был затронут |
||||
319 | { |
||||
320 | DBStaticUnit::cache_clear(); |
||||
321 | } |
||||
322 | } |
||||
323 | |||||
324 | return $result; |
||||
325 | } |
||||
326 | |||||
327 | public static function db_del_record_list($location_type, $condition) { |
||||
328 | if (!($condition = trim($condition))) { |
||||
329 | return false; |
||||
330 | } |
||||
331 | |||||
332 | $table_name = static::$location_info[$location_type][P_TABLE_NAME]; |
||||
333 | |||||
334 | if ($result = self::$db->doquery("DELETE FROM `{{{$table_name}}}` WHERE {$condition}")) { |
||||
335 | if (static::$db->db_affected_rows()) // Обновляем данные только если ряд был затронут |
||||
336 | { |
||||
337 | // Обнуление кэша, потому что непонятно, что поменялось |
||||
338 | DBStaticUnit::cache_clear(); |
||||
339 | } |
||||
340 | } |
||||
341 | |||||
342 | return $result; |
||||
343 | } |
||||
344 | |||||
345 | |||||
346 | /* |
||||
347 | * С $for_update === true эта функция должна вызываться только из транзакции! Все соответствующие записи в users и planets должны быть уже блокированы! |
||||
348 | * |
||||
349 | * $que_type |
||||
350 | * !$que_type - все очереди |
||||
351 | * QUE_XXX - конкретная очередь по планете |
||||
352 | * $user_id - ID пользователя |
||||
353 | * $planet_id |
||||
354 | * $que_type == QUE_RESEARCH - игнорируется |
||||
355 | * null - обработка очередей планет не производится |
||||
356 | * false/0 - обрабатываются очереди всех планет по $user_id |
||||
357 | * (integer) - обрабатываются локальные очереди для планеты. Нужно, например, в обработчике флотов |
||||
358 | * иначе - $que_type для указанной планеты |
||||
359 | * $for_update - true == нужно блокировать записи |
||||
360 | * |
||||
361 | * TODO Работа при !$user_id |
||||
362 | * TODO Переформатировать вывод данных, что бы можно было возвращать данные по всем планетам и юзерам в одном запросе: добавить под-массивы 'que', 'planets', 'players' |
||||
363 | * |
||||
364 | */ |
||||
365 | /** @noinspection PhpUnusedParameterInspection */ |
||||
366 | public static function db_que_list_by_type_location($user_id, $planet_id = null, $que_type = false, $for_update = false) { |
||||
367 | if (!$user_id) { |
||||
368 | pdump(debug_backtrace()); |
||||
369 | die('No user_id for que_get_que()'); |
||||
0 ignored issues
–
show
|
|||||
370 | } |
||||
371 | |||||
372 | $ques = array(); |
||||
373 | |||||
374 | $query = array(); |
||||
375 | |||||
376 | if ($user_id = idval($user_id)) { |
||||
377 | $query[] = "`que_player_id` = {$user_id}"; |
||||
378 | } |
||||
379 | |||||
380 | if ($que_type == QUE_RESEARCH || $planet_id === null) { |
||||
381 | $query[] = "`que_planet_id` IS NULL"; |
||||
382 | } elseif ($planet_id) { |
||||
383 | $query[] = "(`que_planet_id` = {$planet_id}" . ($que_type ? '' : ' OR que_planet_id IS NULL') . ")"; |
||||
384 | } |
||||
385 | if ($que_type) { |
||||
386 | $query[] = "`que_type` = {$que_type}"; |
||||
387 | } |
||||
388 | |||||
389 | $ques['items'] = static::db_get_record_list(LOC_QUE, implode(' AND ', $query)); |
||||
390 | |||||
391 | return que_recalculate($ques); |
||||
392 | } |
||||
393 | |||||
394 | |||||
395 | public static function loadFileSettings() { |
||||
396 | $dbsettings = array(); |
||||
397 | |||||
398 | require(SN_CONFIG_PATH); |
||||
399 | //self::$db_prefix = $dbsettings['prefix']; |
||||
400 | self::$cache_prefix = !empty($dbsettings['cache_prefix']) ? $dbsettings['cache_prefix'] : $dbsettings['prefix']; |
||||
401 | self::$db_name = $dbsettings['name']; |
||||
402 | /** @noinspection SpellCheckingInspection */ |
||||
403 | self::$sn_secret_word = $dbsettings['secretword']; |
||||
404 | |||||
405 | self::services(); |
||||
406 | |||||
407 | unset($dbsettings); |
||||
408 | } |
||||
409 | |||||
410 | public static function init_global_objects() { |
||||
411 | global $sn_cache, $config, $debug; |
||||
412 | |||||
413 | $debug = self::$debug = self::$gc->debug; |
||||
414 | self::$db = self::$gc->db; |
||||
415 | self::$db->sn_db_connect(); |
||||
416 | |||||
417 | self::$user_options = new userOptions(0); |
||||
418 | |||||
419 | // Initializing global `cache` object |
||||
420 | $sn_cache = static::$cache = self::$gc->cache; |
||||
421 | $tables = SN::$db->schema()->getSnTables(); |
||||
422 | empty($tables) && die('DB error - cannot find any table. Halting...'); |
||||
0 ignored issues
–
show
|
|||||
423 | |||||
424 | // Initializing global `config` object |
||||
425 | $config = self::$config = self::$gc->config; |
||||
426 | |||||
427 | // Initializing statics |
||||
428 | Vector::_staticInit(self::$config); |
||||
429 | |||||
430 | // After init callbacks |
||||
431 | foreach (static::$afterInit as $callback) { |
||||
432 | if (is_callable($callback)) { |
||||
433 | $callback(); |
||||
434 | } |
||||
435 | } |
||||
436 | } |
||||
437 | |||||
438 | /** |
||||
439 | * @param int $newStatus |
||||
440 | * @param string $newMessage |
||||
441 | * |
||||
442 | * @return int |
||||
443 | * @noinspection PhpUnusedParameterInspection |
||||
444 | */ |
||||
445 | public static function gameDisable($newStatus = GAME_DISABLE_REASON, $newMessage = '') { |
||||
446 | /** @noinspection PhpCastIsUnnecessaryInspection */ |
||||
447 | $old_server_status = intval(self::$config->pass()->game_disable); |
||||
448 | |||||
449 | self::$config->pass()->game_disable = $newStatus; |
||||
450 | |||||
451 | return $old_server_status; |
||||
452 | } |
||||
453 | |||||
454 | // public static function gameEnable() { |
||||
455 | // self::$config->pass()->game_disable = GAME_DISABLE_NONE; |
||||
456 | // } |
||||
457 | |||||
458 | /** |
||||
459 | * Is game disabled? |
||||
460 | * |
||||
461 | * @return bool |
||||
462 | */ |
||||
463 | public static function gameIsDisabled() { |
||||
464 | return self::$config->pass()->game_disable != GAME_DISABLE_NONE; |
||||
465 | } |
||||
466 | |||||
467 | |||||
468 | /** |
||||
469 | * @return GlobalContainer |
||||
470 | */ |
||||
471 | public static function services() { |
||||
472 | if (empty(self::$gc)) { |
||||
473 | self::$gc = new GlobalContainer(array( |
||||
474 | 'cachePrefix' => self::$cache_prefix, |
||||
475 | )); |
||||
476 | } |
||||
477 | |||||
478 | return self::$gc; |
||||
479 | } |
||||
480 | |||||
481 | } |
||||
482 |