1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Player; |
4
|
|
|
|
5
|
|
|
use Common\oldArrayAccessNd; |
6
|
|
|
|
7
|
|
|
/** |
8
|
|
|
* Class Player\userOptions |
9
|
|
|
* |
10
|
|
|
* Загрузка и сохранение настроек пользователя в БД |
11
|
|
|
* |
12
|
|
|
* Унаследованная поддержка многомерных индексов |
13
|
|
|
* Многоуровневое кэширование: память PHP -> память системы (xCache) -> БД |
14
|
|
|
* isset() работает на кэше в памяти PHP и не проверяет дальше |
15
|
|
|
* Поддержка удаления записей из БД и кэша через unset() |
16
|
|
|
* Поддержка отложенной записи |
17
|
|
|
* |
18
|
|
|
*/ |
19
|
|
|
class userOptions extends oldArrayAccessNd { |
20
|
|
|
protected $user_id = 0; |
21
|
|
|
protected $loaded = false; |
22
|
|
|
protected $defaults = array( |
23
|
|
|
PLAYER_OPTION_MENU_SORT => '', |
24
|
|
|
PLAYER_OPTION_MENU_HIDE_SHOW_BUTTON => PLAYER_OPTION_MENU_HIDE_SHOW_BUTTON_FIXED, |
25
|
|
|
PLAYER_OPTION_MENU_SHOW_ON_BUTTON => 0, |
26
|
|
|
PLAYER_OPTION_MENU_HIDE_ON_BUTTON => 0, |
27
|
|
|
PLAYER_OPTION_MENU_HIDE_ON_LEAVE => 0, |
28
|
|
|
PLAYER_OPTION_MENU_UNPIN_ABSOLUTE => 0, |
29
|
|
|
PLAYER_OPTION_MENU_ITEMS_AS_BUTTONS => 0, |
30
|
|
|
PLAYER_OPTION_MENU_WHITE_TEXT => 0, |
31
|
|
|
PLAYER_OPTION_MENU_OLD => 0, |
32
|
|
|
|
33
|
|
|
PLAYER_OPTION_SOUND_ENABLED => 0, |
34
|
|
|
|
35
|
|
|
PLAYER_OPTION_FLEET_SHIP_SORT => PLAYER_OPTION_SORT_DEFAULT, |
36
|
|
|
PLAYER_OPTION_FLEET_SHIP_SORT_INVERSE => PLAYER_OPTION_SORT_ORDER_PLAIN, |
37
|
|
|
|
38
|
|
|
PLAYER_OPTION_CURRENCY_DEFAULT => 'RUR', |
39
|
|
|
|
40
|
|
|
PLAYER_OPTION_FLEET_SPY_DEFAULT => 1, |
41
|
|
|
// PLAYER_OPTION_FLEET_MESS_AMOUNT_MAX => 99, |
|
|
|
|
42
|
|
|
|
43
|
|
|
PLAYER_OPTION_UNIVERSE_ICON_SPYING => 1, |
44
|
|
|
PLAYER_OPTION_UNIVERSE_ICON_MISSILE => 1, |
45
|
|
|
PLAYER_OPTION_UNIVERSE_ICON_PM => 1, |
46
|
|
|
PLAYER_OPTION_UNIVERSE_ICON_STATS => 1, |
47
|
|
|
PLAYER_OPTION_UNIVERSE_ICON_PROFILE => 1, |
48
|
|
|
PLAYER_OPTION_UNIVERSE_ICON_BUDDY => 1, |
49
|
|
|
PLAYER_OPTION_UNIVERSE_OLD => 0, |
50
|
|
|
PLAYER_OPTION_UNIVERSE_DISABLE_COLONIZE => 0, |
51
|
|
|
|
52
|
|
|
PLAYER_OPTION_PLANET_SORT => 0, |
53
|
|
|
PLAYER_OPTION_PLANET_SORT_INVERSE => 0, |
54
|
|
|
PLAYER_OPTION_TOOLTIP_DELAY => 500, |
55
|
|
|
|
56
|
|
|
PLAYER_OPTION_BASE_FONT_SIZE => FONT_SIZE_PERCENT_DEFAULT_STRING, |
57
|
|
|
|
58
|
|
|
PLAYER_OPTION_BUILD_AUTOCONVERT_HIDE => 0, |
59
|
|
|
|
60
|
|
|
PLAYER_OPTION_NAVBAR_PLANET_VERTICAL => 0, |
61
|
|
|
PLAYER_OPTION_NAVBAR_RESEARCH_WIDE => 0, |
62
|
|
|
PLAYER_OPTION_NAVBAR_DISABLE_EXPEDITIONS => 0, |
63
|
|
|
PLAYER_OPTION_NAVBAR_DISABLE_FLYING_FLEETS => 0, |
64
|
|
|
PLAYER_OPTION_NAVBAR_DISABLE_RESEARCH => 0, |
65
|
|
|
PLAYER_OPTION_NAVBAR_DISABLE_PLANET => 0, |
66
|
|
|
PLAYER_OPTION_NAVBAR_DISABLE_HANGAR => 0, |
67
|
|
|
PLAYER_OPTION_NAVBAR_DISABLE_QUESTS => 0, |
68
|
|
|
PLAYER_OPTION_NAVBAR_DISABLE_META_MATTER => 0, |
69
|
|
|
PLAYER_OPTION_NAVBAR_PLANET_OLD => 0, |
70
|
|
|
PLAYER_OPTION_NAVBAR_PLANET_DISABLE_STORAGE => 0, |
71
|
|
|
|
72
|
|
|
PLAYER_OPTION_BUILDING_SORT => array( |
73
|
|
|
QUE_RESEARCH => PLAYER_OPTION_SORT_DEFAULT, |
74
|
|
|
QUE_STRUCTURES => PLAYER_OPTION_SORT_DEFAULT, |
75
|
|
|
SUBQUE_FLEET => PLAYER_OPTION_SORT_DEFAULT, |
76
|
|
|
SUBQUE_DEFENSE => PLAYER_OPTION_SORT_DEFAULT, |
77
|
|
|
), |
78
|
|
|
PLAYER_OPTION_BUILDING_SORT_INVERSE => array( |
79
|
|
|
QUE_RESEARCH => PLAYER_OPTION_SORT_ORDER_PLAIN, |
80
|
|
|
QUE_STRUCTURES => PLAYER_OPTION_SORT_ORDER_PLAIN, |
81
|
|
|
SUBQUE_FLEET => PLAYER_OPTION_SORT_ORDER_PLAIN, |
82
|
|
|
SUBQUE_DEFENSE => PLAYER_OPTION_SORT_ORDER_PLAIN, |
83
|
|
|
), |
84
|
|
|
|
85
|
|
|
PLAYER_OPTION_ANIMATION_DISABLED => 0, |
86
|
|
|
PLAYER_OPTION_DESIGN_DISABLE_BORDERS => 0, |
87
|
|
|
PLAYER_OPTION_TECH_TREE_TABLE => 0, |
88
|
|
|
|
89
|
|
|
PLAYER_OPTION_PROGRESS_BARS_DISABLED => 0, |
90
|
|
|
|
91
|
|
|
PLAYER_OPTION_FLEET_SHIP_SELECT_OLD => 0, |
92
|
|
|
PLAYER_OPTION_FLEET_SHIP_HIDE_SPEED => 0, |
93
|
|
|
PLAYER_OPTION_FLEET_SHIP_HIDE_CAPACITY => 0, |
94
|
|
|
PLAYER_OPTION_FLEET_SHIP_HIDE_CONSUMPTION => 0, |
95
|
|
|
|
96
|
|
|
PLAYER_OPTION_TUTORIAL_DISABLED => 1, |
97
|
|
|
PLAYER_OPTION_TUTORIAL_WINDOWED => 0, |
98
|
|
|
PLAYER_OPTION_TUTORIAL_CURRENT => 1, |
99
|
|
|
PLAYER_OPTION_TUTORIAL_FINISHED => 0, |
100
|
|
|
|
101
|
|
|
PLAYER_OPTION_QUEST_LIST_FILTER => QUEST_STATUS_ALL, |
102
|
|
|
|
103
|
|
|
PLAYER_OPTION_LOGIN_REWARDED_LAST => SN_DATE_PREHISTORIC_SQL, |
104
|
|
|
PLAYER_OPTION_LOGIN_REWARD_STREAK_BEGAN => SN_DATE_PREHISTORIC_SQL, |
105
|
|
|
); |
106
|
|
|
|
107
|
|
|
public $data = array(); // Container // TODO - make protected |
108
|
|
|
|
109
|
|
|
public $to_write = array(); // TODO - make protected |
110
|
|
|
public $to_delete = array(); // TODO - make protected |
111
|
|
|
|
112
|
|
|
public function __get($offset) { |
113
|
|
|
// TODO: Implement __get() method. |
114
|
|
|
return $this->__isset($offset) ? $this->data[$offset] : null; |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
public function __set($offset, $value = null) { |
118
|
|
|
// if(!$this->__isset($offset) || $this->__get($offset) != $value) |
|
|
|
|
119
|
|
|
{ |
120
|
|
|
$this->data[$offset] = $value; // Сразу записываем данные во внутренний кэш |
121
|
|
|
$this->to_write[$offset] = 1; // Индекс измененного элемента для работы подсистемы отложенной записи |
122
|
|
|
} |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
public function __isset($offset) { |
126
|
|
|
// TODO: Implement __isset() method. |
127
|
|
|
return isset($this->data[$offset]); |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
public function __unset($offset) { |
131
|
|
|
// TODO: Implement __unset() method. |
132
|
|
|
unset($this->data[$offset]); |
133
|
|
|
$this->to_delete[$offset] = 1; |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
public function __flush() { |
137
|
|
|
// TODO Implement |
138
|
|
|
|
139
|
|
|
$update_cache = false; |
140
|
|
|
|
141
|
|
|
if (!empty($this->to_write)) { |
142
|
|
|
foreach ($this->to_write as $key => $cork) { |
143
|
|
|
$value = is_array($this->data[$key]) ? serialize($this->data[$key]) : $this->data[$key]; // Сериализация для массивов при сохранении в БД |
144
|
|
|
$this->to_write[$key] = "({$this->user_id}, '" . db_escape($key) . "', '" . db_escape($value) . "')"; |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
doquery("REPLACE INTO `{{player_options}}` (`player_id`, `option_id`, `value`) VALUES " . implode(',', $this->to_write)); |
148
|
|
|
|
149
|
|
|
$this->to_write = array(); |
150
|
|
|
$update_cache = true; |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
if (!empty($this->to_delete)) { |
154
|
|
|
foreach ($this->to_delete as $key => &$value) { |
155
|
|
|
$value = is_string($key) ? "'" . db_escape($key) . "'" : $key; |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
doquery("DELETE FROM `{{player_options}}` WHERE `player_id` = {$this->user_id} AND `option_id` IN (" . implode(',', $this->to_delete) . ") "); |
159
|
|
|
|
160
|
|
|
$this->to_delete = array(); |
161
|
|
|
$update_cache = true; |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
if ($update_cache) { |
165
|
|
|
global $sn_cache; |
|
|
|
|
166
|
|
|
|
167
|
|
|
$field_name = $this->cached_name(); |
168
|
|
|
$sn_cache->$field_name = $this->data; |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
return true; |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
|
175
|
|
|
public function __construct($user_id) { |
176
|
|
|
$this->user_change($user_id); |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
public function user_change($user_id, $forceLoad = false) { |
180
|
|
|
$this->loaded = false; |
181
|
|
|
$this->user_id = round(floatval($user_id)); |
182
|
|
|
$this->load($forceLoad); |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
protected function cached_name() { |
186
|
|
|
return 'options_' . $this->user_id; |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
protected function load($forceLoad = false) { |
190
|
|
|
global $sn_cache; |
|
|
|
|
191
|
|
|
|
192
|
|
|
if ($this->loaded) { |
193
|
|
|
return; |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
$this->data = $this->defaults; |
197
|
|
|
$this->to_write = array(); |
198
|
|
|
$this->to_delete = array(); |
199
|
|
|
|
200
|
|
|
if (!$this->user_id) { |
201
|
|
|
$this->loaded = true; |
202
|
|
|
|
203
|
|
|
return; |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
$field_name = $this->cached_name(); |
207
|
|
|
if (!$forceLoad) { |
208
|
|
|
$a_data = $sn_cache->$field_name; |
209
|
|
|
|
210
|
|
|
if (!empty($a_data)) { |
211
|
|
|
$this->data = array_replace_recursive($this->data, $a_data); |
212
|
|
|
|
213
|
|
|
return; |
214
|
|
|
} |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
$query = doquery("SELECT * FROM `{{player_options}}` WHERE `player_id` = {$this->user_id} FOR UPDATE"); |
218
|
|
|
while ($row = db_fetch($query)) { |
219
|
|
|
// $this->data[$row['option_id']] = $row['value']; |
|
|
|
|
220
|
|
|
$this->data[$row['option_id']] = is_string($row['value']) && ($temp = unserialize($row['value'])) !== false ? $temp : $row['value']; // Десериализация |
221
|
|
|
} |
222
|
|
|
$sn_cache->$field_name = $this->data; |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
} |
226
|
|
|
|
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.