Issues (1369)

classes/Player/userOptions.php (4 issues)

Severity
1
<?php
2
3
namespace Player;
4
5
use Common\oldArrayAccessNd;
6
use SN;
7
8
/**
9
 * Class Player\userOptions
10
 *
11
 * Загрузка и сохранение настроек пользователя в БД
12
 *
13
 * Унаследованная поддержка многомерных индексов
14
 * Многоуровневое кэширование: память PHP -> память системы (xCache) -> БД
15
 * isset() работает на кэше в памяти PHP и не проверяет дальше
16
 * Поддержка удаления записей из БД и кэша через unset()
17
 * Поддержка отложенной записи
18
 *
19
 */
20
class userOptions extends oldArrayAccessNd {
21
  protected $user_id = 0;
22
  protected $loaded = false;
23
  protected $defaults = array(
24
    PLAYER_OPTION_MENU_SORT             => '',
25
    PLAYER_OPTION_MENU_HIDE_SHOW_BUTTON => PLAYER_OPTION_MENU_HIDE_SHOW_BUTTON_FIXED,
26
    PLAYER_OPTION_MENU_SHOW_ON_BUTTON   => 0,
27
    PLAYER_OPTION_MENU_HIDE_ON_BUTTON   => 0,
28
    PLAYER_OPTION_MENU_HIDE_ON_LEAVE    => 0,
29
    PLAYER_OPTION_MENU_UNPIN_ABSOLUTE   => 0,
30
    PLAYER_OPTION_MENU_ITEMS_AS_BUTTONS => 0,
31
    PLAYER_OPTION_MENU_WHITE_TEXT       => 0,
32
    PLAYER_OPTION_MENU_OLD              => 0,
33
34
    PLAYER_OPTION_SOUND_ENABLED => 0,
35
36
    PLAYER_OPTION_FLEET_SHIP_SORT         => PLAYER_OPTION_SORT_DEFAULT,
37
    PLAYER_OPTION_FLEET_SHIP_SORT_INVERSE => PLAYER_OPTION_SORT_ORDER_PLAIN,
38
39
    PLAYER_OPTION_CURRENCY_DEFAULT => 'RUR',
40
41
    PLAYER_OPTION_FLEET_SPY_DEFAULT => 1,
42
    // PLAYER_OPTION_FLEET_MESS_AMOUNT_MAX => 99,
43
44
    PLAYER_OPTION_UNIVERSE_ICON_SPYING      => 1,
45
    PLAYER_OPTION_UNIVERSE_ICON_MISSILE     => 1,
46
    PLAYER_OPTION_UNIVERSE_ICON_PM          => 1,
47
    PLAYER_OPTION_UNIVERSE_ICON_STATS       => 1,
48
    PLAYER_OPTION_UNIVERSE_ICON_PROFILE     => 1,
49
    PLAYER_OPTION_UNIVERSE_ICON_BUDDY       => 1,
50
    PLAYER_OPTION_UNIVERSE_OLD              => 0,
51
    PLAYER_OPTION_UNIVERSE_DISABLE_COLONIZE => 0,
52
53
    PLAYER_OPTION_PLANET_SORT         => 0,
54
    PLAYER_OPTION_PLANET_SORT_INVERSE => 0,
55
    PLAYER_OPTION_TOOLTIP_DELAY       => 500,
56
57
    PLAYER_OPTION_BASE_FONT_SIZE => FONT_SIZE_PERCENT_DEFAULT_STRING,
58
59
    PLAYER_OPTION_BUILD_AUTOCONVERT_HIDE => 0,
60
61
    PLAYER_OPTION_NAVBAR_PLANET_VERTICAL        => 0,
62
    PLAYER_OPTION_NAVBAR_RESEARCH_WIDE          => 0,
63
    PLAYER_OPTION_NAVBAR_DISABLE_EXPEDITIONS    => 0,
64
    PLAYER_OPTION_NAVBAR_DISABLE_FLYING_FLEETS  => 0,
65
    PLAYER_OPTION_NAVBAR_DISABLE_RESEARCH       => 0,
66
    PLAYER_OPTION_NAVBAR_DISABLE_PLANET         => 0,
67
    PLAYER_OPTION_NAVBAR_DISABLE_HANGAR         => 0,
68
    PLAYER_OPTION_NAVBAR_DISABLE_DEFENSE        => 0,
69
    PLAYER_OPTION_NAVBAR_DISABLE_QUESTS         => 0,
70
    PLAYER_OPTION_NAVBAR_DISABLE_META_MATTER    => 0,
71
    PLAYER_OPTION_NAVBAR_PLANET_OLD             => 0,
72
    PLAYER_OPTION_NAVBAR_PLANET_DISABLE_STORAGE => 0,
73
74
    PLAYER_OPTION_BUILDING_SORT         => array(
75
      QUE_RESEARCH   => PLAYER_OPTION_SORT_DEFAULT,
76
      QUE_STRUCTURES => PLAYER_OPTION_SORT_DEFAULT,
77
      SUBQUE_FLEET   => PLAYER_OPTION_SORT_DEFAULT,
78
      SUBQUE_DEFENSE => PLAYER_OPTION_SORT_DEFAULT,
79
    ),
80
    PLAYER_OPTION_BUILDING_SORT_INVERSE => array(
81
      QUE_RESEARCH   => PLAYER_OPTION_SORT_ORDER_PLAIN,
82
      QUE_STRUCTURES => PLAYER_OPTION_SORT_ORDER_PLAIN,
83
      SUBQUE_FLEET   => PLAYER_OPTION_SORT_ORDER_PLAIN,
84
      SUBQUE_DEFENSE => PLAYER_OPTION_SORT_ORDER_PLAIN,
85
    ),
86
87
    PLAYER_OPTION_ANIMATION_DISABLED     => 0,
88
    PLAYER_OPTION_DESIGN_DISABLE_BORDERS => 0,
89
    PLAYER_OPTION_TECH_TREE_TABLE        => 0,
90
91
    PLAYER_OPTION_PROGRESS_BARS_DISABLED => 0,
92
93
    PLAYER_OPTION_FLEET_SHIP_SELECT_OLD       => 0,
94
    PLAYER_OPTION_FLEET_SHIP_HIDE_SPEED       => 0,
95
    PLAYER_OPTION_FLEET_SHIP_HIDE_CAPACITY    => 0,
96
    PLAYER_OPTION_FLEET_SHIP_HIDE_CONSUMPTION => 0,
97
98
    PLAYER_OPTION_TUTORIAL_DISABLED => 1,
99
    PLAYER_OPTION_TUTORIAL_WINDOWED => 0,
100
    PLAYER_OPTION_TUTORIAL_CURRENT  => 1,
101
    PLAYER_OPTION_TUTORIAL_FINISHED => 0,
102
103
    PLAYER_OPTION_QUEST_LIST_FILTER => QUEST_STATUS_ALL,
104
105
    PLAYER_OPTION_LOGIN_REWARDED_LAST       => SN_DATE_PREHISTORIC_SQL,
106
    PLAYER_OPTION_LOGIN_REWARD_STREAK_BEGAN => SN_DATE_PREHISTORIC_SQL,
107
  );
108
109
  public $data = array(); // Container // TODO - make protected
110
111
  public $to_write = array(); // TODO - make protected
112
  public $to_delete = array(); // TODO - make protected
113
114
  public function __get($offset) {
115
    // TODO: Implement __get() method.
116
    return $this->__isset($offset) ? $this->data[$offset] : null;
117
  }
118
119
  public function __set($offset, $value = null) {
120
//    if(!$this->__isset($offset) || $this->__get($offset) != $value)
121
    {
122
      $this->data[$offset] = $value; // Сразу записываем данные во внутренний кэш
123
      $this->to_write[$offset] = 1; // Индекс измененного элемента для работы подсистемы отложенной записи
124
    }
125
  }
126
127
  public function __isset($offset) {
128
    // TODO: Implement __isset() method.
129
    return isset($this->data[$offset]);
130
  }
131
132
  public function __unset($offset) {
133
    // TODO: Implement __unset() method.
134
    unset($this->data[$offset]);
135
    $this->to_delete[$offset] = 1;
136
  }
137
138
  public function __flush() {
139
    // TODO Implement
140
141
    $update_cache = false;
142
143
    if (!empty($this->to_write)) {
144
      foreach ($this->to_write as $key => $cork) {
145
        $value = is_array($this->data[$key]) ? serialize($this->data[$key]) : $this->data[$key]; // Сериализация для массивов при сохранении в БД
146
        $this->to_write[$key] = "({$this->user_id}, '" . SN::$db->db_escape($key) . "', '" . SN::$db->db_escape($value) . "')";
147
      }
148
149
      doquery("REPLACE INTO `{{player_options}}` (`player_id`, `option_id`, `value`) VALUES " . implode(',', $this->to_write));
0 ignored issues
show
Deprecated Code introduced by
The function doquery() has been deprecated. ( Ignorable by Annotation )

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

149
      /** @scrutinizer ignore-deprecated */ doquery("REPLACE INTO `{{player_options}}` (`player_id`, `option_id`, `value`) VALUES " . implode(',', $this->to_write));
Loading history...
150
151
      $this->to_write = array();
152
      $update_cache = true;
153
    }
154
155
    if (!empty($this->to_delete)) {
156
      foreach ($this->to_delete as $key => &$value) {
157
        $value = is_string($key) ? "'" . SN::$db->db_escape($key) . "'" : $key;
158
      }
159
160
      doquery("DELETE FROM `{{player_options}}` WHERE `player_id` = {$this->user_id} AND `option_id` IN (" . implode(',', $this->to_delete) . ") ");
0 ignored issues
show
Deprecated Code introduced by
The function doquery() has been deprecated. ( Ignorable by Annotation )

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

160
      /** @scrutinizer ignore-deprecated */ doquery("DELETE FROM `{{player_options}}` WHERE `player_id` = {$this->user_id} AND `option_id` IN (" . implode(',', $this->to_delete) . ") ");
Loading history...
161
162
      $this->to_delete = array();
163
      $update_cache = true;
164
    }
165
166
    if ($update_cache) {
167
      global $sn_cache;
168
169
      $field_name = $this->cached_name();
170
      $sn_cache->$field_name = $this->data;
171
    }
172
173
    return true;
174
  }
175
176
177
  public function __construct($user_id) {
178
    $this->user_change($user_id);
179
  }
180
181
  public function user_change($user_id, $forceLoad = false) {
182
    $this->loaded = false;
183
    $this->user_id = round(floatval($user_id));
184
    $this->load($forceLoad);
185
  }
186
187
  protected function cached_name() {
188
    return 'options_' . $this->user_id;
189
  }
190
191
  protected function load($forceLoad = false) {
192
    global $sn_cache;
193
194
    if ($this->loaded) {
195
      return;
196
    }
197
198
    $this->data = $this->defaults;
199
    $this->to_write = array();
200
    $this->to_delete = array();
201
202
    if (!$this->user_id) {
203
      $this->loaded = true;
204
205
      return;
206
    }
207
208
    $field_name = $this->cached_name();
209
    if (!$forceLoad) {
210
      $a_data = $sn_cache->$field_name;
211
212
      if (!empty($a_data)) {
213
        $this->data = array_replace_recursive($this->data, $a_data);
214
215
        return;
216
      }
217
    }
218
219
    $query = doquery("SELECT * FROM `{{player_options}}` WHERE `player_id` = {$this->user_id} FOR UPDATE");
0 ignored issues
show
Deprecated Code introduced by
The function doquery() has been deprecated. ( Ignorable by Annotation )

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

219
    $query = /** @scrutinizer ignore-deprecated */ doquery("SELECT * FROM `{{player_options}}` WHERE `player_id` = {$this->user_id} FOR UPDATE");
Loading history...
220
    while ($row = db_fetch($query)) {
0 ignored issues
show
Deprecated Code introduced by
The function db_fetch() has been deprecated. ( Ignorable by Annotation )

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

220
    while ($row = /** @scrutinizer ignore-deprecated */ db_fetch($query)) {
Loading history...
221
      // $this->data[$row['option_id']] = $row['value'];
222
      $this->data[$row['option_id']] = is_string($row['value']) && ($temp = unserialize($row['value'])) !== false ? $temp : $row['value']; // Десериализация
223
    }
224
    $sn_cache->$field_name = $this->data;
225
  }
226
227
}
228