Completed
Push — work-fleets ( 47cb39...a1ac53 )
by SuperNova.WS
05:19
created

classSupernova::db_get_unit_by_location()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 5
rs 9.4285
cc 2
eloc 3
nc 2
nop 6
1
<?php
2
3
class classSupernova {
4
  /**
5
   * ex $sn_mvc
6
   *
7
   * @var array
8
   */
9
  public static $sn_mvc = array();
10
11
  /**
12
   * ex $functions
13
   *
14
   * @var array
15
   */
16
  public static $functions = array();
17
18
  /**
19
   * @var array[] $design
20
   */
21
  public $design = array(
22
    'bbcodes' => array(),
23
    'smiles'  => array(),
24
  );
25
26
  /**
27
   * Основная БД для доступа к данным
28
   *
29
   * @var db_mysql $db
30
   */
31
  public static $db;
32
  public static $db_name = '';
33
34
  /**
35
   * Настройки из файла конфигурации
36
   *
37
   * @var string
38
   */
39
  public static $cache_prefix = '';
40
41
  public static $sn_secret_word = '';
42
43
  /**
44
   * Конфигурация игры
45
   *
46
   * @var classConfig $config
47
   */
48
  public static $config;
49
50
51
  /**
52
   * Кэш игры
53
   *
54
   * @var classCache $cache
55
   */
56
  public static $cache;
57
58
59
  /**
60
   * @var core_auth $auth
61
   */
62
  public static $auth = null;
63
64
65
  public static $db_in_transaction = false;
66
  public static $db_records_locked = false;
67
  public static $transaction_id = 0;
68
  public static $user = array();
69
  /**
70
   * @var userOptions
71
   */
72
  public static $user_options;
73
74
  /**
75
   * @var debug $debug
76
   */
77
  public static $debug = null;
78
79
  public $options = array();
80
81
  public static $data = array(); // Кэш данных - юзера, планеты, юниты, очередь, альянсы итд
82
  public static $locks = array(); // Информация о блокировках
83
  public static $queries = array(); // Кэш запросов
84
85
  // Массив $locator - хранит отношения между записями для быстрого доступа по тип_записи:тип_локации:ид_локации:внутренний_ид_записи=>информация
86
  // Для LOC_UNIT внутренний ИД - это SNID, а информация - это ссылка на запись `unit`
87
  // Для LOC_QUE внутренний ИД - это тип очереди, а информация - массив ссылок на `que`
88
  public static $locator = array(); // Кэширует соответствия между расположением объектов - в частности юнитов и очередей
89
90
  public static $delayed_changset = array(); // Накопительный массив изменений
91
92
  // Кэш индексов - ключ MD5-строка от суммы ключевых строк через | - менять | на что-то другое перед поиском и назад - после поиска
93
  // Так же в индексах могут быть двойные вхождения - например, названия планет да и вообще
94
  // Придумать спецсимвол для NULL
95
96
  /*
97
  TODO Кэш:
98
  1. Всегда дешевле использовать процессор, чем локальную память
99
  2. Всегда дешевле использовать локальную память, чем общую память всех процессов
100
  3. Всегда дешевле использовать общую память всех процессов, чем обращаться к БД
101
102
  Кэш - многоуровневый: локальная память-общая память-БД
103
  БД может быть сверхкэширующей - см. HyperNova. Это реализуется на уровне СН-драйвера БД
104
  Предусмотреть вариант, когда уровни кэширования совпадают, например когда нет xcache и используется общая память
105
  */
106
107
  // TODO Автоматически заполнять эту таблицу. В случае кэша в памяти - делать show table при обращении к таблице
108
  public static $location_info = array(
109
    LOC_USER => array(
110
      P_TABLE_NAME => 'users',
111
      P_ID         => 'id',
112
      P_OWNER_INFO => array(),
113
    ),
114
115
    LOC_PLANET => array(
116
      P_TABLE_NAME => 'planets',
117
      P_ID         => 'id',
118
      P_OWNER_INFO => array(
119
        LOC_USER => array(
120
          P_LOCATION    => LOC_USER,
121
          P_OWNER_FIELD => 'id_owner',
122
        ),
123
      ),
124
    ),
125
126
    LOC_UNIT => array(
127
      P_TABLE_NAME => 'unit',
128
      P_ID         => 'unit_id',
129
      P_OWNER_INFO => array(
130
        LOC_USER => array(
131
          P_LOCATION    => LOC_USER,
132
          P_OWNER_FIELD => 'unit_player_id',
133
        ),
134
      ),
135
    ),
136
137
    LOC_QUE => array(
138
      P_TABLE_NAME => 'que',
139
      P_ID         => 'que_id',
140
      P_OWNER_INFO => array(
141
        array(
142
          P_LOCATION    => LOC_USER,
143
          P_OWNER_FIELD => 'que_player_id',
144
        ),
145
146
        array(
147
          P_LOCATION    => LOC_PLANET,
148
          P_OWNER_FIELD => 'que_planet_id_origin',
149
        ),
150
151
        array(
152
          P_LOCATION    => LOC_PLANET,
153
          P_OWNER_FIELD => 'que_planet_id',
154
        ),
155
      ),
156
    ),
157
158
    LOC_FLEET => array(
159
      P_TABLE_NAME => 'fleets',
160
      P_ID         => 'fleet_id',
161
      P_OWNER_INFO => array(
162
        array(
163
          P_LOCATION    => LOC_USER,
164
          P_OWNER_FIELD => 'fleet_owner',
165
        ),
166
167
        array(
168
          P_LOCATION    => LOC_USER,
169
          P_OWNER_FIELD => 'fleet_target_owner',
170
        ),
171
172
        array(
173
          P_LOCATION    => LOC_PLANET,
174
          P_OWNER_FIELD => 'fleet_start_planet_id',
175
        ),
176
177
        array(
178
          P_LOCATION    => LOC_PLANET,
179
          P_OWNER_FIELD => 'fleet_end_planet_id',
180
        ),
181
      ),
182
    ),
183
  );
184
185
  /**
186
   * @param $db db_mysql
187
   */
188
  public static function init_main_db($db) {
189
    self::$db = $db;
190
    self::$db->sn_db_connect();
191
  }
192
193
194
  public static function log_file($message, $spaces = 0) {
195
    if (self::$debug) {
196
      self::$debug->log_file($message, $spaces);
197
    }
198
  }
199
200
  public static function debug_set_handler($debug) {
201
    self::$debug = $debug;
202
  }
203
204
  // Перепаковывает массив на заданную глубину, убирая поля с null
205
  public static function array_repack(&$array, $level = 0) {
206
    // TODO $lock_table не нужна тут
207
    if (!is_array($array)) {
208
      return;
209
    }
210
211
    foreach ($array as $key => &$value) {
212
      if ($value === null) {
213
        unset($array[$key]);
214
      } elseif ($level > 0 && is_array($value)) {
215
        static::array_repack($value, $level - 1);
216
        if (empty($value)) {
217
          unset($array[$key]);
218
        }
219
      }
220
    }
221
  }
222
223
224
  // TODO Вынести в отдельный объект
225
  public static function cache_repack($location_type, $record_id = 0) {
226
    // Если есть $user_id - проверяем, а надо ли перепаковывать?
227
    if ($record_id && isset(static::$data[$location_type][$record_id]) && static::$data[$location_type][$record_id] !== null) {
228
      return;
229
    }
230
231
    static::array_repack(static::$data[$location_type]);
232
    static::array_repack(static::$locator[$location_type], 3); // TODO У каждого типа локации - своя глубина!!!! Но можно и глубже ???
233
    static::array_repack(static::$queries[$location_type], 1);
234
  }
235
236
  public static function cache_clear($location_type, $hard = true) {
237
    if ($hard && !empty(static::$data[$location_type])) {
238
      // Здесь нельзя делать unset - надо записывать NULL, что бы это отразилось на зависимых записях
239
      array_walk(static::$data[$location_type], function (&$item) { $item = null; });
240
    }
241
    static::$locator[$location_type] = array();
242
    static::$queries[$location_type] = array();
243
    static::cache_repack($location_type); // Перепаковываем внутренние структуры, если нужно
244
  }
245
246
  public static function cache_clear_all($hard = true) {
247
    if ($hard) {
248
      static::$data = array();
249
      static::cache_lock_unset_all();
250
    }
251
    static::$locator = array();
252
    static::$queries = array();
253
  }
254
255
  public static function cache_get($location_type, $record_id) {
256
    return isset(static::$data[$location_type][$record_id]) ? static::$data[$location_type][$record_id] : null;
257
  }
258
259
  public static function cache_isset($location_type, $record_id) {
260
    return isset(static::$data[$location_type][$record_id]) && static::$data[$location_type][$record_id] !== null;
261
  }
262
263
  /* Кэшируем запись в соответствующий кэш
264
265
  Писать в кэш:
266
  1. Если записи не существует в кэше
267
  2. Если стоит $force_overwrite
268
  3. Если во время транзакции существующая запись не заблокирована
269
270
  Блокировать запись:
271
  1. Если идет транзакция и запись не заблокирована
272
  2. Если не стоит скип-лок
273
  */
274
  public static function cache_set($location_type, $record, $force_overwrite = false, $skip_lock = false) {
275
    // нет идентификатора - выход
276
    if (!($record_id = $record[static::$location_info[$location_type][P_ID]])) {
277
      return;
278
    }
279
280
    $in_transaction = static::db_transaction_check(false);
281
    if (
282
      $force_overwrite
283
      ||
284
      // Не заменяются заблокированные записи во время транзакции
285
      ($in_transaction && !static::cache_lock_get($location_type, $record_id))
286
      ||
287
      !static::cache_isset($location_type, $record_id)
288
    ) {
289
      static::$data[$location_type][$record_id] = $record;
290
      if ($in_transaction && !$skip_lock) {
291
        static::cache_lock_set($location_type, $record_id);
292
      }
293
    }
294
  }
295
296
  public static function cache_unset($cache_id, $safe_record_id) {
297
    // $record_id должен быть проверен заранее !
298
    if (isset(static::$data[$cache_id][$safe_record_id]) && static::$data[$cache_id][$safe_record_id] !== null) {
299
      // Выставляем запись в null
300
      static::$data[$cache_id][$safe_record_id] = null;
301
      // Очищаем кэш мягко - что бы удалить очистить связанные данные - кэш локаций и кэш запоросов и всё, что потребуется впредь
302
      static::cache_clear($cache_id, false);
303
    }
304
  }
305
306
  public static function cache_lock_get($location_type, $record_id) {
307
    return isset(static::$locks[$location_type][$record_id]);
308
  }
309
310
  public static function cache_lock_set($location_type, $record_id) {
311
    return static::$locks[$location_type][$record_id] = true; // Не всегда - от результата
312
  }
313
314
  public static function cache_lock_unset($location_type, $record_id) {
315
    if (isset(static::$locks[$location_type][$record_id])) {
316
      unset(static::$locks[$location_type][$record_id]);
317
    }
318
319
    return true; // Не всегда - от результата
320
  }
321
322
  public static function cache_lock_unset_all() {
323
    // Когда будем работать с xcache - это понадобиться, что бы снимать в xcache блокировки с записей
324
    // Пройти по массиву - снять блокировки для кэшера в памяти
325
    static::$locks = array();
326
327
    return true; // Не всегда - от результата
328
  }
329
330
331
332
333
334
  // TODO Вынести в отдельный объект
335
  /**
336
   * Эта функция проверяет статус транзакции
337
   *
338
   * Это - низкоуровневая функция. В нормальном состоянии движка её сообщения никогда не будут видны
339
   *
340
   * @param null|true|false $status Должна ли быть запущена транзакция в момент проверки
341
   *   <p>null - транзакция НЕ должна быть запущена</p>
342
   *   <p>true - транзакция должна быть запущена - для совместимости с $for_update</p>
343
   *   <p>false - всё равно - для совместимости с $for_update</p>
344
   *
345
   * @return bool Текущий статус транзакции
346
   */
347
  public static function db_transaction_check($status = null) {
348
    $error_msg = false;
349
    if ($status && !static::$db_in_transaction) {
350
      $error_msg = 'No transaction started for current operation';
351
    } elseif ($status === null && static::$db_in_transaction) {
352
      $error_msg = 'Transaction is already started';
353
    }
354
355
    if (!empty($error_msg)) {
356
      // TODO - Убрать позже
357
      print('<h1>СООБЩИТЕ ЭТО АДМИНУ: sn_db_transaction_check() - ' . $error_msg . '</h1>');
358
      $backtrace = debug_backtrace();
359
      array_shift($backtrace);
360
      pdump($backtrace);
361
      die($error_msg);
362
    }
363
364
    return static::$db_in_transaction;
365
  }
366
367
  public static function db_transaction_start($level = '') {
368
    static::db_transaction_check(null);
369
370
    $level ? doquery('SET TRANSACTION ISOLATION LEVEL ' . $level) : false;
371
372
    static::$transaction_id++;
373
    doquery('START TRANSACTION');
374
375
    if (classSupernova::$config->db_manual_lock_enabled) {
376
      classSupernova::$config->db_loadItem('var_db_manually_locked');
377
      classSupernova::$config->db_saveItem('var_db_manually_locked', SN_TIME_SQL);
378
    }
379
380
    static::$db_in_transaction = true;
381
    static::$locator = array();
382
    static::$queries = array();
383
384
    return static::$transaction_id;
385
  }
386
387
  public static function db_transaction_commit() {
388
    static::db_transaction_check(true);
0 ignored issues
show
Documentation introduced by
true is of type boolean, but the function expects a null|object<true>|false.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
389
390
    if (!empty(static::$delayed_changset)) {
391
      static::db_changeset_apply(static::$delayed_changset, true);
392
    }
393
    doquery('COMMIT');
394
395
    return static::db_transaction_clear();
396
  }
397
398
  public static function db_transaction_rollback() {
399
    // static::db_transaction_check(true); // TODO - вообще-то тут тоже надо проверять есть ли транзакция
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
400
401
    if (!empty(static::$delayed_changset)) {
402
      static::db_changeset_revert();
403
    }
404
    doquery('ROLLBACK');
405
406
    return static::db_transaction_clear();
407
  }
408
409
  protected static function db_transaction_clear() {
410
    static::$delayed_changset = array();
411
    static::cache_lock_unset_all();
412
413
    static::$db_in_transaction = false;
414
    static::$db_records_locked = false;
415
    static::$transaction_id++;
416
417
    return static::$transaction_id;
418
  }
419
420
  /**
421
   * Блокирует указанные таблицу/список таблиц
422
   *
423
   * @param string|array $tables Таблица/список таблиц для блокировки. Названия таблиц - без префиксов
424
   * <p>string - название таблицы для блокировки</p>
425
   * <p>array - массив, где ключ - имя таблицы, а значение - условия блокировки элементов</p>
426
   */
427
  public static function db_lock_tables($tables) {
428
    $tables = is_array($tables) ? $tables : array($tables => '');
429
    foreach ($tables as $table_name => $condition) {
430
      self::$db->doquery("SELECT 1 FROM {{{$table_name}}}" . ($condition ? ' WHERE ' . $condition : ''));
431
    }
432
  }
433
434
  public static function db_query($query, $fetch = false, $skip_lock = false) {
435
    $select = strpos(strtoupper($query), 'SELECT') !== false;
436
437
    $query .= $select && $fetch ? ' LIMIT 1' : '';
438
    $query .= $select && !$skip_lock && static::db_transaction_check(false) ? ' FOR UPDATE' : '';
439
440
    $result = self::$db->doquery($query, $fetch);
0 ignored issues
show
Documentation introduced by
$fetch is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
441
442
    return $result;
443
  }
444
445
  /**
446
   * Возвращает информацию о записи по её ID
447
   *
448
   * @param int       $location_type
449
   * @param int|array $record_id_unsafe
450
   *    <p>int - ID записи</p>
451
   *    <p>array - запись пользователя с установленным полем P_ID</p>
452
   * @param bool      $for_update @deprecated
453
   * @param string    $fields @deprecated список полей или '*'/'' для всех полей
454
   * @param bool      $skip_lock Указывает на то, что не нужно блокировать запись //TODO и не нужно сохранять в кэше
455
   *
456
   * @return array|false
457
   *    <p>false - Нет записи с указанным ID</p>
458
   *    <p>array - запись</p>
459
   */
460
  public static function db_get_record_by_id($location_type, $record_id_unsafe, $for_update = false, $fields = '*', $skip_lock = false) {
0 ignored issues
show
Unused Code introduced by
The parameter $for_update is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $fields is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $skip_lock is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
461
    $id_field = static::$location_info[$location_type][P_ID];
462
    $record_id_safe = idval(is_array($record_id_unsafe) && isset($record_id_unsafe[$id_field]) ? $record_id_unsafe[$id_field] : $record_id_unsafe);
463
464
    return static::db_get_record_list($location_type, "`{$id_field}` = {$record_id_safe}", true, false);
465
  }
466
467
  public static function db_get_record_list($location_type, $filter = '', $fetch = false, $no_return = false) {
468
    $query_cache = &static::$queries[$location_type][$filter];
469
470
    if (!isset($query_cache) || $query_cache === null) {
471
      $location_info = &static::$location_info[$location_type];
472
      $id_field = $location_info[P_ID];
473
      $query_cache = array();
474
475
      if (static::db_transaction_check(false)) {
476
        // Проходим по всем родителям данной записи
477
        foreach ($location_info[P_OWNER_INFO] as $owner_data) {
478
          $owner_location_type = $owner_data[P_LOCATION];
479
          $parent_id_list = array();
480
          // Выбираем родителей данного типа и соответствующие ИД текущего типа
481
          $query = static::db_query(
482
            "SELECT
483
              distinct({{{$location_info[P_TABLE_NAME]}}}.{$owner_data[P_OWNER_FIELD]}) AS parent_id
484
            FROM {{{$location_info[P_TABLE_NAME]}}}" .
485
            ($filter ? ' WHERE ' . $filter : '') .
486
            ($fetch ? ' LIMIT 1' : ''), false, true);
487
488
          while ($row = db_fetch($query)) {
489
            // Исключаем из списка родительских ИД уже заблокированные записи
490
            if (!static::cache_lock_get($owner_location_type, $row['parent_id'])) {
491
              $parent_id_list[$row['parent_id']] = $row['parent_id'];
492
            }
493
          }
494
          // Если все-таки какие-то записи еще не заблокированы - вынимаем текущие версии из базы
495
          if ($indexes_str = implode(',', $parent_id_list)) {
496
            $parent_id_field = static::$location_info[$owner_location_type][P_ID];
497
            static::db_get_record_list($owner_location_type,
498
              $parent_id_field . (count($parent_id_list) > 1 ? " IN ({$indexes_str})" : " = {$indexes_str}"), $fetch, true);
499
          }
500
        }
501
      }
502
503
      $query = static::db_query(
504
        "SELECT * FROM {{{$location_info[P_TABLE_NAME]}}}" .
505
        (($filter = trim($filter)) ? " WHERE {$filter}" : '')
506
      );
507
      while ($row = db_fetch($query)) {
508
        static::cache_set($location_type, $row);
509
        $query_cache[$row[$id_field]] = &static::$data[$location_type][$row[$id_field]];
510
      }
511
    }
512
513
    if ($no_return) {
514
      return true;
515
    } else {
516
      $result = false;
517
      if (is_array($query_cache)) {
518
        foreach ($query_cache as $key => $value) {
519
          $result[$key] = $value;
520
          if ($fetch) {
521
            break;
522
          }
523
        }
524
      }
525
526
      return $fetch ? (is_array($result) ? reset($result) : false) : $result;
527
    }
528
  }
529
530
  /**
531
   * @param int    $location_type
532
   * @param int    $record_id
533
   * @param string $set - SQL SET structure
534
   *
535
   * @return array|bool|mysqli_result|null
536
   */
537
  public static function db_upd_record_by_id($location_type, $record_id, $set) {
538
    if (!($record_id = idval($record_id)) || !($set = trim($set))) {
539
      return false;
540
    }
541
542
    $location_info = &static::$location_info[$location_type];
543
    $id_field = $location_info[P_ID];
544
    $table_name = $location_info[P_TABLE_NAME];
545
    if ($result = static::db_query($q = "UPDATE {{{$table_name}}} SET {$set} WHERE `{$id_field}` = {$record_id}")) // TODO Как-то вернуть может быть LIMIT 1 ?
546
    {
547
      if (static::$db->db_affected_rows()) {
548
        // Обновляем данные только если ряд был затронут
549
        // TODO - переделать под работу со структурированными $set
550
551
        // Тут именно так, а не cache_unset - что бы в кэшах автоматически обновилась запись. Будет нужно на будущее
552
        static::$data[$location_type][$record_id] = null;
553
        // Вытаскиваем обновленную запись
554
        static::db_get_record_by_id($location_type, $record_id);
555
        static::cache_clear($location_type, false); // Мягкий сброс - только $queries
556
      }
557
    }
558
559
    return $result;
560
  }
561
562
  public static function db_upd_record_list($location_type, $condition, $set) {
563
    if (!($set = trim($set))) {
564
      return false;
565
    }
566
567
    $condition = trim($condition);
568
    $table_name = static::$location_info[$location_type][P_TABLE_NAME];
569
570
    if ($result = static::db_query("UPDATE {{{$table_name}}} SET " . $set . ($condition ? ' WHERE ' . $condition : ''))) {
571
572
      if (static::$db->db_affected_rows()) { // Обновляем данные только если ряд был затронут
573
        // Поскольку нам неизвестно, что и как обновилось - сбрасываем кэш этого типа полностью
574
        // TODO - когда будет структурированный $condition и $set - перепаковывать данные
575
        static::cache_clear($location_type, true);
576
      }
577
    }
578
579
    return $result;
580
  }
581
582
  /**
583
   * @param int    $location_type
584
   * @param string $set
585
   *
586
   * @return array|bool|false|mysqli_result|null
587
   */
588
  public static function db_ins_record($location_type, $set) {
589
    $set = trim($set);
590
    $table_name = static::$location_info[$location_type][P_TABLE_NAME];
591 View Code Duplication
    if ($result = static::db_query("INSERT INTO `{{{$table_name}}}` SET {$set}")) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
592
      if (static::$db->db_affected_rows()) // Обновляем данные только если ряд был затронут
593
      {
594
        $record_id = db_insert_id();
595
        // Вытаскиваем запись целиком, потому что в $set могли быть "данные по умолчанию"
596
        $result = static::db_get_record_by_id($location_type, $record_id);
597
        // Очищаем второстепенные кэши - потому что вставленная запись могла повлиять на результаты запросов или локация или еще чего
598
        // TODO - когда будет поддержка изменения индексов и локаций - можно будет вызывать её
599
        static::cache_clear($location_type, false); // Мягкий сброс - только $queries
600
      }
601
    }
602
603
    return $result;
604
  }
605
606
  public static function db_ins_field_set($location_type, $field_set, $serialize = false) {
607
    // TODO multiinsert
608
    !sn_db_field_set_is_safe($field_set) ? $field_set = sn_db_field_set_make_safe($field_set, $serialize) : false;
609
    sn_db_field_set_safe_flag_clear($field_set);
610
    $values = implode(',', $field_set);
611
    $fields = implode(',', array_keys($field_set));
612
613
    $table_name = static::$location_info[$location_type][P_TABLE_NAME];
614 View Code Duplication
    if ($result = static::db_query("INSERT INTO `{{{$table_name}}}` ($fields) VALUES ($values);")) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
615
      if (static::$db->db_affected_rows()) {
616
        // Обновляем данные только если ряд был затронут
617
        $record_id = db_insert_id();
618
        // Вытаскиваем запись целиком, потому что в $set могли быть "данные по умолчанию"
619
        $result = static::db_get_record_by_id($location_type, $record_id);
620
        // Очищаем второстепенные кэши - потому что вставленная запись могла повлиять на результаты запросов или локация или еще чего
621
        // TODO - когда будет поддержка изменения индексов и локаций - можно будет вызывать её
622
        static::cache_clear($location_type, false); // Мягкий сброс - только $queries
623
      }
624
    }
625
626
    return $result;
627
  }
628
629
  public static function db_del_record_by_id($location_type, $safe_record_id) {
630
    if (!($safe_record_id = idval($safe_record_id))) {
631
      return false;
632
    }
633
634
    $location_info = &static::$location_info[$location_type];
635
    $id_field = $location_info[P_ID];
636
    $table_name = $location_info[P_TABLE_NAME];
637
    if ($result = static::db_query("DELETE FROM `{{{$table_name}}}` WHERE `{$id_field}` = {$safe_record_id}")) {
638
      // Обновляем данные только если ряд был затронут
639
      if (static::$db->db_affected_rows()) {
640
        static::cache_unset($location_type, $safe_record_id);
641
      }
642
    }
643
644
    return $result;
645
  }
646
647
  public static function db_del_record_list($location_type, $condition) {
648
    if (!($condition = trim($condition))) {
649
      return false;
650
    }
651
652
    $location_info = &static::$location_info[$location_type];
653
    $table_name = $location_info[P_TABLE_NAME];
654
655
    if ($result = static::db_query("DELETE FROM `{{{$table_name}}}` WHERE {$condition}")) {
656
      // Обновляем данные только если ряд был затронут
657
      if (static::$db->db_affected_rows()) {
658
        // Обнуление кэша, потому что непонятно, что поменялось
659
        // TODO - когда будет структурированный $condition можно будет делать только cache_unset по нужным записям
660
        static::cache_clear($location_type);
661
      }
662
    }
663
664
    return $result;
665
  }
666
667
668
669
  // Работа с пользователями
670
  /**
671
   * Возвращает информацию о пользователе по его ID
672
   *
673
   * @param int|array $user_id_unsafe
674
   *    <p>int - ID пользователя</p>
675
   *    <p>array - запись пользователя с установленным полем ['id']</p>
676
   * @param bool      $for_update @deprecated
677
   * @param string    $fields @deprecated список полей или '*'/'' для всех полей
678
   * @param null      $player
679
   * @param bool|null $player Признак выбора записи пользователь типа "игрок"
680
   *    <p>null - Можно выбрать запись любого типа</p>
681
   *    <p>true - Выбирается только запись типа "игрок"</p>
682
   *    <p>false - Выбирается только запись типа "альянс"</p>
683
   *
684
   * @return array|false
685
   *    <p>false - Нет записи с указанным ID и $player</p>
686
   *    <p>array - запись типа $user</p>
687
   */
688
  public static function db_get_user_by_id($user_id_unsafe, $for_update = false, $fields = '*', $player = null) {
689
    $user = static::db_get_record_by_id(LOC_USER, $user_id_unsafe, $for_update, $fields);
690
691
    return (is_array($user) &&
692
      (
693
        $player === null
694
        ||
695
        ($player === true && !$user['user_as_ally'])
696
        ||
697
        ($player === false && $user['user_as_ally'])
698
      )) ? $user : false;
699
  }
700
701
  public static function db_get_user_by_username($username_unsafe, $for_update = false, $fields = '*', $player = null, $like = false) {
0 ignored issues
show
Unused Code introduced by
The parameter $for_update is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $fields is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
702
    // TODO Проверить, кстати - а везде ли нужно выбирать юзеров или где-то все-таки ищутся Альянсы ?
703
    if (!($username_unsafe = trim($username_unsafe))) {
704
      return false;
705
    }
706
707
    $user = null;
708
    if (is_array(static::$data[LOC_USER])) {
709
      foreach (static::$data[LOC_USER] as $user_id => $user_data) {
710
        if (is_array($user_data) && isset($user_data['username'])) {
711
          // проверяем поле
712
          // TODO Возможно есть смысл всегда искать по strtolower - но может игрок захочет переименоваться с другим регистром? Проверить!
713
          if ((!$like && $user_data['username'] == $username_unsafe) || ($like && strtolower($user_data['username']) == strtolower($username_unsafe))) {
714
            // $user_as_ally = intval($user_data['user_as_ally']);
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
715
            $user_as_ally = idval($user_data['user_as_ally']);
716
            if ($player === null || ($player === true && !$user_as_ally) || ($player === false && $user_as_ally)) {
717
              $user = $user_data;
718
              break;
719
            }
720
          }
721
        }
722
      }
723
    }
724
725 View Code Duplication
    if ($user === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
726
      // Вытаскиваем запись
727
      $username_safe = db_escape($like ? strtolower($username_unsafe) : $username_unsafe); // тут на самом деле strtolower() лишняя, но пусть будет
728
729
      // TODO переписать
730
      $user = static::db_query(
731
        "SELECT * FROM {{users}} WHERE `username` " . ($like ? 'LIKE' : '=') . " '{$username_safe}'"
732
        , true);
733
      static::cache_set(LOC_USER, $user); // В кэш-юзер так же заполнять индексы
734
    }
735
736
    return $user;
737
  }
738
739
  // UNUSED
740
  public static function db_get_user_by_email($email_unsafe, $use_both = false, $for_update = false, $fields = '*') {
0 ignored issues
show
Unused Code introduced by
The parameter $for_update is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $fields is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
741
    if (!($email_unsafe = strtolower(trim($email_unsafe)))) {
742
      return false;
743
    }
744
745
    $user = null;
746
    // TODO переделать на индексы
747
    if (is_array(static::$data[LOC_USER])) {
748
      foreach (static::$data[LOC_USER] as $user_id => $user_data) {
749
        if (is_array($user_data) && isset($user_data['email_2'])) {
750
          // проверяем поле
751
          if (strtolower($user_data['email_2']) == $email_unsafe || ($use_both && strtolower($user_data['email']) == $email_unsafe)) {
752
            $user = $user_data;
753
            break;
754
          }
755
        }
756
      }
757
    }
758
759 View Code Duplication
    if ($user === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
760
      // Вытаскиваем запись
761
      $email_safe = db_escape($email_unsafe);
762
      $user = static::db_query(
763
        "SELECT * FROM {{users}} WHERE LOWER(`email_2`) = '{$email_safe}'" .
764
        ($use_both ? " OR LOWER(`email`) = '{$email_safe}'" : '')
765
        , true);
766
767
      static::cache_set(LOC_USER, $user); // В кэш-юзер так же заполнять индексы
768
    }
769
770
    return $user;
771
  }
772
773
  public static function db_get_user_by_where($where_safe, $for_update = false, $fields = '*') {
0 ignored issues
show
Unused Code introduced by
The parameter $for_update is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $fields is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
774
    $user = null;
775
    // TODO переделать на индексы
776
777
    if ($user === null && !empty($where_safe)) {
778
      // Вытаскиваем запись
779
      $user = static::db_query("SELECT * FROM {{users}} WHERE {$where_safe}", true);
780
781
      static::cache_set(LOC_USER, $user); // В кэш-юзер так же заполнять индексы
782
    }
783
784
    return $user;
785
  }
786
787
788 View Code Duplication
  public static function db_unit_time_restrictions($date = SN_TIME_NOW) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
789
    $date = is_numeric($date) ? "FROM_UNIXTIME({$date})" : "'{$date}'";
790
791
    return
792
      "(unit_time_start IS NULL OR unit_time_start <= {$date}) AND
793
    (unit_time_finish IS NULL OR unit_time_finish = '1970-01-01 03:00:00' OR unit_time_finish >= {$date})";
794
  }
795
796
  public static function db_get_unit_by_id($unit_id, $for_update = false, $fields = '*') {
797
    // TODO запихивать в $data[LOC_LOCATION][$location_type][$location_id]
0 ignored issues
show
Unused Code Comprehensibility introduced by
53% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
798
    $unit = static::db_get_record_by_id(LOC_UNIT, $unit_id, $for_update, $fields);
799
    if (is_array($unit)) {
800
      static::$locator[LOC_UNIT][$unit['unit_location_type']][$unit['unit_location_id']][$unit['unit_snid']] = &static::$data[LOC_UNIT][$unit_id];
801
    }
802
803
    return $unit;
804
  }
805
806
  /**
807
   * @param int $user_id
808
   * @param     $location_type
809
   * @param     $location_id
810
   *
811
   * @return array|bool
812
   */
813
  public static function db_get_unit_list_by_location($user_id = 0, $location_type, $location_id) {
0 ignored issues
show
Unused Code introduced by
The parameter $user_id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
814
    if (!($location_type = idval($location_type)) || !($location_id = idval($location_id))) {
815
      return false;
816
    }
817
818
    $query_cache = &static::$locator[LOC_UNIT][$location_type][$location_id];
819
    if (!isset($query_cache)) {
820
      $got_data = static::db_get_record_list(LOC_UNIT, "unit_location_type = {$location_type} AND unit_location_id = {$location_id} AND " . static::db_unit_time_restrictions());
821
      if (is_array($got_data)) {
822
        foreach ($got_data as $unit_id => $unit_data) {
823
          $query_cache[$unit_data['unit_snid']] = &static::$data[LOC_UNIT][$unit_id];
824
        }
825
      }
826
    }
827
828
    $result = false;
829
    if (is_array($query_cache)) {
830
      foreach ($query_cache as $key => $value) {
831
        $result[$key] = $value;
832
      }
833
    }
834
835
    return $result;
836
  }
837
838
  public static function db_get_unit_by_location($user_id = 0, $location_type, $location_id, $unit_snid = 0, $for_update = false, $fields = '*') {
0 ignored issues
show
Unused Code introduced by
The parameter $for_update is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $fields is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
839
    static::db_get_unit_list_by_location($user_id, $location_type, $location_id);
840
841
    return $unit_snid ? static::$locator[LOC_UNIT][$location_type][$location_id][$unit_snid] : static::$locator[LOC_UNIT][$location_type][$location_id];
842
  }
843
844
845
  /*
846
   * С $for_update === true эта функция должна вызываться только из транзакции! Все соответствующие записи в users и planets должны быть уже блокированы!
847
   *
848
   * $que_type
849
   *   !$que_type - все очереди
850
   *   QUE_XXXXXX - конкретная очередь по планете
851
   * $user_id - ID пользователя
852
   * $planet_id
853
   *   $que_type == QUE_RESEARCH - игнорируется
854
   *   null - обработка очередей планет не производится
855
   *   false/0 - обрабатываются очереди всех планет по $user_id
856
   *   (integer) - обрабатываются локальные очереди для планеты. Нужно, например, в обработчике флотов
857
   *   иначе - $que_type для указанной планеты
858
   * $for_update - true == нужно блокировать записи
859
   *
860
   * TODO Работа при !$user_id
861
   * TODO Переформатировать вывод данных, что бы можно было возвращать данные по всем планетам и юзерам в одном запросе: добавить подмассивы 'que', 'planets', 'players'
862
   *
863
   */
864
  public static function db_que_list_by_type_location($user_id, $planet_id = null, $que_type = false, $for_update = false) {
0 ignored issues
show
Unused Code introduced by
The parameter $for_update is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
865
    if (!$user_id) {
866
      pdump(debug_backtrace());
867
      die('No user_id for que_get_que()');
868
    }
869
870
    $ques = array();
871
872
    $query = array();
873
874
    if ($user_id = idval($user_id)) {
875
      $query[] = "`que_player_id` = {$user_id}";
876
    }
877
878
    if ($que_type == QUE_RESEARCH || $planet_id === null) {
879
      $query[] = "`que_planet_id` IS NULL";
880
    } elseif ($planet_id) {
881
      $query[] = "(`que_planet_id` = {$planet_id}" . ($que_type ? '' : ' OR que_planet_id IS NULL') . ")";
882
    }
883
    if ($que_type) {
884
      $query[] = "`que_type` = {$que_type}";
885
    }
886
887
    $ques['items'] = static::db_get_record_list(LOC_QUE, implode(' AND ', $query));
888
889
    return que_recalculate($ques);
890
  }
891
892
893 View Code Duplication
  public static function db_changeset_prepare_unit($unit_id, $unit_value, $user, $planet_id = null) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
894
    if (!is_array($user)) {
895
      // TODO - remove later
896
      print('<h1>СООБЩИТЕ ЭТО АДМИНУ: sn_db_unit_changeset_prepare() - USER is not ARRAY</h1>');
897
      pdump(debug_backtrace());
898
      die('USER is not ARRAY');
899
    }
900
    if (!isset($user['id']) || !$user['id']) {
901
      // TODO - remove later
902
      print('<h1>СООБЩИТЕ ЭТО АДМИНУ: sn_db_unit_changeset_prepare() - USER[id] пустой</h1>');
903
      pdump($user);
904
      pdump(debug_backtrace());
905
      die('USER[id] пустой');
906
    }
907
    $planet_id = is_array($planet_id) && isset($planet_id['id']) ? $planet_id['id'] : $planet_id;
908
909
    $unit_location = sys_get_unit_location($user, array(), $unit_id);
910
    $location_id = $unit_location == LOC_USER ? $user['id'] : $planet_id;
911
    $location_id = $location_id ? $location_id : 'NULL';
912
913
    $temp = db_unit_by_location($user['id'], $unit_location, $location_id, $unit_id, true, 'unit_id');
914
    if ($temp['unit_id']) {
915
      $db_changeset = array(
916
        'action'  => SQL_OP_UPDATE,
917
        P_VERSION => 1,
918
        'where'   => array(
919
          "unit_id" => $temp['unit_id'],
920
        ),
921
        'fields'  => array(
922
          'unit_level' => array(
923
            'delta' => $unit_value
924
          ),
925
        ),
926
      );
927
    } else {
928
      $db_changeset = array(
929
        'action' => SQL_OP_INSERT,
930
        'fields' => array(
931
          'unit_player_id'     => array(
932
            'set' => $user['id'],
933
          ),
934
          'unit_location_type' => array(
935
            'set' => $unit_location,
936
          ),
937
          'unit_location_id'   => array(
938
            'set' => $unit_location == LOC_USER ? $user['id'] : $planet_id,
939
          ),
940
          'unit_type'          => array(
941
            'set' => get_unit_param($unit_id, P_UNIT_TYPE),
942
          ),
943
          'unit_snid'          => array(
944
            'set' => $unit_id,
945
          ),
946
          'unit_level'         => array(
947
            'set' => $unit_value,
948
          ),
949
        ),
950
      );
951
    }
952
953
    return $db_changeset;
954
  }
955
956
957
  public function db_changeset_delay($table_name, $table_data) {
958
    // TODO Применять ченджсет к записям
959
    static::$delayed_changset[$table_name] = is_array(static::$delayed_changset[$table_name]) ? static::$delayed_changset[$table_name] : array();
960
    // TODO - На самом деле дурацкая оптимизация, если честно - может быть идентичные записи с идентичными дельтами - и привет. Но не должны, конечно
961
    static::$delayed_changset[$table_name] = array_merge(static::$delayed_changset[$table_name], $table_data);
962
  }
963
964
  public function db_changeset_revert() {
965
    // TODO Для этапа 1 - достаточно чистить только те таблицы, что были затронуты
966
    // Для этапа 2 - чистить только записи
967
    // Для этапа 3 - возвращать всё
968
    static::cache_clear_all(true);
969
  }
970
971
  public function db_changeset_condition_compile(&$conditions, &$table_name = '') {
972
    if (!$conditions[P_LOCATION] || $conditions[P_LOCATION] == LOC_NONE) {
973
      $conditions[P_LOCATION] = LOC_NONE;
974
      switch ($table_name) {
975
        case 'users':
976
        case LOC_USER:
977
          $conditions[P_TABLE_NAME] = $table_name = 'users';
978
          $conditions[P_LOCATION] = LOC_USER;
979
        break;
980
981
        case 'planets':
982
        case LOC_PLANET:
983
          $conditions[P_TABLE_NAME] = $table_name = 'planets';
984
          $conditions[P_LOCATION] = LOC_PLANET;
985
        break;
986
987
        case 'unit':
988
        case LOC_UNIT:
989
          $conditions[P_TABLE_NAME] = $table_name = 'unit';
990
          $conditions[P_LOCATION] = LOC_UNIT;
991
        break;
992
      }
993
    }
994
995
    $conditions[P_FIELDS_STR] = '';
996
    if ($conditions['fields']) {
997
      $fields = array();
998 View Code Duplication
      foreach ($conditions['fields'] as $field_name => $field_data) {
0 ignored issues
show
Bug introduced by
The expression $conditions['fields'] of type string is not traversable.
Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
999
        $condition = "`{$field_name}` = ";
1000
        $value = '';
1001
        if ($field_data['delta']) {
1002
          $value = "`{$field_name}`" . ($field_data['delta'] >= 0 ? '+' : '') . $field_data['delta'];
1003
        } elseif ($field_data['set']) {
1004
          $value = (is_string($field_data['set']) ? "'{$field_data['set']}'" : $field_data['set']);
1005
        }
1006
1007
        if ($value) {
1008
          $fields[] = $condition . $value;
1009
        }
1010
      }
1011
      $conditions[P_FIELDS_STR] = implode(',', $fields);
1012
    }
1013
1014
    $conditions[P_WHERE_STR] = '';
1015
    if (!empty($conditions['where'])) {
1016
      if ($conditions[P_VERSION] == 1) {
1017
        $the_conditions = array();
1018
        foreach ($conditions['where'] as $field_id => $field_value) {
0 ignored issues
show
Bug introduced by
The expression $conditions['where'] of type string is not traversable.
Loading history...
1019
          // Простое условие - $field_id = $field_value
1020
          if (is_string($field_id)) {
1021
            $field_value =
1022
              $field_value === null ? 'NULL' :
1023
                (is_string($field_value) ? "'" . db_escape($field_value) . "'" :
1024
                  (is_bool($field_value) ? intval($field_value) : $field_value));
1025
            $the_conditions[] = "`{$field_id}` = {$field_value}";
1026
          } else {
1027
            die('Неподдерживаемый тип условия');
1028
          }
1029
        }
1030
      } else {
1031
        $the_conditions = &$conditions['where'];
1032
      }
1033
      $conditions[P_WHERE_STR] = implode(' AND ', $the_conditions);
1034
    }
1035
1036
    switch ($conditions['action']) {
1037
      case SQL_OP_DELETE:
1038
        $conditions[P_ACTION_STR] = ("DELETE FROM {{{$table_name}}}");
1039
      break;
1040
      case SQL_OP_UPDATE:
1041
        $conditions[P_ACTION_STR] = ("UPDATE {{{$table_name}}} SET");
1042
      break;
1043
      case SQL_OP_INSERT:
1044
        $conditions[P_ACTION_STR] = ("INSERT INTO {{{$table_name}}} SET");
1045
      break;
1046
      // case SQL_OP_REPLACE: $result = doquery("REPLACE INTO {{{$table_name}}} SET {$fields}") && $result; break;
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1047
      default:
1048
        die('Неподдерживаемая операция в classSupernova::db_changeset_condition_compile');
1049
    }
1050
1051
    $conditions[P_QUERY_STR] = $conditions[P_ACTION_STR] . ' ' . $conditions[P_FIELDS_STR] . (' WHERE ' . $conditions[P_WHERE_STR]);
1052
  }
1053
1054
  public static function db_changeset_apply($db_changeset, $flush_delayed = false) {
0 ignored issues
show
Unused Code introduced by
The parameter $flush_delayed is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1055
    $result = true;
1056
    if (!is_array($db_changeset) || empty($db_changeset)) {
1057
      return $result;
1058
    }
1059
1060
    foreach ($db_changeset as $table_name => &$table_data) {
1061
      // TODO - delayed changeset
1062
      foreach ($table_data as $record_id => &$conditions) {
1063
        static::db_changeset_condition_compile($conditions, $table_name);
1064
1065
        if ($conditions['action'] != SQL_OP_DELETE && !$conditions[P_FIELDS_STR]) {
1066
          continue;
1067
        }
1068
        if ($conditions['action'] == SQL_OP_DELETE && !$conditions[P_WHERE_STR]) {
1069
          continue;
1070
        } // Защита от случайного удаления всех данных в таблице
1071
1072
        if ($conditions[P_LOCATION] != LOC_NONE) {
1073
          switch ($conditions['action']) {
1074
            case SQL_OP_DELETE:
1075
              $result = self::db_del_record_list($conditions[P_LOCATION], $conditions[P_WHERE_STR]) && $result;
1076
            break;
1077
            case SQL_OP_UPDATE:
1078
              $result = self::db_upd_record_list($conditions[P_LOCATION], $conditions[P_WHERE_STR], $conditions[P_FIELDS_STR]) && $result;
1079
            break;
1080
            case SQL_OP_INSERT:
1081
              $result = self::db_ins_record($conditions[P_LOCATION], $conditions[P_FIELDS_STR]) && $result;
1082
            break;
1083
            default:
1084
              die('Неподдерживаемая операция в classSupernova::db_changeset_apply');
1085
            // case SQL_OP_REPLACE: $result = $result && doquery("REPLACE INTO {{{$table_name}}} SET {$fields}"); break;
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1086
          }
1087
        } else {
1088
          $result = doquery($conditions[P_QUERY_STR]) && $result;
1089
        }
1090
      }
1091
    }
1092
1093
    return $result;
1094
  }
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
  // que_process не всегда должна работать в режиме прямой работы с БД !! Она может работать и в режиме эмуляции
1131
  // !!!!!!!! После que_get брать не [0] элемент, а first() - тогда можно в индекс элемента засовывать que_id из таблицы
1132
1133
1134
  // TODO - это вообще-то надо хранить в конфигурации
1135
  public static function db_get_user_player_username_last_registered() {
1136
    $user = static::db_query('SELECT * FROM {{users}} WHERE `user_as_ally` IS NULL ORDER BY `id` DESC', true);
1137
    static::cache_set(LOC_USER, $user);
1138
1139
    return isset($user['username']) ? $user['username'] : '';
1140
  }
1141
1142
  // Это для поиска по кэшу
1143
  protected static function db_get_record_by_field($location_type) {
0 ignored issues
show
Unused Code introduced by
The parameter $location_type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1144
  }
1145
1146
  // Для модулей - регистрация юнитов
1147
  public static function unit_register() {
1148
1149
  }
1150
1151
1152
  public static function init_0_prepare() {
1153
    // Отключаем magic_quotes
1154
    ini_get('magic_quotes_sybase') ? die('SN is incompatible with \'magic_quotes_sybase\' turned on. Disable it in php.ini or .htaccess...') : false;
1155
    if (@get_magic_quotes_gpc()) {
1156
      $gpcr = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
1157
      array_walk_recursive($gpcr, function (&$value, $key) {
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1158
        $value = stripslashes($value);
1159
      });
1160
    }
1161
    if (function_exists('set_magic_quotes_runtime')) {
1162
      @set_magic_quotes_runtime(0);
1163
      @ini_set('magic_quotes_runtime', 0);
1164
      @ini_set('magic_quotes_sybase', 0);
1165
    }
1166
  }
1167
1168
  public static function init_3_load_config_file() {
1169
    $dbsettings = array();
1170
1171
    require(SN_ROOT_PHYSICAL . "config" . DOT_PHP_EX);
1172
    self::$cache_prefix = !empty($dbsettings['cache_prefix']) ? $dbsettings['cache_prefix'] : $dbsettings['prefix'];
1173
    self::$db_name = $dbsettings['name'];
1174
    self::$sn_secret_word = $dbsettings['secretword'];
1175
    unset($dbsettings);
1176
  }
1177
1178
  public static function init_global_objects() {
1179
    /**
1180
     * @var classSupernova $supernova
1181
     */
1182
    global $supernova, $sn_cache;
1183
1184
    self::$user_options = new userOptions(0);
1185
1186
    /**
1187
     * @var classSupernova $supernova
1188
     */
1189
    $supernova = new classSupernova();
1190
1191
    // Initializing global 'cacher' object
1192
    static::$cache = new classCache(classSupernova::$cache_prefix);
1193
    $sn_cache = static::$cache;
1194
    empty($sn_cache->tables) ? sys_refresh_tablelist() : false;
1195
    empty($sn_cache->tables) ? die('DB error - cannot find any table. Halting...') : false;
1196
1197
    // Initializing global "config" object
1198
    classSupernova::$config = static::$config = new classConfig(classSupernova::$cache_prefix);
1199
  }
1200
1201
  public static function init_debug_state() {
1202
    if ($_SERVER['SERVER_NAME'] == 'localhost' && !defined('BE_DEBUG')) {
1203
      define('BE_DEBUG', true);
1204
    }
1205
    // define('DEBUG_SQL_ONLINE', true); // Полный дамп запросов в рил-тайме. Подойдет любое значение
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1206
    define('DEBUG_SQL_ERROR', true); // Выводить в сообщении об ошибке так же полный дамп запросов за сессию. Подойдет любое значение
1207
    define('DEBUG_SQL_COMMENT_LONG', true); // Добавлять SQL запрос длинные комментарии. Не зависим от всех остальных параметров. Подойдет любое значение
1208
    define('DEBUG_SQL_COMMENT', true); // Добавлять комментарии прямо в SQL запрос. Подойдет любое значение
1209
    // Включаем нужные настройки
1210
    defined('DEBUG_SQL_ONLINE') && !defined('DEBUG_SQL_ERROR') ? define('DEBUG_SQL_ERROR', true) : false;
1211
    defined('DEBUG_SQL_ERROR') && !defined('DEBUG_SQL_COMMENT') ? define('DEBUG_SQL_COMMENT', true) : false;
1212
    defined('DEBUG_SQL_COMMENT_LONG') && !defined('DEBUG_SQL_COMMENT') ? define('DEBUG_SQL_COMMENT', true) : false;
1213
1214
    if (defined('BE_DEBUG') || static::$config->debug) {
1215
      @define('BE_DEBUG', true);
1216
      @ini_set('display_errors', 1);
1217
      @error_reporting(E_ALL ^ E_NOTICE ^ E_DEPRECATED);
1218
    } else {
1219
      @define('BE_DEBUG', false);
1220
      @ini_set('display_errors', 0);
1221
    }
1222
1223
  }
1224
1225
}
1226