Commit | Line | Data |
---|---|---|
efc4e026 | 1 | <?php |
a9229942 | 2 | |
a8e8aa21 | 3 | namespace wcf\system\user\collapsible\content; |
a9229942 | 4 | |
efc4e026 | 5 | use wcf\data\object\type\ObjectTypeCache; |
fc521fb9 | 6 | use wcf\system\database\util\PreparedStatementConditionBuilder; |
79bbb75a | 7 | use wcf\system\exception\InvalidObjectTypeException; |
efc4e026 | 8 | use wcf\system\SingletonFactory; |
a9229942 | 9 | use wcf\system\user\storage\UserStorageHandler; |
efc4e026 AE |
10 | use wcf\system\WCF; |
11 | ||
12 | /** | |
13 | * Provides methods for handling collapsible containers. | |
a9229942 TD |
14 | * |
15 | * @author Alexander Ebert | |
16 | * @copyright 2001-2019 WoltLab GmbH | |
17 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> | |
18 | * @package WoltLabSuite\Core\System\User\Collapsible\Content | |
efc4e026 | 19 | */ |
a9229942 TD |
20 | class UserCollapsibleContentHandler extends SingletonFactory |
21 | { | |
22 | /** | |
23 | * object type cache | |
24 | * @var mixed[][] | |
25 | */ | |
26 | protected $cache; | |
27 | ||
28 | /** | |
29 | * list of collapsed object ids per object type id | |
30 | * @var int[][] | |
31 | */ | |
32 | protected $collapsedContent = []; | |
33 | ||
34 | /** | |
35 | * @inheritDoc | |
36 | */ | |
37 | protected function init() | |
38 | { | |
39 | $this->cache = [ | |
40 | 'objectTypes' => [], | |
41 | 'objectTypeIDs' => [], | |
42 | ]; | |
43 | ||
44 | $objectTypes = ObjectTypeCache::getInstance()->getObjectTypes('com.woltlab.wcf.collapsibleContent'); | |
45 | foreach ($objectTypes as $objectType) { | |
46 | $this->cache['objectTypes'][$objectType->objectTypeID] = $objectType; | |
47 | $this->cache['objectTypeIDs'][$objectType->objectType] = $objectType->objectTypeID; | |
48 | } | |
49 | } | |
50 | ||
51 | /** | |
52 | * Returns true if given object is collapsed. | |
53 | * | |
54 | * @param string $objectType | |
55 | * @param string $objectID | |
56 | * @return bool | |
57 | * @throws InvalidObjectTypeException | |
58 | */ | |
59 | public function isCollapsed($objectType, $objectID) | |
60 | { | |
61 | $objectTypeID = $this->getObjectTypeID($objectType); | |
62 | if ($objectTypeID === null) { | |
63 | throw new InvalidObjectTypeException($objectType, 'com.woltlab.wcf.collapsibleContent'); | |
64 | } | |
65 | ||
66 | return \in_array($objectID, $this->getCollapsedContent($objectTypeID)); | |
67 | } | |
68 | ||
69 | /** | |
70 | * Returns the object type id based upon specified object type name. Returns | |
71 | * null, if object type is unknown. | |
72 | * | |
73 | * @param string $objectType | |
74 | * @return int | |
75 | */ | |
76 | public function getObjectTypeID($objectType) | |
77 | { | |
78 | if (isset($this->cache['objectTypeIDs'][$objectType])) { | |
79 | return $this->cache['objectTypeIDs'][$objectType]; | |
80 | } | |
81 | } | |
82 | ||
83 | /** | |
84 | * Returns a list of object ids being collapsed by current user. | |
85 | * | |
86 | * @param int $objectTypeID | |
87 | * @return int[] | |
88 | */ | |
89 | public function getCollapsedContent($objectTypeID) | |
90 | { | |
91 | if (!isset($this->collapsedContent[$objectTypeID])) { | |
92 | $this->collapsedContent[$objectTypeID] = []; | |
93 | ||
94 | if (WCF::getUser()->userID) { | |
95 | $data = UserStorageHandler::getInstance()->getField('collapsedContent-' . $objectTypeID); | |
96 | ||
97 | // cache does not exist or is outdated | |
98 | if ($data === null) { | |
99 | $sql = "SELECT objectID | |
100 | FROM wcf" . WCF_N . "_user_collapsible_content | |
101 | WHERE objectTypeID = ? | |
102 | AND userID = ?"; | |
103 | $statement = WCF::getDB()->prepareStatement($sql); | |
104 | $statement->execute([ | |
105 | $objectTypeID, | |
106 | WCF::getUser()->userID, | |
107 | ]); | |
108 | $this->collapsedContent[$objectTypeID] = $statement->fetchAll(\PDO::FETCH_COLUMN); | |
109 | ||
110 | // update storage data | |
111 | UserStorageHandler::getInstance()->update( | |
112 | WCF::getUser()->userID, | |
113 | 'collapsedContent-' . $objectTypeID, | |
114 | \serialize($this->collapsedContent[$objectTypeID]) | |
115 | ); | |
116 | } else { | |
117 | $this->collapsedContent[$objectTypeID] = @\unserialize($data); | |
118 | } | |
119 | } else { | |
120 | $collapsedContent = WCF::getSession()->getVar('collapsedContent'); | |
121 | if ($collapsedContent !== null && \is_array($collapsedContent)) { | |
122 | if (isset($collapsedContent[$objectTypeID])) { | |
123 | $this->collapsedContent[$objectTypeID] = $collapsedContent[$objectTypeID]; | |
124 | } | |
125 | } | |
126 | } | |
127 | } | |
128 | ||
129 | return $this->collapsedContent[$objectTypeID]; | |
130 | } | |
131 | ||
132 | /** | |
133 | * Marks content as collapsed. | |
134 | * | |
135 | * @param int $objectTypeID | |
136 | * @param string $objectID | |
137 | */ | |
138 | public function markAsCollapsed($objectTypeID, $objectID) | |
139 | { | |
140 | if (WCF::getUser()->userID) { | |
141 | $sql = "SELECT * | |
142 | FROM wcf" . WCF_N . "_user_collapsible_content | |
143 | WHERE objectTypeID = ? | |
144 | AND objectID = ? | |
145 | AND userID = ?"; | |
146 | $statement = WCF::getDB()->prepareStatement($sql); | |
147 | $statement->execute([ | |
148 | $objectTypeID, | |
149 | $objectID, | |
150 | WCF::getUser()->userID, | |
151 | ]); | |
152 | $row = $statement->fetchArray(); | |
153 | ||
154 | if (!$row) { | |
155 | $sql = "INSERT INTO wcf" . WCF_N . "_user_collapsible_content | |
156 | (objectTypeID, objectID, userID) | |
157 | VALUES (?, ?, ?)"; | |
158 | $statement = WCF::getDB()->prepareStatement($sql); | |
159 | $statement->execute([ | |
160 | $objectTypeID, | |
161 | $objectID, | |
162 | WCF::getUser()->userID, | |
163 | ]); | |
164 | } | |
165 | ||
166 | // reset storage | |
167 | UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'collapsedContent-' . $objectTypeID); | |
168 | } else { | |
169 | $collapsedContent = WCF::getSession()->getVar('collapsedContent'); | |
170 | if ($collapsedContent === null || !\is_array($collapsedContent)) { | |
171 | $collapsedContent = []; | |
172 | } | |
173 | ||
174 | if (!\in_array($objectID, $collapsedContent)) { | |
175 | $collapsedContent[$objectTypeID] = []; | |
176 | } | |
177 | ||
178 | $collapsedContent[$objectTypeID][] = $objectID; | |
179 | WCF::getSession()->register('collapsedContent', $collapsedContent); | |
180 | } | |
181 | } | |
182 | ||
183 | /** | |
184 | * Marks content as opened, thus removing the collapsed marking. | |
185 | * | |
186 | * @param int $objectTypeID | |
187 | * @param string $objectID | |
188 | */ | |
189 | public function markAsOpened($objectTypeID, $objectID) | |
190 | { | |
191 | if (WCF::getUser()->userID) { | |
192 | $sql = "DELETE FROM wcf" . WCF_N . "_user_collapsible_content | |
193 | WHERE objectTypeID = ? | |
194 | AND objectID = ? | |
195 | AND userID = ?"; | |
196 | $statement = WCF::getDB()->prepareStatement($sql); | |
197 | $statement->execute([ | |
198 | $objectTypeID, | |
199 | $objectID, | |
200 | WCF::getUser()->userID, | |
201 | ]); | |
202 | ||
203 | // reset storage | |
204 | UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'collapsedContent-' . $objectTypeID); | |
205 | } else { | |
206 | $collapsedContent = WCF::getSession()->getVar('collapsedContent'); | |
207 | if ($collapsedContent === null || !\is_array($collapsedContent)) { | |
208 | $collapsedContent = []; | |
209 | } | |
210 | ||
211 | if (isset($collapsedContent[$objectTypeID])) { | |
212 | foreach ($collapsedContent[$objectTypeID] as $index => $collapsedObjectID) { | |
213 | if ($collapsedObjectID == $objectID) { | |
214 | unset($collapsedContent[$objectTypeID][$index]); | |
215 | } | |
216 | } | |
217 | } | |
218 | ||
219 | WCF::getSession()->register('collapsedContent', $collapsedContent); | |
220 | } | |
221 | } | |
222 | ||
223 | /** | |
224 | * Deletes all saved states for a specific object type. | |
225 | * | |
226 | * @param int $objectTypeID | |
227 | */ | |
228 | public function reset($objectTypeID) | |
229 | { | |
230 | if (WCF::getUser()->userID) { | |
231 | $sql = "DELETE FROM wcf" . WCF_N . "_user_collapsible_content | |
232 | WHERE objectTypeID = ? | |
233 | AND userID = ?"; | |
234 | $statement = WCF::getDB()->prepareStatement($sql); | |
235 | $statement->execute([ | |
236 | $objectTypeID, | |
237 | WCF::getUser()->userID, | |
238 | ]); | |
239 | ||
240 | // reset storage | |
241 | UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'collapsedContent-' . $objectTypeID); | |
242 | } else { | |
243 | $collapsedContent = WCF::getSession()->getVar('collapsedContent'); | |
244 | if ($collapsedContent === null || !\is_array($collapsedContent)) { | |
245 | $collapsedContent = []; | |
246 | } | |
247 | ||
248 | if (isset($collapsedContent[$objectTypeID])) { | |
249 | unset($collapsedContent[$objectTypeID]); | |
250 | } | |
251 | ||
252 | WCF::getSession()->register('collapsedContent', $collapsedContent); | |
253 | } | |
254 | } | |
255 | ||
256 | /** | |
257 | * Deletes the saved states for a specific object or all objects of a | |
258 | * specific object type for all users. | |
259 | * | |
260 | * @param string $objectType | |
261 | * @param int $objectID | |
262 | * @throws InvalidObjectTypeException | |
263 | */ | |
264 | public function resetAll($objectType, $objectID = null) | |
265 | { | |
266 | $objectTypeID = $this->getObjectTypeID($objectType); | |
267 | if (!$objectTypeID) { | |
268 | throw new InvalidObjectTypeException($objectType, 'com.woltlab.wcf.collapsibleContent'); | |
269 | } | |
270 | ||
271 | $conditionBuilder = new PreparedStatementConditionBuilder(); | |
272 | $conditionBuilder->add('objectTypeID = ?', [$objectTypeID]); | |
273 | if ($objectID) { | |
274 | $conditionBuilder->add('objectID = ?', [$objectID]); | |
275 | } | |
276 | ||
277 | $sql = "DELETE FROM wcf" . WCF_N . "_user_collapsible_content | |
278 | " . $conditionBuilder; | |
279 | $statement = WCF::getDB()->prepareStatement($sql); | |
280 | $statement->execute($conditionBuilder->getParameters()); | |
281 | ||
282 | UserStorageHandler::getInstance()->resetAll('collapsedContent-' . $objectTypeID); | |
283 | } | |
efc4e026 | 284 | } |