Test Failed
Push — trunk ( 132e87...b3f953 )
by SuperNova.WS
11:54
created

SN::loadFileSettings()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 0
dl 0
loc 13
rs 10
c 0
b 0
f 0
ccs 0
cts 11
cp 0
crap 6
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
  /**
81
   * @var debug $debug
82
   */
83
  public static $debug = null;
84
85
86
  public static $options = array();
87
88
  /**
89
   * Is header already rendered?
90
   *
91
   * @var bool $headerRendered
92
   */
93
  public static $headerRendered = false;
94
95
  /** @var bool $sys_user_logged_in Is user logged in? TODO - move to user-related */
96
  public static $sys_user_logged_in = false;
97
98
  /*
99
  TODO Кэш:
100
  1. Всегда дешевле использовать процессор, чем локальную память
101
  2. Всегда дешевле использовать локальную память, чем общую память всех процессов
102
  3. Всегда дешевле использовать общую память всех процессов, чем обращаться к БД
103
104
  Кэш - многоуровневый: локальная память-общая память-БД
105
  БД может быть сверх-кэширующей - см. HyperNova. Это реализуется на уровне СН-драйвера БД
106
  Предусмотреть вариант, когда уровни кэширования совпадают, например когда нет xCache и используется общая память
107
  */
108
  //public static $cache; // Кэширующий объект - либо встроенная память, либо кэш в памяти с блокировками - находится внутри $db!!!!
109
  //public static $db; // Объект-БД - либо кэширующий объект с блокировками, либо БД
110
111
  // protected static $info = array(); // Кэш информации - инфо о юнитах, инфо о группах итд
112
113
  // TODO Автоматически заполнять эту таблицу. В случае кэша в памяти - делать show table при обращении к таблице
114
  public static $location_info = array(
115
    LOC_USER => array(
116
      P_TABLE_NAME => 'users',
117
      P_ID         => 'id',
118
      P_OWNER_INFO => array(),
119
    ),
120
121
    LOC_PLANET => array(
122
      P_TABLE_NAME => 'planets',
123
      P_ID         => 'id',
124
      P_OWNER_INFO => array(
125
        LOC_USER => array(
126
          P_LOCATION    => LOC_USER,
127
          P_OWNER_FIELD => 'id_owner',
128
        ),
129
      ),
130
    ),
131
132
    LOC_UNIT => array(
133
      P_TABLE_NAME => 'unit',
134
      P_ID         => 'unit_id',
135
      P_OWNER_INFO => array(
136
        LOC_USER => array(
137
          P_LOCATION    => LOC_USER,
138
          P_OWNER_FIELD => 'unit_player_id',
139
        ),
140
      ),
141
    ),
142
143
    LOC_QUE => array(
144
      P_TABLE_NAME => 'que',
145
      P_ID         => 'que_id',
146
      P_OWNER_INFO => array(
147
        array(
148
          P_LOCATION    => LOC_USER,
149
          P_OWNER_FIELD => 'que_player_id',
150
        ),
151
152
        array(
153
          P_LOCATION    => LOC_PLANET,
154
          P_OWNER_FIELD => 'que_planet_id_origin',
155
        ),
156
157
        array(
158
          P_LOCATION    => LOC_PLANET,
159
          P_OWNER_FIELD => 'que_planet_id',
160
        ),
161
      ),
162
    ),
163
164
    LOC_FLEET => array(
165
      P_TABLE_NAME => 'fleets',
166
      P_ID         => 'fleet_id',
167
      P_OWNER_INFO => array(
168
        array(
169
          P_LOCATION    => LOC_USER,
170
          P_OWNER_FIELD => 'fleet_owner',
171
        ),
172
173
        array(
174
          P_LOCATION    => LOC_USER,
175
          P_OWNER_FIELD => 'fleet_target_owner',
176
        ),
177
178
        array(
179
          P_LOCATION    => LOC_PLANET,
180
          P_OWNER_FIELD => 'fleet_start_planet_id',
181
        ),
182
183
        array(
184
          P_LOCATION    => LOC_PLANET,
185
          P_OWNER_FIELD => 'fleet_end_planet_id',
186
        ),
187
      ),
188
    ),
189
  );
190
191
  /**
192
   * @var callable[] $afterInit
193
   */
194
  public static $afterInit = [];
195
196
  public function __construct() {
197
198
  }
199
200
201
  public static function log_file($message, $spaces = 0) {
202
    if (self::$debug) {
203
      self::$debug->log_file($message, $spaces);
204
    }
205
  }
206
207
208
  /**
209
   * Возвращает информацию о записи по её ID
210
   *
211
   * @param int       $location_type
212
   * @param int|array $record_id_unsafe
213
   *    <p>int - ID записи</p>
214
   *    <p>array - запись пользователя с установленным полем P_ID</p>
215
   *
216
   * @return array|false
217
   *    <p>false - Нет записи с указанным ID</p>
218
   *    <p>array - запись</p>
219
   */
220
  public static function db_get_record_by_id($location_type, $record_id_unsafe) {
221
    $id_field       = static::$location_info[$location_type][P_ID];
222
    $record_id_safe = idval(is_array($record_id_unsafe) && isset($record_id_unsafe[$id_field]) ? $record_id_unsafe[$id_field] : $record_id_unsafe);
223
224
    return static::db_get_record_list($location_type, "`{$id_field}` = {$record_id_safe}", true);
225
  }
226
227
  public static function db_get_record_list($location_type, $filter = '', $fetch = false, $no_return = false) {
228
    $location_info = &static::$location_info[$location_type];
229
    $id_field      = $location_info[P_ID];
230
    $tableName     = $location_info[P_TABLE_NAME];
231
232
    $result = false;
233
234
//    $sqlResult = static::db_query_select(
235
//      "SELECT * FROM {{{$tableName}}}" . (($filter = trim($filter)) ? " WHERE {$filter}" : '')
236
//    );
237
    $query = "SELECT * FROM {{{$tableName}}}" . (($filter = trim($filter)) ? " WHERE {$filter}" : '');
238
    $query .= db_mysql::db_transaction_check(db_mysql::DB_TRANSACTION_WHATEVER) ? ' FOR UPDATE' : '';
239
240
    $sqlResult = self::$db->doquery($query, false);
241
242
    while ($row = db_fetch($sqlResult)) {
0 ignored issues
show
Deprecated Code introduced by
The function db_fetch() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

242
    while ($row = /** @scrutinizer ignore-deprecated */ db_fetch($sqlResult)) {
Loading history...
243
      $result[$row[$id_field]] = $row;
244
      if ($fetch) {
245
        break;
246
      }
247
    }
248
249
    if ($no_return) {
250
      return true;
251
    } else {
252
      return $fetch ? (is_array($result) ? reset($result) : false) : $result;
253
    }
254
  }
255
256
  public static function db_upd_record_by_id($location_type, $record_id, $set) {
257
    if (!($record_id = idval($record_id)) || !($set = trim($set))) {
258
      return false;
259
    }
260
261
    $location_info = &static::$location_info[$location_type];
262
    $id_field      = $location_info[P_ID];
263
    $table_name    = $location_info[P_TABLE_NAME];
264
    if ($result = self::$db->doquery("UPDATE {{{$table_name}}} SET {$set} WHERE `{$id_field}` = {$record_id}", false)) // TODO Как-то вернуть может быть LIMIT 1 ?
265
    {
266
      if (static::$db->db_affected_rows()) {
267
        // Обновляем данные только если ряд был затронут
268
        DBStaticUnit::cache_clear();
269
      }
270
    }
271
272
    return $result;
273
  }
274
275
  public static function db_upd_record_list($location_type, $condition, $set) {
276
    if (!($set = trim($set))) {
277
      return false;
278
    }
279
280
    $condition  = trim($condition);
281
    $table_name = static::$location_info[$location_type][P_TABLE_NAME];
282
283
    if ($result = self::$db->doquery("UPDATE {{{$table_name}}} SET " . $set . ($condition ? ' WHERE ' . $condition : ''))) {
284
285
      if (static::$db->db_affected_rows()) { // Обновляем данные только если ряд был затронут
286
        // Поскольку нам неизвестно, что и как обновилось - сбрасываем кэш этого типа полностью
287
        DBStaticUnit::cache_clear();
288
      }
289
    }
290
291
    return $result;
292
  }
293
294
  public static function db_ins_record($location_type, $set) {
295
    $set        = trim($set);
296
    $table_name = static::$location_info[$location_type][P_TABLE_NAME];
297
    if ($result = self::$db->doquery("INSERT INTO `{{{$table_name}}}` SET {$set}")) {
298
      if (static::$db->db_affected_rows()) // Обновляем данные только если ряд был затронут
299
      {
300
        $record_id = SN::$db->db_insert_id();
301
        // Вытаскиваем запись целиком, потому что в $set могли быть "данные по умолчанию"
302
        $result = static::db_get_record_by_id($location_type, $record_id);
0 ignored issues
show
Bug introduced by
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 ignore-type  annotation

302
        $result = static::db_get_record_by_id($location_type, /** @scrutinizer ignore-type */ $record_id);
Loading history...
303
        // Очищаем второстепенные кэши - потому что вставленная запись могла повлиять на результаты запросов или локация или еще чего
304
        DBStaticUnit::cache_clear();
305
      }
306
    }
307
308
    return $result;
309
  }
310
311
  public static function db_del_record_by_id($location_type, $safe_record_id) {
312
    if (!($safe_record_id = idval($safe_record_id))) {
313
      return false;
314
    }
315
316
    $location_info = &static::$location_info[$location_type];
317
    $id_field      = $location_info[P_ID];
318
    $table_name    = $location_info[P_TABLE_NAME];
319
    if ($result = self::$db->doquery("DELETE FROM `{{{$table_name}}}` WHERE `{$id_field}` = {$safe_record_id}")) {
320
      if (static::$db->db_affected_rows()) // Обновляем данные только если ряд был затронут
321
      {
322
        DBStaticUnit::cache_clear();
323
      }
324
    }
325
326
    return $result;
327
  }
328
329
  public static function db_del_record_list($location_type, $condition) {
330
    if (!($condition = trim($condition))) {
331
      return false;
332
    }
333
334
    $table_name = static::$location_info[$location_type][P_TABLE_NAME];
335
336
    if ($result = self::$db->doquery("DELETE FROM `{{{$table_name}}}` WHERE {$condition}")) {
337
      if (static::$db->db_affected_rows()) // Обновляем данные только если ряд был затронут
338
      {
339
        // Обнуление кэша, потому что непонятно, что поменялось
340
        DBStaticUnit::cache_clear();
341
      }
342
    }
343
344
    return $result;
345
  }
346
347
348
  /*
349
   * С $for_update === true эта функция должна вызываться только из транзакции! Все соответствующие записи в users и planets должны быть уже блокированы!
350
   *
351
   * $que_type
352
   *   !$que_type - все очереди
353
   *   QUE_XXX - конкретная очередь по планете
354
   * $user_id - ID пользователя
355
   * $planet_id
356
   *   $que_type == QUE_RESEARCH - игнорируется
357
   *   null - обработка очередей планет не производится
358
   *   false/0 - обрабатываются очереди всех планет по $user_id
359
   *   (integer) - обрабатываются локальные очереди для планеты. Нужно, например, в обработчике флотов
360
   *   иначе - $que_type для указанной планеты
361
   * $for_update - true == нужно блокировать записи
362
   *
363
   * TODO Работа при !$user_id
364
   * TODO Переформатировать вывод данных, что бы можно было возвращать данные по всем планетам и юзерам в одном запросе: добавить под-массивы 'que', 'planets', 'players'
365
   *
366
   */
367
  /** @noinspection PhpUnusedParameterInspection */
368
  public static function db_que_list_by_type_location($user_id, $planet_id = null, $que_type = false, $for_update = false) {
369
    if (!$user_id) {
370
      pdump(debug_backtrace());
371
      die('No user_id for que_get_que()');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
372
    }
373
374
    $ques = array();
375
376
    $query = array();
377
378
    if ($user_id = idval($user_id)) {
379
      $query[] = "`que_player_id` = {$user_id}";
380
    }
381
382
    if ($que_type == QUE_RESEARCH || $planet_id === null) {
383
      $query[] = "`que_planet_id` IS NULL";
384
    } elseif ($planet_id) {
385
      $query[] = "(`que_planet_id` = {$planet_id}" . ($que_type ? '' : ' OR que_planet_id IS NULL') . ")";
386
    }
387
    if ($que_type) {
388
      $query[] = "`que_type` = {$que_type}";
389
    }
390
391
    $ques['items'] = static::db_get_record_list(LOC_QUE, implode(' AND ', $query));
392
393
    return que_recalculate($ques);
394
  }
395
396
397
  public static function loadFileSettings() {
398
    $dbsettings = array();
399
400
    require(SN_CONFIG_PATH);
401
    //self::$db_prefix = $dbsettings['prefix'];
402
    self::$cache_prefix = !empty($dbsettings['cache_prefix']) ? $dbsettings['cache_prefix'] : $dbsettings['prefix'];
403
    self::$db_name      = $dbsettings['name'];
404
    /** @noinspection SpellCheckingInspection */
405
    self::$sn_secret_word = $dbsettings['secretword'];
406
407
    self::services();
408
409
    unset($dbsettings);
410
  }
411
412
  public static function init_global_objects() {
413
    global $sn_cache, $config, $debug;
414
415
    $debug    = self::$debug = self::$gc->debug;
416
    self::$db = self::$gc->db;
417
    self::$db->sn_db_connect();
418
419
    self::$user_options = new userOptions(0);
420
421
    // Initializing global `cache` object
422
    $sn_cache = static::$cache = self::$gc->cache;
423
    $tables   = SN::$db->schema()->getSnTables();
424
    empty($tables) && die('DB error - cannot find any table. Halting...');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
425
426
    // Initializing global `config` object
427
    $config = self::$config = self::$gc->config;
428
429
    // Initializing statics
430
    Vector::_staticInit(self::$config);
431
432
    // After init callbacks
433
    foreach (static::$afterInit as $callback) {
434
      if (is_callable($callback)) {
435
        $callback();
436
      }
437
    }
438
  }
439
440
  /**
441
   * @param int    $newStatus
442
   * @param string $newMessage
443
   *
444
   * @return int
445
   * @noinspection PhpUnusedParameterInspection
446
   */
447
  public static function gameDisable($newStatus = GAME_DISABLE_REASON, $newMessage = '') {
448
    /** @noinspection PhpCastIsUnnecessaryInspection */
449
    $old_server_status = intval(self::$config->pass()->game_disable);
450
451
    self::$config->pass()->game_disable = $newStatus;
452
453
    return $old_server_status;
454
  }
455
456
//  public static function gameEnable() {
457
//    self::$config->pass()->game_disable = GAME_DISABLE_NONE;
458
//  }
459
460
  /**
461
   * Is game disabled?
462
   *
463
   * @return bool
464
   */
465
  public static function gameIsDisabled() {
466
    return self::$config->pass()->game_disable != GAME_DISABLE_NONE;
467
  }
468
469
470
  /**
471
   * @return GlobalContainer
472
   */
473
  public static function services() {
474
    if (empty(self::$gc)) {
475
      self::$gc = new GlobalContainer(array(
476
        'cachePrefix' => self::$cache_prefix,
477
      ));
478
    }
479
480
    return self::$gc;
481
  }
482
483
}
484