Completed
Push — work-fleets ( d64c53...5442ac )
by SuperNova.WS
05:10
created

classSupernova::db_lock_tables()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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