Completed
Push — work-fleets ( 6b7253...c0452c )
by SuperNova.WS
06:17
created

classSupernova::cache_clear()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 3
eloc 6
nc 2
nop 2
dl 0
loc 9
rs 9.6666
c 2
b 0
f 0
ccs 0
cts 7
cp 0
crap 12
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
  /**
435
   * @param      $query
436
   * @param bool $fetch
437
   * @param bool $skip_lock
438
   *
439
   * @return array|bool|mysqli_result|null
440
   */
441
  public static function db_query($query, $fetch = false, $skip_lock = false) {
442
    $select = strpos(strtoupper($query), 'SELECT') !== false;
443
444
    $query .= $select && $fetch ? ' LIMIT 1' : '';
445
    $query .= $select && !$skip_lock && static::db_transaction_check(false) ? ' FOR UPDATE' : '';
446
447
    $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...
448
449
    return $result;
450
  }
451
452
  /**
453
   * Возвращает информацию о записи по её ID
454
   *
455
   * @param int       $location_type
456
   * @param int|array $record_id_unsafe
457
   *    <p>int - ID записи</p>
458
   *    <p>array - запись пользователя с установленным полем P_ID</p>
459
   * @param bool      $for_update @deprecated
460
   * @param string    $fields @deprecated список полей или '*'/'' для всех полей
461
   * @param bool      $skip_lock Указывает на то, что не нужно блокировать запись //TODO и не нужно сохранять в кэше
462
   *
463
   * @return array|false
464
   *    <p>false - Нет записи с указанным ID</p>
465
   *    <p>array - запись</p>
466
   */
467
  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...
468
    $id_field = static::$location_info[$location_type][P_ID];
469
    $record_id_safe = idval(is_array($record_id_unsafe) && isset($record_id_unsafe[$id_field]) ? $record_id_unsafe[$id_field] : $record_id_unsafe);
470
471
    return static::db_get_record_list($location_type, "`{$id_field}` = {$record_id_safe}", true, false);
472
  }
473
474
  public static function db_get_record_list($location_type, $filter = '', $fetch = false, $no_return = false) {
475
    $query_cache = &static::$queries[$location_type][$filter];
476
477
    if (!isset($query_cache) || $query_cache === null) {
478
      $location_info = &static::$location_info[$location_type];
479
      $id_field = $location_info[P_ID];
480
      $query_cache = array();
481
482
      if (static::db_transaction_check(false)) {
483
        // Проходим по всем родителям данной записи
484
        foreach ($location_info[P_OWNER_INFO] as $owner_data) {
485
          $owner_location_type = $owner_data[P_LOCATION];
486
          $parent_id_list = array();
487
          // Выбираем родителей данного типа и соответствующие ИД текущего типа
488
          $query = static::db_query(
489
            "SELECT
490
              distinct({{{$location_info[P_TABLE_NAME]}}}.{$owner_data[P_OWNER_FIELD]}) AS parent_id
491
            FROM {{{$location_info[P_TABLE_NAME]}}}" .
492
            ($filter ? ' WHERE ' . $filter : '') .
493
            ($fetch ? ' LIMIT 1' : ''), false, true);
494
495
          while($row = db_fetch($query)) {
496
            // Исключаем из списка родительских ИД уже заблокированные записи
497
            if (!static::cache_lock_get($owner_location_type, $row['parent_id'])) {
498
              $parent_id_list[$row['parent_id']] = $row['parent_id'];
499
            }
500
          }
501
          // Если все-таки какие-то записи еще не заблокированы - вынимаем текущие версии из базы
502
          if ($indexes_str = implode(',', $parent_id_list)) {
503
            $parent_id_field = static::$location_info[$owner_location_type][P_ID];
504
            static::db_get_record_list($owner_location_type,
505
              $parent_id_field . (count($parent_id_list) > 1 ? " IN ({$indexes_str})" : " = {$indexes_str}"), $fetch, true);
506
          }
507
        }
508
      }
509
510
      $query = static::db_query(
511
        "SELECT * FROM {{{$location_info[P_TABLE_NAME]}}}" .
512
        (($filter = trim($filter)) ? " WHERE {$filter}" : '')
513
      );
514
      while($row = db_fetch($query)) {
515
        static::cache_set($location_type, $row);
516
        $query_cache[$row[$id_field]] = &static::$data[$location_type][$row[$id_field]];
517
      }
518
    }
519
520
    if ($no_return) {
521
      return true;
522
    } else {
523
      $result = false;
524
      if (is_array($query_cache)) {
525
        foreach ($query_cache as $key => $value) {
526
          $result[$key] = $value;
527
          if ($fetch) {
528
            break;
529
          }
530
        }
531
      }
532
533
      return $fetch ? (is_array($result) ? reset($result) : false) : $result;
534
    }
535
  }
536
537
  /**
538
   * @param int    $location_type
539
   * @param int    $record_id
540
   * @param string $set - SQL SET structure
541
   *
542
   * @return array|bool|mysqli_result|null
543
   */
544
  public static function db_upd_record_by_id($location_type, $record_id, $set) {
545
    if (!($record_id = idval($record_id)) || !($set = trim($set))) {
546
      return false;
547
    }
548
549
    $location_info = &static::$location_info[$location_type];
550
    $id_field = $location_info[P_ID];
551
    $table_name = $location_info[P_TABLE_NAME];
552
    if ($result = static::db_query($q = "UPDATE {{{$table_name}}} SET {$set} WHERE `{$id_field}` = {$record_id}")) // TODO Как-то вернуть может быть LIMIT 1 ?
553
    {
554
      if (static::$db->db_affected_rows()) {
555
        // Обновляем данные только если ряд был затронут
556
        // TODO - переделать под работу со структурированными $set
557
558
        // Тут именно так, а не cache_unset - что бы в кэшах автоматически обновилась запись. Будет нужно на будущее
559
        static::$data[$location_type][$record_id] = null;
560
        // Вытаскиваем обновленную запись
561
        static::db_get_record_by_id($location_type, $record_id);
562
        static::cache_clear($location_type, false); // Мягкий сброс - только $queries
563
      }
564
    }
565
566
    return $result;
567
  }
568
569
  public static function db_upd_record_list($location_type, $condition, $set) {
570
    if (!($set = trim($set))) {
571
      return false;
572
    }
573
574
    $condition = trim($condition);
575
    $table_name = static::$location_info[$location_type][P_TABLE_NAME];
576
577
    if ($result = static::db_query("UPDATE {{{$table_name}}} SET " . $set . ($condition ? ' WHERE ' . $condition : ''))) {
578
579
      if (static::$db->db_affected_rows()) { // Обновляем данные только если ряд был затронут
580
        // Поскольку нам неизвестно, что и как обновилось - сбрасываем кэш этого типа полностью
581
        // TODO - когда будет структурированный $condition и $set - перепаковывать данные
582
        static::cache_clear($location_type, true);
583
      }
584
    }
585
586
    return $result;
587
  }
588
589
  /**
590
   * @param int    $location_type
591
   * @param string $set
592
   *
593
   * @return array|bool|false|mysqli_result|null
594
   */
595
  public static function db_ins_record($location_type, $set) {
596
    $set = trim($set);
597
    $table_name = static::$location_info[$location_type][P_TABLE_NAME];
598 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...
599
      if (static::$db->db_affected_rows()) // Обновляем данные только если ряд был затронут
600
      {
601
        $record_id = db_insert_id();
602
        // Вытаскиваем запись целиком, потому что в $set могли быть "данные по умолчанию"
603
        $result = static::db_get_record_by_id($location_type, $record_id);
604
        // Очищаем второстепенные кэши - потому что вставленная запись могла повлиять на результаты запросов или локация или еще чего
605
        // TODO - когда будет поддержка изменения индексов и локаций - можно будет вызывать её
606
        static::cache_clear($location_type, false); // Мягкий сброс - только $queries
607
      }
608
    }
609
610
    return $result;
611
  }
612
613
  public static function db_ins_field_set($location_type, $field_set, $serialize = false) {
614
    // TODO multiinsert
615
    !sn_db_field_set_is_safe($field_set) ? $field_set = sn_db_field_set_make_safe($field_set, $serialize) : false;
616
    sn_db_field_set_safe_flag_clear($field_set);
617
    $values = implode(',', $field_set);
618
    $fields = implode(',', array_keys($field_set));
619
620
    $table_name = static::$location_info[$location_type][P_TABLE_NAME];
621 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...
622
      if (static::$db->db_affected_rows()) {
623
        // Обновляем данные только если ряд был затронут
624
        $record_id = db_insert_id();
625
        // Вытаскиваем запись целиком, потому что в $set могли быть "данные по умолчанию"
626
        $result = static::db_get_record_by_id($location_type, $record_id);
627
        // Очищаем второстепенные кэши - потому что вставленная запись могла повлиять на результаты запросов или локация или еще чего
628
        // TODO - когда будет поддержка изменения индексов и локаций - можно будет вызывать её
629
        static::cache_clear($location_type, false); // Мягкий сброс - только $queries
630
      }
631
    }
632
633
    return $result;
634
  }
635
636
  public static function db_del_record_by_id($location_type, $safe_record_id) {
637
    if (!($safe_record_id = idval($safe_record_id))) {
638
      return false;
639
    }
640
641
    $location_info = &static::$location_info[$location_type];
642
    $id_field = $location_info[P_ID];
643
    $table_name = $location_info[P_TABLE_NAME];
644
    if ($result = static::db_query("DELETE FROM `{{{$table_name}}}` WHERE `{$id_field}` = {$safe_record_id}")) {
645
      // Обновляем данные только если ряд был затронут
646
      if (static::$db->db_affected_rows()) {
647
        static::cache_unset($location_type, $safe_record_id);
648
      }
649
    }
650
651
    return $result;
652
  }
653
654
  public static function db_del_record_list($location_type, $condition) {
655
    if (!($condition = trim($condition))) {
656
      return false;
657
    }
658
659
    $location_info = &static::$location_info[$location_type];
660
    $table_name = $location_info[P_TABLE_NAME];
661
662
    if ($result = static::db_query("DELETE FROM `{{{$table_name}}}` WHERE {$condition}")) {
663
      // Обновляем данные только если ряд был затронут
664
      if (static::$db->db_affected_rows()) {
665
        // Обнуление кэша, потому что непонятно, что поменялось
666
        // TODO - когда будет структурированный $condition можно будет делать только cache_unset по нужным записям
667
        static::cache_clear($location_type);
668
      }
669
    }
670
671
    return $result;
672
  }
673
674
675
676
  // Работа с пользователями
677
  /**
678
   * Возвращает информацию о пользователе по его ID
679
   *
680
   * @param int|array $user_id_unsafe
681
   *    <p>int - ID пользователя</p>
682
   *    <p>array - запись пользователя с установленным полем ['id']</p>
683
   * @param bool      $for_update @deprecated
684
   * @param string    $fields @deprecated список полей или '*'/'' для всех полей
685
   * @param null      $player
686
   * @param bool|null $player Признак выбора записи пользователь типа "игрок"
687
   *    <p>null - Можно выбрать запись любого типа</p>
688
   *    <p>true - Выбирается только запись типа "игрок"</p>
689
   *    <p>false - Выбирается только запись типа "альянс"</p>
690
   *
691
   * @return array|false
692
   *    <p>false - Нет записи с указанным ID и $player</p>
693
   *    <p>array - запись типа $user</p>
694
   */
695
  public static function db_get_user_by_id($user_id_unsafe, $for_update = false, $fields = '*', $player = null) {
696
    $user = static::db_get_record_by_id(LOC_USER, $user_id_unsafe, $for_update, $fields);
697
698
    return (is_array($user) &&
699
      (
700
        $player === null
701
        ||
702
        ($player === true && !$user['user_as_ally'])
703
        ||
704
        ($player === false && $user['user_as_ally'])
705
      )) ? $user : false;
706
  }
707
708
  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...
709
    // TODO Проверить, кстати - а везде ли нужно выбирать юзеров или где-то все-таки ищутся Альянсы ?
710
    if (!($username_unsafe = trim($username_unsafe))) {
711
      return false;
712
    }
713
714
    $user = null;
715
    if (is_array(static::$data[LOC_USER])) {
716
      foreach (static::$data[LOC_USER] as $user_id => $user_data) {
717
        if (is_array($user_data) && isset($user_data['username'])) {
718
          // проверяем поле
719
          // TODO Возможно есть смысл всегда искать по strtolower - но может игрок захочет переименоваться с другим регистром? Проверить!
720
          if ((!$like && $user_data['username'] == $username_unsafe) || ($like && strtolower($user_data['username']) == strtolower($username_unsafe))) {
721
            // $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...
722
            $user_as_ally = idval($user_data['user_as_ally']);
723
            if ($player === null || ($player === true && !$user_as_ally) || ($player === false && $user_as_ally)) {
724
              $user = $user_data;
725
              break;
726
            }
727
          }
728
        }
729
      }
730
    }
731
732
    if ($user === null) {
733
      // Вытаскиваем запись
734
      $username_safe = db_escape($like ? strtolower($username_unsafe) : $username_unsafe); // тут на самом деле strtolower() лишняя, но пусть будет
735
736
      // TODO переписать
737
      $user = self::$db->selectRow(
738
        DBStaticUser::buildSelect()
739
          ->field('*')
740
          ->where(array("`username` " . ($like ? 'LIKE' : '=') . " '{$username_safe}'"))
741
          ->setFetchOne()
742
      );
743
744
      if(empty($user)) {
745
        $user = null;
746
      }
747
748
//      $user = static::db_query(
0 ignored issues
show
Unused Code Comprehensibility introduced by
46% 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...
749
//        "SELECT * FROM {{users}} WHERE `username` " . ($like ? 'LIKE' : '=') . " '{$username_safe}'"
750
//        , true);
751
      static::cache_set(LOC_USER, $user); // В кэш-юзер так же заполнять индексы
752
    }
753
754
    return $user;
755
  }
756
757
  // UNUSED
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...
758
//  public static function db_get_user_by_email($email_unsafe, $use_both = false, $for_update = false, $fields = '*') {
759
//    if (!($email_unsafe = strtolower(trim($email_unsafe)))) {
760
//      return false;
761
//    }
762
//
763
//    $user = null;
764
//    // TODO переделать на индексы
765
//    if (is_array(static::$data[LOC_USER])) {
766
//      foreach (static::$data[LOC_USER] as $user_id => $user_data) {
767
//        if (is_array($user_data) && isset($user_data['email_2'])) {
768
//          // проверяем поле
769
//          if (strtolower($user_data['email_2']) == $email_unsafe || ($use_both && strtolower($user_data['email']) == $email_unsafe)) {
770
//            $user = $user_data;
771
//            break;
772
//          }
773
//        }
774
//      }
775
//    }
776
//
777
//    if ($user === null) {
778
//      // Вытаскиваем запись
779
//      $email_safe = db_escape($email_unsafe);
780
//      $user = static::db_query(
781
//        "SELECT * FROM {{users}} WHERE LOWER(`email_2`) = '{$email_safe}'" .
782
//        ($use_both ? " OR LOWER(`email`) = '{$email_safe}'" : '')
783
//        , true);
784
//
785
//      static::cache_set(LOC_USER, $user); // В кэш-юзер так же заполнять индексы
786
//    }
787
//
788
//    return $user;
789
//  }
790
791
  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...
792
    $user = null;
793
    // TODO переделать на индексы
794
795
    if ($user === null && !empty($where_safe)) {
796
      // Вытаскиваем запись
797
      $user = static::db_query("SELECT * FROM {{users}} WHERE {$where_safe}", true);
798
799
      static::cache_set(LOC_USER, $user); // В кэш-юзер так же заполнять индексы
800
    }
801
802
    return $user;
803
  }
804
805
806 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...
807
    $date = is_numeric($date) ? "FROM_UNIXTIME({$date})" : "'{$date}'";
808
809
    return
810
      "(unit_time_start IS NULL OR unit_time_start <= {$date}) AND
811
    (unit_time_finish IS NULL OR unit_time_finish = '1970-01-01 03:00:00' OR unit_time_finish >= {$date})";
812
  }
813
814
  public static function db_get_unit_by_id($unit_id, $for_update = false, $fields = '*') {
815
    // 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...
816
    $unit = static::db_get_record_by_id(LOC_UNIT, $unit_id, $for_update, $fields);
817
    if (is_array($unit)) {
818
      static::$locator[LOC_UNIT][$unit['unit_location_type']][$unit['unit_location_id']][$unit['unit_snid']] = &static::$data[LOC_UNIT][$unit_id];
819
    }
820
821
    return $unit;
822
  }
823
824
  /**
825
   * @param int $user_id
826
   * @param     $location_type
827
   * @param     $location_id
828
   *
829
   * @return array|bool
830
   */
831
  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...
832
    if (!($location_type = idval($location_type)) || !($location_id = idval($location_id))) {
833
      return false;
834
    }
835
836
    $query_cache = &static::$locator[LOC_UNIT][$location_type][$location_id];
837
    if (!isset($query_cache)) {
838
      $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());
839
      if (is_array($got_data)) {
840
        foreach ($got_data as $unit_id => $unit_data) {
841
          $query_cache[$unit_data['unit_snid']] = &static::$data[LOC_UNIT][$unit_id];
842
        }
843
      }
844
    }
845
846
    $result = false;
847
    if (is_array($query_cache)) {
848
      foreach ($query_cache as $key => $value) {
849
        $result[$key] = $value;
850
      }
851
    }
852
853
    return $result;
854
  }
855
856
  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...
857
    static::db_get_unit_list_by_location($user_id, $location_type, $location_id);
858
859
    return $unit_snid ? static::$locator[LOC_UNIT][$location_type][$location_id][$unit_snid] : static::$locator[LOC_UNIT][$location_type][$location_id];
860
  }
861
862
863
  /*
864
   * С $for_update === true эта функция должна вызываться только из транзакции! Все соответствующие записи в users и planets должны быть уже блокированы!
865
   *
866
   * $que_type
867
   *   !$que_type - все очереди
868
   *   QUE_XXXXXX - конкретная очередь по планете
869
   * $user_id - ID пользователя
870
   * $planet_id
871
   *   $que_type == QUE_RESEARCH - игнорируется
872
   *   null - обработка очередей планет не производится
873
   *   false/0 - обрабатываются очереди всех планет по $user_id
874
   *   (integer) - обрабатываются локальные очереди для планеты. Нужно, например, в обработчике флотов
875
   *   иначе - $que_type для указанной планеты
876
   * $for_update - true == нужно блокировать записи
877
   *
878
   * TODO Работа при !$user_id
879
   * TODO Переформатировать вывод данных, что бы можно было возвращать данные по всем планетам и юзерам в одном запросе: добавить подмассивы 'que', 'planets', 'players'
880
   *
881
   */
882
  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...
883
    if (!$user_id) {
884
      pdump(debug_backtrace());
885
      die('No user_id for que_get_que()');
886
    }
887
888
    $ques = array();
889
890
    $query = array();
891
892
    if ($user_id = idval($user_id)) {
893
      $query[] = "`que_player_id` = {$user_id}";
894
    }
895
896
    if ($que_type == QUE_RESEARCH || $planet_id === null) {
897
      $query[] = "`que_planet_id` IS NULL";
898
    } elseif ($planet_id) {
899
      $query[] = "(`que_planet_id` = {$planet_id}" . ($que_type ? '' : ' OR que_planet_id IS NULL') . ")";
900
    }
901
    if ($que_type) {
902
      $query[] = "`que_type` = {$que_type}";
903
    }
904
905
    $ques['items'] = static::db_get_record_list(LOC_QUE, implode(' AND ', $query));
906
907
    return que_recalculate($ques);
908
  }
909
910
911 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...
912
    if (!is_array($user)) {
913
      // TODO - remove later
914
      print('<h1>СООБЩИТЕ ЭТО АДМИНУ: sn_db_unit_changeset_prepare() - USER is not ARRAY</h1>');
915
      pdump(debug_backtrace());
916
      die('USER is not ARRAY');
917
    }
918
    if (!isset($user['id']) || !$user['id']) {
919
      // TODO - remove later
920
      print('<h1>СООБЩИТЕ ЭТО АДМИНУ: sn_db_unit_changeset_prepare() - USER[id] пустой</h1>');
921
      pdump($user);
922
      pdump(debug_backtrace());
923
      die('USER[id] пустой');
924
    }
925
    $planet_id = is_array($planet_id) && isset($planet_id['id']) ? $planet_id['id'] : $planet_id;
926
927
    $unit_location = sys_get_unit_location($user, array(), $unit_id);
928
    $location_id = $unit_location == LOC_USER ? $user['id'] : $planet_id;
929
    $location_id = $location_id ? $location_id : 'NULL';
930
931
    $temp = DBStaticUnit::db_unit_by_location($user['id'], $unit_location, $location_id, $unit_id, true, 'unit_id');
932
    if ($temp['unit_id']) {
933
      $db_changeset = array(
934
        'action'  => SQL_OP_UPDATE,
935
        P_VERSION => 1,
936
        'where'   => array(
937
          "unit_id" => $temp['unit_id'],
938
        ),
939
        'fields'  => array(
940
          'unit_level' => array(
941
            'delta' => $unit_value
942
          ),
943
        ),
944
      );
945
    } else {
946
      $db_changeset = array(
947
        'action' => SQL_OP_INSERT,
948
        'fields' => array(
949
          'unit_player_id'     => array(
950
            'set' => $user['id'],
951
          ),
952
          'unit_location_type' => array(
953
            'set' => $unit_location,
954
          ),
955
          'unit_location_id'   => array(
956
            'set' => $unit_location == LOC_USER ? $user['id'] : $planet_id,
957
          ),
958
          'unit_type'          => array(
959
            'set' => get_unit_param($unit_id, P_UNIT_TYPE),
960
          ),
961
          'unit_snid'          => array(
962
            'set' => $unit_id,
963
          ),
964
          'unit_level'         => array(
965
            'set' => $unit_value,
966
          ),
967
        ),
968
      );
969
    }
970
971
    return $db_changeset;
972
  }
973
974
975
  public function db_changeset_delay($table_name, $table_data) {
976
    // TODO Применять ченджсет к записям
977
    static::$delayed_changset[$table_name] = is_array(static::$delayed_changset[$table_name]) ? static::$delayed_changset[$table_name] : array();
978
    // TODO - На самом деле дурацкая оптимизация, если честно - может быть идентичные записи с идентичными дельтами - и привет. Но не должны, конечно
979
    static::$delayed_changset[$table_name] = array_merge(static::$delayed_changset[$table_name], $table_data);
980
  }
981
982
  public function db_changeset_revert() {
983
    // TODO Для этапа 1 - достаточно чистить только те таблицы, что были затронуты
984
    // Для этапа 2 - чистить только записи
985
    // Для этапа 3 - возвращать всё
986
    static::cache_clear_all(true);
987
  }
988
989
  public function db_changeset_condition_compile(&$conditions, &$table_name = '') {
990
    if (!$conditions[P_LOCATION] || $conditions[P_LOCATION] == LOC_NONE) {
991
      $conditions[P_LOCATION] = LOC_NONE;
992
      switch($table_name) {
993
        case 'users':
994
        case LOC_USER:
995
          $conditions[P_TABLE_NAME] = $table_name = 'users';
996
          $conditions[P_LOCATION] = LOC_USER;
997
        break;
998
999
        case 'planets':
1000
        case LOC_PLANET:
1001
          $conditions[P_TABLE_NAME] = $table_name = 'planets';
1002
          $conditions[P_LOCATION] = LOC_PLANET;
1003
        break;
1004
1005
        case 'unit':
1006
        case LOC_UNIT:
1007
          $conditions[P_TABLE_NAME] = $table_name = 'unit';
1008
          $conditions[P_LOCATION] = LOC_UNIT;
1009
        break;
1010
      }
1011
    }
1012
1013
    $conditions[P_FIELDS_STR] = '';
1014
    if ($conditions['fields']) {
1015
      $fields = array();
1016 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...
1017
        $condition = "`{$field_name}` = ";
1018
        $value = '';
1019
        if ($field_data['delta']) {
1020
          $value = "`{$field_name}`" . ($field_data['delta'] >= 0 ? '+' : '') . $field_data['delta'];
1021
        } elseif ($field_data['set']) {
1022
          $value = (is_string($field_data['set']) ? "'{$field_data['set']}'" : $field_data['set']);
1023
        }
1024
1025
        if ($value) {
1026
          $fields[] = $condition . $value;
1027
        }
1028
      }
1029
      $conditions[P_FIELDS_STR] = implode(',', $fields);
1030
    }
1031
1032
    $conditions[P_WHERE_STR] = '';
1033
    if (!empty($conditions['where'])) {
1034
      if ($conditions[P_VERSION] == 1) {
1035
        $the_conditions = array();
1036
        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...
1037
          // Простое условие - $field_id = $field_value
1038
          if (is_string($field_id)) {
1039
            $field_value =
1040
              $field_value === null ? 'NULL' :
1041
                (is_string($field_value) ? "'" . db_escape($field_value) . "'" :
1042
                  (is_bool($field_value) ? intval($field_value) : $field_value));
1043
            $the_conditions[] = "`{$field_id}` = {$field_value}";
1044
          } else {
1045
            die('Неподдерживаемый тип условия');
1046
          }
1047
        }
1048
      } else {
1049
        $the_conditions = &$conditions['where'];
1050
      }
1051
      $conditions[P_WHERE_STR] = implode(' AND ', $the_conditions);
1052
    }
1053
1054
    switch($conditions['action']) {
1055
      case SQL_OP_DELETE:
1056
        $conditions[P_ACTION_STR] = ("DELETE FROM {{{$table_name}}}");
1057
      break;
1058
      case SQL_OP_UPDATE:
1059
        $conditions[P_ACTION_STR] = ("UPDATE {{{$table_name}}} SET");
1060
      break;
1061
      case SQL_OP_INSERT:
1062
        $conditions[P_ACTION_STR] = ("INSERT INTO {{{$table_name}}} SET");
1063
      break;
1064
      // 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...
1065
      default:
1066
        die('Неподдерживаемая операция в classSupernova::db_changeset_condition_compile');
1067
    }
1068
1069
    $conditions[P_QUERY_STR] = $conditions[P_ACTION_STR] . ' ' . $conditions[P_FIELDS_STR] . (' WHERE ' . $conditions[P_WHERE_STR]);
1070
  }
1071
1072
  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...
1073
    $result = true;
1074
    if (!is_array($db_changeset) || empty($db_changeset)) {
1075
      return $result;
1076
    }
1077
1078
    foreach ($db_changeset as $table_name => &$table_data) {
1079
      // TODO - delayed changeset
1080
      foreach ($table_data as $record_id => &$conditions) {
1081
        static::db_changeset_condition_compile($conditions, $table_name);
1082
1083
        if ($conditions['action'] != SQL_OP_DELETE && !$conditions[P_FIELDS_STR]) {
1084
          continue;
1085
        }
1086
        if ($conditions['action'] == SQL_OP_DELETE && !$conditions[P_WHERE_STR]) {
1087
          continue;
1088
        } // Защита от случайного удаления всех данных в таблице
1089
1090
        if ($conditions[P_LOCATION] != LOC_NONE) {
1091
          switch($conditions['action']) {
1092
            case SQL_OP_DELETE:
1093
              $result = self::db_del_record_list($conditions[P_LOCATION], $conditions[P_WHERE_STR]) && $result;
1094
            break;
1095
            case SQL_OP_UPDATE:
1096
              $result = self::db_upd_record_list($conditions[P_LOCATION], $conditions[P_WHERE_STR], $conditions[P_FIELDS_STR]) && $result;
1097
            break;
1098
            case SQL_OP_INSERT:
1099
              $result = self::db_ins_record($conditions[P_LOCATION], $conditions[P_FIELDS_STR]) && $result;
1100
            break;
1101
            default:
1102
              die('Неподдерживаемая операция в classSupernova::db_changeset_apply');
1103
            // 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...
1104
          }
1105
        } else {
1106
          $result = doquery($conditions[P_QUERY_STR]) && $result;
1107
        }
1108
      }
1109
    }
1110
1111
    return $result;
1112
  }
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
  // que_process не всегда должна работать в режиме прямой работы с БД !! Она может работать и в режиме эмуляции
1149
  // !!!!!!!! После que_get брать не [0] элемент, а first() - тогда можно в индекс элемента засовывать que_id из таблицы
1150
1151
1152
  // Это для поиска по кэшу
1153
  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...
1154
  }
1155
1156
  // Для модулей - регистрация юнитов
1157
  public static function unit_register() {
1158
1159
  }
1160
1161
1162
  public static function init_0_prepare() {
1163
    // Отключаем magic_quotes
1164
    ini_get('magic_quotes_sybase') ? die('SN is incompatible with \'magic_quotes_sybase\' turned on. Disable it in php.ini or .htaccess...') : false;
1165
    if (@get_magic_quotes_gpc()) {
1166
      $gpcr = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
1167
      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...
1168
        $value = stripslashes($value);
1169
      });
1170
    }
1171
    if (function_exists('set_magic_quotes_runtime')) {
1172
      @set_magic_quotes_runtime(0);
1173
      @ini_set('magic_quotes_runtime', 0);
1174
      @ini_set('magic_quotes_sybase', 0);
1175
    }
1176
  }
1177
1178
  public static function init_3_load_config_file() {
1179
    $dbsettings = array();
1180
1181
    require(SN_ROOT_PHYSICAL . "config" . DOT_PHP_EX);
1182
    self::$cache_prefix = !empty($dbsettings['cache_prefix']) ? $dbsettings['cache_prefix'] : $dbsettings['prefix'];
1183
    self::$db_name = $dbsettings['name'];
1184
    self::$sn_secret_word = $dbsettings['secretword'];
1185
    unset($dbsettings);
1186
  }
1187
1188
  public static function init_global_objects() {
1189
    /**
1190
     * @var classSupernova $supernova
1191
     */
1192
    global $supernova, $sn_cache;
1193
1194
    self::$user_options = new userOptions(0);
1195
1196
    /**
1197
     * @var classSupernova $supernova
1198
     */
1199
    $supernova = new classSupernova();
1200
1201
    // Initializing global 'cacher' object
1202
    static::$cache = new classCache(classSupernova::$cache_prefix);
1203
    $sn_cache = static::$cache;
1204
    empty($sn_cache->tables) ? sys_refresh_tablelist() : false;
1205
    empty($sn_cache->tables) ? die('DB error - cannot find any table. Halting...') : false;
1206
1207
    // Initializing global "config" object
1208
    classSupernova::$config = static::$config = new classConfig(classSupernova::$cache_prefix);
1209
  }
1210
1211
  public static function init_debug_state() {
1212
    if ($_SERVER['SERVER_NAME'] == 'localhost' && !defined('BE_DEBUG')) {
1213
      define('BE_DEBUG', true);
1214
    }
1215
    // 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...
1216
    define('DEBUG_SQL_ERROR', true); // Выводить в сообщении об ошибке так же полный дамп запросов за сессию. Подойдет любое значение
1217
    define('DEBUG_SQL_COMMENT_LONG', true); // Добавлять SQL запрос длинные комментарии. Не зависим от всех остальных параметров. Подойдет любое значение
1218
    define('DEBUG_SQL_COMMENT', true); // Добавлять комментарии прямо в SQL запрос. Подойдет любое значение
1219
    // Включаем нужные настройки
1220
    defined('DEBUG_SQL_ONLINE') && !defined('DEBUG_SQL_ERROR') ? define('DEBUG_SQL_ERROR', true) : false;
1221
    defined('DEBUG_SQL_ERROR') && !defined('DEBUG_SQL_COMMENT') ? define('DEBUG_SQL_COMMENT', true) : false;
1222
    defined('DEBUG_SQL_COMMENT_LONG') && !defined('DEBUG_SQL_COMMENT') ? define('DEBUG_SQL_COMMENT', true) : false;
1223
1224
    if (defined('BE_DEBUG') || static::$config->debug) {
1225
      @define('BE_DEBUG', true);
1226
      @ini_set('display_errors', 1);
1227
      @error_reporting(E_ALL ^ E_NOTICE ^ E_DEPRECATED);
1228
    } else {
1229
      @define('BE_DEBUG', false);
1230
      @ini_set('display_errors', 0);
1231
    }
1232
1233
  }
1234
1235
}
1236