Completed
Push — work-fleets ( 2bd11a...17dd3b )
by SuperNova.WS
06:36
created

classSupernova::db_transaction_start()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 7
Bugs 0 Features 0
Metric Value
cc 3
eloc 12
c 7
b 0
f 0
nc 4
nop 1
dl 0
loc 19
ccs 0
cts 14
cp 0
crap 12
rs 9.4285
1
<?php
2
3
use Vector\Vector;
4
5
use Common\GlobalContainer;
6
7
class classSupernova {
8
  /**
9
   * @var GlobalContainer $gc
10
   */
11
  public static $gc;
12
13
  /**
14
   * ex $sn_mvc
15
   *
16
   * @var array
17
   */
18
  public static $sn_mvc = array();
19
20
  /**
21
   * ex $functions
22
   *
23
   * @var array
24
   */
25
  public static $functions = array();
26
27
  /**
28
   * @var array[] $design
29
   */
30
  public static $design = array(
31
    'bbcodes' => array(),
32
    'smiles'  => array(),
33
  );
34
35
  /**
36
   * Основная БД для доступа к данным
37
   *
38
   * @var db_mysql $db
39
   */
40
  public static $db;
41
  public static $db_name = '';
42
43
  /**
44
   * @var \DBAL\DbTransaction
45
   */
46
  public static $transaction;
47
48
  /**
49
   * @var SnCache $dbCache
50
   */
51
  public static $dbCache;
52
53
  /**
54
   * Настройки из файла конфигурации
55
   *
56
   * @var string
57
   */
58
  public static $cache_prefix = '';
59
60
  public static $sn_secret_word = '';
61
62
  /**
63
   * Конфигурация игры
64
   *
65
   * @var classConfig $config
66
   */
67
  public static $config;
68
69
70
  /**
71
   * Кэш игры
72
   *
73
   * @var classCache $cache
74
   */
75
  public static $cache;
76
77
78
  /**
79
   * @var core_auth $auth
80
   */
81
  public static $auth = null;
82
83
84
  public static $user = array();
85
  /**
86
   * @var userOptions
87
   */
88
  public static $user_options;
89
90
  /**
91
   * @var debug $debug
92
   */
93
  public static $debug = null;
94
95
  public static $options = array();
96
97
  public static $delayed_changset = array(); // Накопительный массив изменений
98
99
  // Кэш индексов - ключ MD5-строка от суммы ключевых строк через | - менять | на что-то другое перед поиском и назад - после поиска
100
  // Так же в индексах могут быть двойные вхождения - например, названия планет да и вообще
101
  // Придумать спецсимвол для NULL
102
103
  /*
104
  TODO Кэш:
105
  1. Всегда дешевле использовать процессор, чем локальную память
106
  2. Всегда дешевле использовать локальную память, чем общую память всех процессов
107
  3. Всегда дешевле использовать общую память всех процессов, чем обращаться к БД
108
109
  Кэш - многоуровневый: локальная память-общая память-БД
110
  БД может быть сверхкэширующей - см. HyperNova. Это реализуется на уровне СН-драйвера БД
111
  Предусмотреть вариант, когда уровни кэширования совпадают, например когда нет xcache и используется общая память
112
  */
113
114
  // TODO Автоматически заполнять эту таблицу. В случае кэша в памяти - делать show table при обращении к таблице
115
  public static $location_info = array(
116
    LOC_USER => array(
117
      P_TABLE_NAME => 'users',
118
      P_ID         => 'id',
119
      P_OWNER_INFO => array(),
120
    ),
121
122
    LOC_PLANET => array(
123
      P_TABLE_NAME => 'planets',
124
      P_ID         => 'id',
125
      P_OWNER_INFO => array(
126
        LOC_USER => array(
127
          P_LOCATION    => LOC_USER,
128
          P_OWNER_FIELD => 'id_owner',
129
        ),
130
      ),
131
    ),
132
133
    LOC_UNIT => array(
134
      P_TABLE_NAME => 'unit',
135
      P_ID         => 'unit_id',
136
      P_OWNER_INFO => array(
137
        LOC_USER => array(
138
          P_LOCATION    => LOC_USER,
139
          P_OWNER_FIELD => 'unit_player_id',
140
        ),
141
      ),
142
    ),
143
144
    LOC_QUE => array(
145
      P_TABLE_NAME => 'que',
146
      P_ID         => 'que_id',
147
      P_OWNER_INFO => array(
148
        array(
149
          P_LOCATION    => LOC_USER,
150
          P_OWNER_FIELD => 'que_player_id',
151
        ),
152
153
        array(
154
          P_LOCATION    => LOC_PLANET,
155
          P_OWNER_FIELD => 'que_planet_id_origin',
156
        ),
157
158
        array(
159
          P_LOCATION    => LOC_PLANET,
160
          P_OWNER_FIELD => 'que_planet_id',
161
        ),
162
      ),
163
    ),
164
165
    LOC_FLEET => array(
166
      P_TABLE_NAME => 'fleets',
167
      P_ID         => 'fleet_id',
168
      P_OWNER_INFO => array(
169
        array(
170
          P_LOCATION    => LOC_USER,
171
          P_OWNER_FIELD => 'fleet_owner',
172
        ),
173
174
        array(
175
          P_LOCATION    => LOC_USER,
176
          P_OWNER_FIELD => 'fleet_target_owner',
177
        ),
178
179
        array(
180
          P_LOCATION    => LOC_PLANET,
181
          P_OWNER_FIELD => 'fleet_start_planet_id',
182
        ),
183
184
        array(
185
          P_LOCATION    => LOC_PLANET,
186
          P_OWNER_FIELD => 'fleet_end_planet_id',
187
        ),
188
      ),
189
    ),
190
  );
191
192
193
  public static function log_file($message, $spaces = 0) {
194
    if (self::$debug) {
195
      self::$debug->log_file($message, $spaces);
196
    }
197
  }
198
199
200
  /**
201
   * Блокирует указанные таблицу/список таблиц
202
   *
203
   * @param string|array $tables Таблица/список таблиц для блокировки. Названия таблиц - без префиксов
204
   * <p>string - название таблицы для блокировки</p>
205
   * <p>array - массив, где ключ - имя таблицы, а значение - условия блокировки элементов</p>
206
   */
207
  public static function db_lock_tables($tables) {
208
    $tables = is_array($tables) ? $tables : array($tables => '');
209
    foreach ($tables as $table_name => $condition) {
210
      self::$db->doSelect("SELECT 1 FROM {{{$table_name}}}" . ($condition ? ' WHERE ' . $condition : ''));
211
    }
212
  }
213
214
  /**
215
   * Возвращает информацию о записи по её ID
216
   *
217
   * @param int       $location_type
218
   * @param int|array $record_id_unsafe
219
   *    <p>int - ID записи</p>
220
   *    <p>array - запись пользователя с установленным полем P_ID</p>
221
   * @param bool      $for_update @deprecated
222
   * @param string    $fields @deprecated список полей или '*'/'' для всех полей
223
   * @param bool      $skip_lock Указывает на то, что не нужно блокировать запись //TODO и не нужно сохранять в кэше
224
   *
225
   * @return array|false
226
   *    <p>false - Нет записи с указанным ID</p>
227
   *    <p>array - запись</p>
228
   */
229
  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...
230
    $id_field = static::$location_info[$location_type][P_ID];
231
    $record_id_safe = idval(is_array($record_id_unsafe) && isset($record_id_unsafe[$id_field]) ? $record_id_unsafe[$id_field] : $record_id_unsafe);
232
233
    return static::db_get_record_list($location_type, "`{$id_field}` = {$record_id_safe}", true, false);
234
  }
235
236
  public static function db_get_record_list($location_type, $filter = '', $fetch = false, $no_return = false) {
237
    if (SnCache::isQueryCacheByLocationAndFilterEmpty($location_type, $filter)) {
238
      SnCache::queryCacheResetByLocationAndFilter($location_type, $filter);
239
240
      $location_info = &static::$location_info[$location_type];
241
      $id_field = $location_info[P_ID];
242
243
      if (static::$db->getTransaction()->check(false)) {
244
        // Проходим по всем родителям данной записи
245
        foreach ($location_info[P_OWNER_INFO] as $owner_data) {
246
          $owner_location_type = $owner_data[P_LOCATION];
247
          $parent_id_list = array();
248
          // Выбираем родителей данного типа и соответствующие ИД текущего типа
249
          $query = static::$db->doSelect(
250
            "SELECT
251
              distinct({{{$location_info[P_TABLE_NAME]}}}.{$owner_data[P_OWNER_FIELD]}) AS parent_id
252
            FROM {{{$location_info[P_TABLE_NAME]}}}" .
253
            ($filter ? ' WHERE ' . $filter : '') .
254
            ($fetch ? ' LIMIT 1' : ''));
255
          while ($row = db_fetch($query)) {
256
            // Исключаем из списка родительских ИД уже заблокированные записи
257
            if (!SnCache::cache_lock_get($owner_location_type, $row['parent_id'])) {
258
              $parent_id_list[$row['parent_id']] = $row['parent_id'];
259
            }
260
          }
261
262
          // Если все-таки какие-то записи еще не заблокированы - вынимаем текущие версии из базы
263
          if ($indexes_str = implode(',', $parent_id_list)) {
264
            $parent_id_field = static::$location_info[$owner_location_type][P_ID];
265
            static::db_get_record_list($owner_location_type,
266
              $parent_id_field . (count($parent_id_list) > 1 ? " IN ({$indexes_str})" : " = {$indexes_str}"), $fetch, true);
267
          }
268
        }
269
      }
270
271
      $query = static::$db->doSelect(
272
        "SELECT * FROM {{{$location_info[P_TABLE_NAME]}}}" .
273
        (($filter = trim($filter)) ? " WHERE {$filter}" : '')
274
        . " FOR UPDATE"
275
      );
276
      while ($row = db_fetch($query)) {
277
        // Caching record in row cache
278
        SnCache::cache_set($location_type, $row);
279
        // Making ref to cached record in query cache
280
        SnCache::queryCacheSetByFilter($location_type, $filter, $row[$id_field]);
281
      }
282
    }
283
284
    if ($no_return) {
285
      return true;
286
    } else {
287
      $result = false;
288
//      $queryCache = SnCache::getQueriesByLocationAndFilter($location_type, $filter);
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% 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...
289
//      if (is_array($queryCache)) {
290
//        foreach ($queryCache as $key => $value) {
291
      foreach (SnCache::getQueriesByLocationAndFilter($location_type, $filter) as $key => $value) {
292
        $result[$key] = $value;
293
        if ($fetch) {
294
          break;
295
        }
296
      }
297
298
//      }
299
300
      return $fetch ? (is_array($result) ? reset($result) : false) : $result;
301
    }
302
  }
303
304
  /**
305
   * @param int    $location_type
306
   * @param int    $record_id
307
   * @param string $set - SQL SET structure
308
   *
309
   * @return array|bool|mysqli_result|null
310
   */
311
  public static function db_upd_record_by_id($location_type, $record_id, $set) {
312
    if (!($record_id = idval($record_id)) || !($set = trim($set))) {
313
      return false;
314
    }
315
316
    $id_field = static::$location_info[$location_type][P_ID];
317
    $table_name = static::$location_info[$location_type][P_TABLE_NAME];
318
    // TODO Как-то вернуть может быть LIMIT 1 ?
319
    if ($result = static::$db->doUpdate("UPDATE {{{$table_name}}} SET {$set} WHERE `{$id_field}` = {$record_id}")) {
320
      if (static::$db->db_affected_rows()) {
321
        // Обновляем данные только если ряд был затронут
322
        // TODO - переделать под работу со структурированными $set
323
324
        // Тут именно так, а не cache_unset - что бы в кэшах автоматически обновилась запись. Будет нужно на будущее
325
        //static::$data[$location_type][$record_id] = null;
0 ignored issues
show
Unused Code Comprehensibility introduced by
79% 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...
326
        SnCache::cacheUnsetElement($location_type, $record_id);
327
        // Вытаскиваем обновленную запись
328
        static::db_get_record_by_id($location_type, $record_id);
329
        SnCache::cache_clear($location_type, false); // Мягкий сброс - только $queries
330
      }
331
    }
332
333
    return $result;
334
  }
335
336
  public static function db_upd_record_list($location_type, $condition, $set) {
337
    if (!($set = trim($set))) {
338
      return false;
339
    }
340
341
    $condition = trim($condition);
342
    $table_name = static::$location_info[$location_type][P_TABLE_NAME];
343
344
    if ($result = static::$db->doUpdate("UPDATE {{{$table_name}}} SET " . $set . ($condition ? ' WHERE ' . $condition : ''))) {
345
346
      if (static::$db->db_affected_rows()) { // Обновляем данные только если ряд был затронут
347
        // Поскольку нам неизвестно, что и как обновилось - сбрасываем кэш этого типа полностью
348
        // TODO - когда будет структурированный $condition и $set - перепаковывать данные
349
        SnCache::cache_clear($location_type, true);
350
      }
351
    }
352
353
    return $result;
354
  }
355
356
  /**
357
   * @param int    $location_type
358
   * @param string $set
359
   *
360
   * @return array|bool|false|mysqli_result|null
361
   */
362
  public static function db_ins_record($location_type, $set) {
363
    $set = trim($set);
364
    $table_name = static::$location_info[$location_type][P_TABLE_NAME];
365 View Code Duplication
    if ($result = static::$db->doInsert("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...
366
      if (static::$db->db_affected_rows()) // Обновляем данные только если ряд был затронут
367
      {
368
        $record_id = classSupernova::$db->db_insert_id();
369
        // Вытаскиваем запись целиком, потому что в $set могли быть "данные по умолчанию"
370
        $result = static::db_get_record_by_id($location_type, $record_id);
371
        // Очищаем второстепенные кэши - потому что вставленная запись могла повлиять на результаты запросов или локация или еще чего
372
        // TODO - когда будет поддержка изменения индексов и локаций - можно будет вызывать её
373
        SnCache::cache_clear($location_type, false); // Мягкий сброс - только $queries
374
      }
375
    }
376
377
    return $result;
378
  }
379
380
  public static function db_ins_field_set($location_type, $field_set, $serialize = false) {
381
    // TODO multiinsert
382
    !sn_db_field_set_is_safe($field_set) ? $field_set = sn_db_field_set_make_safe($field_set, $serialize) : false;
383
    sn_db_field_set_safe_flag_clear($field_set);
384
    $values = implode(',', $field_set);
385
    $fields = implode(',', array_keys($field_set));
386
387
    $table_name = static::$location_info[$location_type][P_TABLE_NAME];
388 View Code Duplication
    if ($result = static::$db->doInsert("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...
389
      if (static::$db->db_affected_rows()) {
390
        // Обновляем данные только если ряд был затронут
391
        $record_id = classSupernova::$db->db_insert_id();
392
        // Вытаскиваем запись целиком, потому что в $set могли быть "данные по умолчанию"
393
        $result = static::db_get_record_by_id($location_type, $record_id);
394
        // Очищаем второстепенные кэши - потому что вставленная запись могла повлиять на результаты запросов или локация или еще чего
395
        // TODO - когда будет поддержка изменения индексов и локаций - можно будет вызывать её
396
        SnCache::cache_clear($location_type, false); // Мягкий сброс - только $queries
397
      }
398
    }
399
400
    return $result;
401
  }
402
403
  public static function db_del_record_by_id($location_type, $safe_record_id) {
404
    if (!($safe_record_id = idval($safe_record_id))) {
405
      return false;
406
    }
407
408
    $id_field = static::$location_info[$location_type][P_ID];
409
    $table_name = static::$location_info[$location_type][P_TABLE_NAME];
410 View Code Duplication
    if ($result = static::$db->doDelete("DELETE FROM `{{{$table_name}}}` WHERE `{$id_field}` = {$safe_record_id}")) {
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...
411
      // Обновляем данные только если ряд был затронут
412
      if (static::$db->db_affected_rows()) {
413
        SnCache::cache_unset($location_type, $safe_record_id);
414
      }
415
    }
416
417
    return $result;
418
  }
419
420
  public static function db_del_record_list($location_type, $condition) {
421
    if (!($condition = trim($condition))) {
422
      return false;
423
    }
424
425
    $table_name = static::$location_info[$location_type][P_TABLE_NAME];
426
427 View Code Duplication
    if ($result = static::$db->doDelete("DELETE FROM `{{{$table_name}}}` WHERE {$condition}")) {
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...
428
      // Обновляем данные только если ряд был затронут
429
      if (static::$db->db_affected_rows()) {
430
        // Обнуление кэша, потому что непонятно, что поменялось
431
        // TODO - когда будет структурированный $condition можно будет делать только cache_unset по нужным записям
432
        SnCache::cache_clear($location_type);
433
      }
434
    }
435
436
    return $result;
437
  }
438
439
440
441
  // Работа с пользователями
442
  /**
443
   * Возвращает информацию о пользователе по его ID
444
   *
445
   * @param int|array $user_id_unsafe
446
   *    <p>int - ID пользователя</p>
447
   *    <p>array - запись пользователя с установленным полем ['id']</p>
448
   * @param bool      $for_update @deprecated
449
   * @param string    $fields @deprecated список полей или '*'/'' для всех полей
450
   * @param null      $player
451
   * @param bool|null $player Признак выбора записи пользователь типа "игрок"
452
   *    <p>null - Можно выбрать запись любого типа</p>
453
   *    <p>true - Выбирается только запись типа "игрок"</p>
454
   *    <p>false - Выбирается только запись типа "альянс"</p>
455
   *
456
   * @return array|false
457
   *    <p>false - Нет записи с указанным ID и $player</p>
458
   *    <p>array - запись типа $user</p>
459
   */
460
  public static function db_get_user_by_id($user_id_unsafe, $for_update = false, $fields = '*', $player = null) {
461
    $user = static::db_get_record_by_id(LOC_USER, $user_id_unsafe, $for_update, $fields);
462
463
    return (is_array($user) &&
464
      (
465
        $player === null
466
        ||
467
        ($player === true && !$user['user_as_ally'])
468
        ||
469
        ($player === false && $user['user_as_ally'])
470
      )) ? $user : false;
471
  }
472
473
  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...
474
    // TODO Проверить, кстати - а везде ли нужно выбирать юзеров или где-то все-таки ищутся Альянсы ?
475
    if (!($username_unsafe = trim($username_unsafe))) {
476
      return false;
477
    }
478
479
    $user = null;
480
    if (SnCache::isArrayLocation(LOC_USER)) {
481
      foreach (SnCache::getData(LOC_USER) as $user_id => $user_data) {
482
        if (is_array($user_data) && isset($user_data['username'])) {
483
          // проверяем поле
484
          // TODO Возможно есть смысл всегда искать по strtolower - но может игрок захочет переименоваться с другим регистром? Проверить!
485
          if ((!$like && $user_data['username'] == $username_unsafe) || ($like && strtolower($user_data['username']) == strtolower($username_unsafe))) {
486
            // $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...
487
            $user_as_ally = idval($user_data['user_as_ally']);
488
            if ($player === null || ($player === true && !$user_as_ally) || ($player === false && $user_as_ally)) {
489
              $user = $user_data;
490
              break;
491
            }
492
          }
493
        }
494
      }
495
    }
496
497
    if ($user === null) {
498
      // Вытаскиваем запись
499
      $username_safe = db_escape($like ? strtolower($username_unsafe) : $username_unsafe); // тут на самом деле strtolower() лишняя, но пусть будет
500
501
      $user = static::$db->doSelectFetch(
502
        "SELECT * FROM {{users}} WHERE `username` " . ($like ? 'LIKE' : '=') . " '{$username_safe}'"
503
        . " FOR UPDATE"
504
      );
505
      SnCache::cache_set(LOC_USER, $user); // В кэш-юзер так же заполнять индексы
506
    }
507
508
    return $user;
509
  }
510
511
512
  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...
513
    $user = null;
514
    // TODO переделать на индексы
515
516
    if ($user === null && !empty($where_safe)) {
517
      // Вытаскиваем запись
518
      $user = static::$db->doSelectFetch("SELECT * FROM {{users}} WHERE {$where_safe}" . " FOR UPDATE");
519
520
      SnCache::cache_set(LOC_USER, $user); // В кэш-юзер так же заполнять индексы
521
    }
522
523
    return $user;
524
  }
525
526
527 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...
528
    $date = is_numeric($date) ? "FROM_UNIXTIME({$date})" : "'{$date}'";
529
530
    return
531
      "(unit_time_start IS NULL OR unit_time_start <= {$date}) AND
532
    (unit_time_finish IS NULL OR unit_time_finish = '1970-01-01 03:00:00' OR unit_time_finish >= {$date})";
533
  }
534
535
  public static function db_get_unit_by_id($unit_id, $for_update = false, $fields = '*') {
536
    // 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...
537
    $unit = static::db_get_record_by_id(LOC_UNIT, $unit_id, $for_update, $fields);
538
//    if (is_array($unit)) {
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...
539
//      // static::$locator[LOC_UNIT][$unit['unit_location_type']][$unit['unit_location_id']][$unit['unit_snid']] = &SnCache::$data[LOC_UNIT][$unit_id];
540
//      SnCache::$locator[LOC_UNIT][$unit['unit_location_type']][$unit['unit_location_id']][$unit['unit_snid']] = &SnCache::getDataRefByLocationAndId(LOC_UNIT, $unit_id);
541
//    }
542
    SnCache::setUnitLocator($unit, $unit_id);
543
544
    return $unit;
545
  }
546
547
  /**
548
   * @param int $user_id
549
   * @param int $location_type
550
   * @param int $location_id
551
   *
552
   * @return array|bool
553
   */
554
  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...
555
    if (!($location_type = idval($location_type)) || !($location_id = idval($location_id))) {
556
      return false;
557
    }
558
559
    if (SnCache::isUnitLocatorNotSet($location_type, $location_id)) {
560
      $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());
561
      if (!empty($got_data) && is_array($got_data)) {
562
        foreach ($got_data as $unit_id => $unit_data) {
563
          SnCache::setUnitLocatorByLocationAndIDs($location_type, $location_id, $unit_data);
564
        }
565
      }
566
    }
567
568
    $result = false;
569
    foreach (SnCache::getUnitLocatorByFullLocation($location_type, $location_id) as $key => $value) {
570
      $result[$key] = $value;
571
    }
572
573
    return $result;
574
  }
575
576
  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...
577
    static::db_get_unit_list_by_location($user_id, $location_type, $location_id);
578
579
    return SnCache::getUnitLocator($location_type, $location_id, $unit_snid);
580
  }
581
582
583
  /*
584
   * С $for_update === true эта функция должна вызываться только из транзакции! Все соответствующие записи в users и planets должны быть уже блокированы!
585
   *
586
   * $que_type
587
   *   !$que_type - все очереди
588
   *   QUE_XXXXXX - конкретная очередь по планете
589
   * $user_id - ID пользователя
590
   * $planet_id
591
   *   $que_type == QUE_RESEARCH - игнорируется
592
   *   null - обработка очередей планет не производится
593
   *   false/0 - обрабатываются очереди всех планет по $user_id
594
   *   (integer) - обрабатываются локальные очереди для планеты. Нужно, например, в обработчике флотов
595
   *   иначе - $que_type для указанной планеты
596
   * $for_update - true == нужно блокировать записи
597
   *
598
   * TODO Работа при !$user_id
599
   * TODO Переформатировать вывод данных, что бы можно было возвращать данные по всем планетам и юзерам в одном запросе: добавить подмассивы 'que', 'planets', 'players'
600
   *
601
   */
602
  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...
603
    if (!$user_id) {
604
      pdump(debug_backtrace());
605
      die('No user_id for que_get_que()');
606
    }
607
608
    $ques = array();
609
610
    $query = array();
611
612
    if ($user_id = idval($user_id)) {
613
      $query[] = "`que_player_id` = {$user_id}";
614
    }
615
616
    if ($que_type == QUE_RESEARCH || $planet_id === null) {
617
      $query[] = "`que_planet_id` IS NULL";
618
    } elseif ($planet_id) {
619
      $query[] = "(`que_planet_id` = {$planet_id}" . ($que_type ? '' : ' OR que_planet_id IS NULL') . ")";
620
    }
621
    if ($que_type) {
622
      $query[] = "`que_type` = {$que_type}";
623
    }
624
625
    $ques['items'] = static::db_get_record_list(LOC_QUE, implode(' AND ', $query));
626
627
    return que_recalculate($ques);
628
  }
629
630
631 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...
632
    if (!is_array($user)) {
633
      // TODO - remove later
634
      print('<h1>СООБЩИТЕ ЭТО АДМИНУ: sn_db_unit_changeset_prepare() - USER is not ARRAY</h1>');
635
      pdump(debug_backtrace());
636
      die('USER is not ARRAY');
637
    }
638
    if (!isset($user['id']) || !$user['id']) {
639
      // TODO - remove later
640
      print('<h1>СООБЩИТЕ ЭТО АДМИНУ: sn_db_unit_changeset_prepare() - USER[id] пустой</h1>');
641
      pdump($user);
642
      pdump(debug_backtrace());
643
      die('USER[id] пустой');
644
    }
645
    $planet_id = is_array($planet_id) && isset($planet_id['id']) ? $planet_id['id'] : $planet_id;
646
647
    $unit_location = sys_get_unit_location($user, array(), $unit_id);
648
    $location_id = $unit_location == LOC_USER ? $user['id'] : $planet_id;
649
    $location_id = $location_id ? $location_id : 'NULL';
650
651
    $temp = DBStaticUnit::db_unit_by_location($user['id'], $unit_location, $location_id, $unit_id, true, 'unit_id');
652
    if ($temp['unit_id']) {
653
      $db_changeset = array(
654
        'action'  => SQL_OP_UPDATE,
655
        P_VERSION => 1,
656
        'where'   => array(
657
          "unit_id" => $temp['unit_id'],
658
        ),
659
        'fields'  => array(
660
          'unit_level' => array(
661
            'delta' => $unit_value
662
          ),
663
        ),
664
      );
665
    } else {
666
      $db_changeset = array(
667
        'action' => SQL_OP_INSERT,
668
        'fields' => array(
669
          'unit_player_id'     => array(
670
            'set' => $user['id'],
671
          ),
672
          'unit_location_type' => array(
673
            'set' => $unit_location,
674
          ),
675
          'unit_location_id'   => array(
676
            'set' => $unit_location == LOC_USER ? $user['id'] : $planet_id,
677
          ),
678
          'unit_type'          => array(
679
            'set' => get_unit_param($unit_id, P_UNIT_TYPE),
680
          ),
681
          'unit_snid'          => array(
682
            'set' => $unit_id,
683
          ),
684
          'unit_level'         => array(
685
            'set' => $unit_value,
686
          ),
687
        ),
688
      );
689
    }
690
691
    return $db_changeset;
692
  }
693
694
695
  public function db_changeset_delay($table_name, $table_data) {
696
    // TODO Применять ченджсет к записям
697
    static::$delayed_changset[$table_name] = is_array(static::$delayed_changset[$table_name]) ? static::$delayed_changset[$table_name] : array();
698
    // TODO - На самом деле дурацкая оптимизация, если честно - может быть идентичные записи с идентичными дельтами - и привет. Но не должны, конечно
699
    static::$delayed_changset[$table_name] = array_merge(static::$delayed_changset[$table_name], $table_data);
700
  }
701
702
  public function db_changeset_condition_compile(&$conditions, &$table_name = '') {
703
    if (!$conditions[P_LOCATION] || $conditions[P_LOCATION] == LOC_NONE) {
704
      $conditions[P_LOCATION] = LOC_NONE;
705
      switch ($table_name) {
706
        case 'users':
707
        case LOC_USER:
708
          $conditions[P_TABLE_NAME] = $table_name = 'users';
709
          $conditions[P_LOCATION] = LOC_USER;
710
        break;
711
712
        case 'planets':
713
        case LOC_PLANET:
714
          $conditions[P_TABLE_NAME] = $table_name = 'planets';
715
          $conditions[P_LOCATION] = LOC_PLANET;
716
        break;
717
718
        case 'unit':
719
        case LOC_UNIT:
720
          $conditions[P_TABLE_NAME] = $table_name = 'unit';
721
          $conditions[P_LOCATION] = LOC_UNIT;
722
        break;
723
      }
724
    }
725
726
    $conditions[P_FIELDS_STR] = '';
727
    if ($conditions['fields']) {
728
      $fields = array();
729 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...
730
        $condition = "`{$field_name}` = ";
731
        $value = '';
732
        if ($field_data['delta']) {
733
          $value = "`{$field_name}`" . ($field_data['delta'] >= 0 ? '+' : '') . $field_data['delta'];
734
        } elseif ($field_data['set']) {
735
          $value = (is_string($field_data['set']) ? "'{$field_data['set']}'" : $field_data['set']);
736
        }
737
738
        if ($value) {
739
          $fields[] = $condition . $value;
740
        }
741
      }
742
      $conditions[P_FIELDS_STR] = implode(',', $fields);
743
    }
744
745
    $conditions[P_WHERE_STR] = '';
746
    if (!empty($conditions['where'])) {
747
      if ($conditions[P_VERSION] == 1) {
748
        $the_conditions = array();
749
        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...
750
          // Простое условие - $field_id = $field_value
751
          if (is_string($field_id)) {
752
            $field_value =
753
              $field_value === null ? 'NULL' :
754
                (is_string($field_value) ? "'" . db_escape($field_value) . "'" :
755
                  (is_bool($field_value) ? intval($field_value) : $field_value));
756
            $the_conditions[] = "`{$field_id}` = {$field_value}";
757
          } else {
758
            die('Неподдерживаемый тип условия');
759
          }
760
        }
761
      } else {
762
        $the_conditions = &$conditions['where'];
763
      }
764
      $conditions[P_WHERE_STR] = implode(' AND ', $the_conditions);
765
    }
766
767
    switch ($conditions['action']) {
768
      case SQL_OP_DELETE:
769
        $conditions[P_ACTION_STR] = ("DELETE FROM {{{$table_name}}}");
770
      break;
771
      case SQL_OP_UPDATE:
772
        $conditions[P_ACTION_STR] = ("UPDATE {{{$table_name}}} SET");
773
      break;
774
      case SQL_OP_INSERT:
775
        $conditions[P_ACTION_STR] = ("INSERT INTO {{{$table_name}}} SET");
776
      break;
777
778
      default:
779
        die('Неподдерживаемая операция в classSupernova::db_changeset_condition_compile');
780
    }
781
782
    $conditions[P_QUERY_STR] = $conditions[P_ACTION_STR] . ' ' . $conditions[P_FIELDS_STR] . (' WHERE ' . $conditions[P_WHERE_STR]);
783
  }
784
785
  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...
786
    $result = true;
787
    if (!is_array($db_changeset) || empty($db_changeset)) {
788
      return $result;
789
    }
790
791
    foreach ($db_changeset as $table_name => &$table_data) {
792
      // TODO - delayed changeset
793
      foreach ($table_data as $record_id => &$conditions) {
794
        static::db_changeset_condition_compile($conditions, $table_name);
795
796
        if ($conditions['action'] != SQL_OP_DELETE && !$conditions[P_FIELDS_STR]) {
797
          continue;
798
        }
799
        if ($conditions['action'] == SQL_OP_DELETE && !$conditions[P_WHERE_STR]) {
800
          continue;
801
        } // Защита от случайного удаления всех данных в таблице
802
803
        if ($conditions[P_LOCATION] != LOC_NONE) {
804
          switch ($conditions['action']) {
805
            case SQL_OP_DELETE:
806
              $result = self::db_del_record_list($conditions[P_LOCATION], $conditions[P_WHERE_STR]) && $result;
807
            break;
808
            case SQL_OP_UPDATE:
809
              $result = self::db_upd_record_list($conditions[P_LOCATION], $conditions[P_WHERE_STR], $conditions[P_FIELDS_STR]) && $result;
810
            break;
811
            case SQL_OP_INSERT:
812
              $result = self::db_ins_record($conditions[P_LOCATION], $conditions[P_FIELDS_STR]) && $result;
813
            break;
814
            default:
815
              die('Неподдерживаемая операция в classSupernova::db_changeset_apply');
816
          }
817
        } else {
818
          $result = classSupernova::$db->doExecute($conditions[P_QUERY_STR]) && $result;
819
        }
820
      }
821
    }
822
823
    return $result;
824
  }
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
  // que_process не всегда должна работать в режиме прямой работы с БД !! Она может работать и в режиме эмуляции
861
  // !!!!!!!! После que_get брать не [0] элемент, а first() - тогда можно в индекс элемента засовывать que_id из таблицы
862
863
864
  public static function init_0_prepare() {
865
    // Отключаем magic_quotes
866
    ini_get('magic_quotes_sybase') ? die('SN is incompatible with \'magic_quotes_sybase\' turned on. Disable it in php.ini or .htaccess...') : false;
867
    if (@get_magic_quotes_gpc()) {
868
      $gpcr = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
869
      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...
870
        $value = stripslashes($value);
871
      });
872
    }
873
    if (function_exists('set_magic_quotes_runtime')) {
874
      @set_magic_quotes_runtime(0);
875
      @ini_set('magic_quotes_runtime', 0);
876
      @ini_set('magic_quotes_sybase', 0);
877
    }
878
  }
879
880
  public static function init_1_globalContainer() {
881
    static::$gc = new GlobalContainer();
882
    $gc = static::$gc;
883
884
    // Default db
885
    $gc->db = function ($c) {
886
      $db = new db_mysql($c);
887
      $db->sn_db_connect();
888
889
      return $db;
890
    };
891
892
    $gc->debug = function ($c) {
0 ignored issues
show
Unused Code introduced by
The parameter $c 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...
893
      return new debug();
894
    };
895
896
    $gc->cache = function ($c) {
0 ignored issues
show
Unused Code introduced by
The parameter $c 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...
897
      return new classCache(classSupernova::$cache_prefix);
898
    };
899
900
    $gc->config = function ($c) {
0 ignored issues
show
Unused Code introduced by
The parameter $c 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...
901
      return new classConfig(classSupernova::$cache_prefix);
902
    };
903
904
    $gc->localePlayer = function (GlobalContainer $c) {
905
      return new classLocale($c->config->server_locale_log_usage);
906
    };
907
908
    $gc->dbRowOperator = function ($c) {
909
      return new DbRowDirectOperator($c);
0 ignored issues
show
Unused Code introduced by
The call to DbRowDirectOperator::__construct() has too many arguments starting with $c.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
910
    };
911
912
    $gc->buddyClass = 'Buddy\BuddyModel';
913
    $gc->buddy = $gc->factory(function (GlobalContainer $c) {
914
      return new $c->buddyClass($c);
915
    });
916
917
    $gc->query = $gc->factory(function (GlobalContainer $c) {
918
      return new DbQueryConstructor($c->db);
0 ignored issues
show
Bug introduced by
It seems like $c->db can also be of type object<Closure>; however, DbSqlAware::__construct() does only seem to accept object<db_mysql>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
919
    });
920
921
    $gc->unit = $gc->factory(function (GlobalContainer $c) {
922
      return new \V2Unit\V2UnitModel($c);
923
    });
924
925
// TODO
0 ignored issues
show
Unused Code Comprehensibility introduced by
49% 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...
926
//    $container->vector = $container->factory(function (GlobalContainer $c) {
927
//      return new Vector($c->db);
928
//    });
929
  }
930
931
  public static function init_3_load_config_file() {
932
    $dbsettings = array();
933
934
    require(SN_ROOT_PHYSICAL . "config" . DOT_PHP_EX);
935
    self::$cache_prefix = !empty($dbsettings['cache_prefix']) ? $dbsettings['cache_prefix'] : $dbsettings['prefix'];
936
    self::$db_name = $dbsettings['name'];
937
    self::$sn_secret_word = $dbsettings['secretword'];
938
    unset($dbsettings);
939
  }
940
941
  public static function init_global_objects() {
942
    self::$debug = self::$gc->debug;
0 ignored issues
show
Documentation Bug introduced by
It seems like self::$gc->debug can also be of type object<Closure>. However, the property $debug is declared as type object<debug>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
943
    self::$db = self::$gc->db;
0 ignored issues
show
Documentation Bug introduced by
It seems like self::$gc->db can also be of type object<Closure>. However, the property $db is declared as type object<db_mysql>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
944
    self::$user_options = new userOptions(0);
945
946
    // Initializing global 'cacher' object
947
    self::$cache = self::$gc->cache;
0 ignored issues
show
Documentation Bug introduced by
It seems like self::$gc->cache can also be of type object<Closure>. However, the property $cache is declared as type object<classCache>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
948
949
    empty(static::$cache->tables) ? sys_refresh_tablelist() : false;
950
    empty(static::$cache->tables) ? die('DB error - cannot find any table. Halting...') : false;
951
952
    // Initializing global "config" object
953
    static::$config = self::$gc->config;
0 ignored issues
show
Documentation Bug introduced by
It seems like self::$gc->config can also be of type object<Closure>. However, the property $config is declared as type object<classConfig>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
954
955
    // Initializing statics
956
    Vector::_staticInit(static::$config);
0 ignored issues
show
Bug introduced by
It seems like static::$config can also be of type object<Closure>; however, Vector\Vector::_staticInit() does only seem to accept object<classConfig>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
957
  }
958
959
  public static function init_debug_state() {
960
    if ($_SERVER['SERVER_NAME'] == 'localhost' && !defined('BE_DEBUG')) {
961
      define('BE_DEBUG', true);
962
    }
963
    // 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...
964
    define('DEBUG_SQL_ERROR', true); // Выводить в сообщении об ошибке так же полный дамп запросов за сессию. Подойдет любое значение
965
    define('DEBUG_SQL_COMMENT_LONG', true); // Добавлять SQL запрос длинные комментарии. Не зависим от всех остальных параметров. Подойдет любое значение
966
    define('DEBUG_SQL_COMMENT', true); // Добавлять комментарии прямо в SQL запрос. Подойдет любое значение
967
    // Включаем нужные настройки
968
    defined('DEBUG_SQL_ONLINE') && !defined('DEBUG_SQL_ERROR') ? define('DEBUG_SQL_ERROR', true) : false;
969
    defined('DEBUG_SQL_ERROR') && !defined('DEBUG_SQL_COMMENT') ? define('DEBUG_SQL_COMMENT', true) : false;
970
    defined('DEBUG_SQL_COMMENT_LONG') && !defined('DEBUG_SQL_COMMENT') ? define('DEBUG_SQL_COMMENT', true) : false;
971
972
    if (defined('BE_DEBUG') || static::$config->debug) {
973
      @define('BE_DEBUG', true);
974
      @ini_set('display_errors', 1);
975
      @error_reporting(E_ALL ^ E_NOTICE ^ E_DEPRECATED);
976
    } else {
977
      @define('BE_DEBUG', false);
978
      @ini_set('display_errors', 0);
979
    }
980
981
  }
982
983
  public static function checkReturnRef(&$ref1, &$ref2) {
984
    if (isset($ref1['id'])) {
985
      $ref1['id']++;
986
      pdump($ref1['id']);
987
      pdump($ref2['id']);
988
      if ($ref2['id'] == $ref1['id']) {
989
        pdump('ok');
990
      } else {
991
        pdie('failed');
992
      }
993
      $ref2['id']--;
994
      if ($ref2['id'] == $ref1['id']) {
995
        pdump('ok');
996
      } else {
997
        pdie('failed');
998
      }
999
    }
1000
1001
  }
1002
1003
}
1004