Commit | Line | Data |
---|---|---|
11ade432 AE |
1 | <?php |
2 | namespace wcf\data; | |
11ade432 AE |
3 | use wcf\system\event\EventHandler; |
4 | use wcf\system\exception\PermissionDeniedException; | |
4e877829 | 5 | use wcf\system\exception\SystemException; |
11ade432 AE |
6 | use wcf\system\exception\ValidateActionException; |
7 | use wcf\system\WCF; | |
8 | use wcf\util\ClassUtil; | |
9 | use wcf\util\StringUtil; | |
10 | ||
11 | /** | |
12 | * Default implementation for DatabaseObject-related actions. | |
13 | * | |
14 | * @author Alexander Ebert | |
15 | * @copyright 2001-2011 WoltLab GmbH | |
16 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> | |
17 | * @package com.woltlab.wcf | |
18 | * @subpackage data | |
19 | * @category Community Framework | |
20 | */ | |
a427a8c8 | 21 | abstract class AbstractDatabaseObjectAction implements IDatabaseObjectAction, IDeleteAction { |
11ade432 AE |
22 | /** |
23 | * pending action | |
11ade432 AE |
24 | * @var string |
25 | */ | |
26 | protected $action = ''; | |
27 | ||
28 | /** | |
29 | * object editor class name | |
11ade432 AE |
30 | * @var string |
31 | */ | |
32 | protected $className = ''; | |
33 | ||
34 | /** | |
35 | * list of object ids | |
11ade432 AE |
36 | * @var array<integer> |
37 | */ | |
38 | protected $objectIDs = array(); | |
39 | ||
40 | /** | |
832371b2 | 41 | * list of object editors |
a2554026 | 42 | * @var array<wcf\data\DatabaseObjectEditor> |
11ade432 AE |
43 | */ |
44 | protected $objects = array(); | |
45 | ||
46 | /** | |
47 | * multi-dimensional array of parameters required by an action | |
11ade432 AE |
48 | * @var array<array> |
49 | */ | |
50 | protected $parameters = array(); | |
51 | ||
52 | /** | |
53 | * list of permissions required to create objects | |
832371b2 | 54 | * @var array<string> |
11ade432 AE |
55 | */ |
56 | protected $permissionsCreate = array(); | |
57 | ||
58 | /** | |
59 | * list of permissions required to delete objects | |
832371b2 | 60 | * @var array<string> |
11ade432 AE |
61 | */ |
62 | protected $permissionsDelete = array(); | |
63 | ||
64 | /** | |
65 | * list of permissions required to update objects | |
832371b2 | 66 | * @var array<string> |
11ade432 AE |
67 | */ |
68 | protected $permissionsUpdate = array(); | |
69 | ||
70 | /** | |
71 | * values returned by executed action | |
11ade432 AE |
72 | * @var mixed |
73 | */ | |
74 | protected $returnValues = null; | |
75 | ||
fca077a6 | 76 | /** |
878d0d80 AE |
77 | * allows guest access for all specified methods, by default |
78 | * guest access is completely disabled | |
79 | * @var array<string> | |
fca077a6 | 80 | */ |
878d0d80 | 81 | protected $allowGuestAccess = array(); |
fca077a6 | 82 | |
11ade432 | 83 | /** |
a90028e5 | 84 | * Initialize a new DatabaseObject-related action. |
11ade432 | 85 | * |
4e877829 | 86 | * @param array<mixed> $objects |
11ade432 AE |
87 | * @param string $action |
88 | * @param array $parameters | |
89 | */ | |
4e877829 | 90 | public function __construct(array $objects, $action, array $parameters = array()) { |
7703d974 MS |
91 | // set class name |
92 | if (empty($this->className)) { | |
93 | $className = get_called_class(); | |
94 | ||
95 | if (StringUtil::substring($className, -6) == 'Action') { | |
96 | $this->className = StringUtil::substring($className, 0, -6).'Editor'; | |
97 | } | |
98 | } | |
99 | ||
4e877829 MW |
100 | $indexName = call_user_func(array($this->className, 'getDatabaseTableIndexName')); |
101 | $baseClass = call_user_func(array($this->className, 'getBaseClass')); | |
102 | ||
103 | foreach ($objects as $object) { | |
104 | if (is_object($object)) { | |
105 | if ($object instanceof $this->className) { | |
106 | $this->objects[] = $object; | |
107 | } | |
108 | else if ($object instanceof $baseClass) { | |
109 | $this->objects[] = new $this->className($object); | |
110 | } | |
111 | else { | |
112 | throw new SystemException('invalid value of parameter objects given'); | |
113 | } | |
114 | ||
115 | $this->objectIDs[] = $object->$indexName; | |
116 | } | |
4e877829 | 117 | else { |
f28efd50 | 118 | $this->objectIDs[] = $object; |
4e877829 MW |
119 | } |
120 | } | |
121 | ||
11ade432 AE |
122 | $this->action = $action; |
123 | $this->parameters = $parameters; | |
124 | ||
125 | // fire event action | |
126 | EventHandler::getInstance()->fireAction($this, 'initializeAction'); | |
127 | } | |
128 | ||
129 | /** | |
a2554026 | 130 | * @see wcf\data\IDatabaseObjectAction::validateAction() |
11ade432 AE |
131 | */ |
132 | public function validateAction() { | |
fca077a6 | 133 | // validate if user is logged in |
878d0d80 | 134 | if (!WCF::getUser()->userID && !in_array($this->getActionName(), $this->allowGuestAccess)) { |
fca077a6 AE |
135 | throw new ValidateActionException("Please login before executing this action"); |
136 | } | |
137 | ||
11ade432 AE |
138 | // validate action name |
139 | if (!method_exists($this, $this->getActionName())) { | |
140 | throw new ValidateActionException("unknown action '".$this->getActionName()."'"); | |
141 | } | |
142 | ||
143 | $actionName = 'validate'.StringUtil::firstCharToUpperCase($this->getActionName()); | |
144 | if (!method_exists($this, $actionName)) { | |
145 | throw new ValidateActionException("validation of action '".$this->getActionName()."' failed"); | |
146 | } | |
147 | ||
148 | // execute action | |
149 | call_user_func_array(array($this, $actionName), $this->getParameters()); | |
150 | } | |
151 | ||
152 | /** | |
a2554026 | 153 | * @see wcf\data\IDatabaseObjectAction::executeAction() |
11ade432 AE |
154 | */ |
155 | public function executeAction() { | |
156 | // execute action | |
157 | if (method_exists($this, $this->getActionName())) { | |
158 | $this->returnValues = call_user_func_array(array($this, $this->getActionName()), $this->getParameters()); | |
159 | } | |
160 | ||
161 | // reset cache | |
b522d4f1 | 162 | if (ClassUtil::isInstanceOf($this->className, 'wcf\data\IEditableCachedObject')) { |
11ade432 AE |
163 | call_user_func(array($this->className, 'resetCache')); |
164 | } | |
165 | ||
166 | // fire event action | |
167 | EventHandler::getInstance()->fireAction($this, 'finalizeAction'); | |
168 | ||
169 | return $this->getReturnValues(); | |
170 | } | |
171 | ||
172 | /** | |
b522d4f1 | 173 | * @see wcf\data\IDatabaseObjectAction::getActionName() |
11ade432 AE |
174 | */ |
175 | public function getActionName() { | |
176 | return $this->action; | |
177 | } | |
178 | ||
179 | /** | |
b522d4f1 | 180 | * @see wcf\data\IDatabaseObjectAction::getObjectIDs() |
11ade432 AE |
181 | */ |
182 | public function getObjectIDs() { | |
183 | return $this->objectIDs; | |
184 | } | |
185 | ||
e9aeabca MW |
186 | /** |
187 | * Sets the database objects. | |
188 | * | |
189 | * @param array<wcf\data\DatabaseObject> $objects | |
190 | */ | |
191 | public function setObjects(array $objects) { | |
192 | $this->objects = $objects; | |
193 | } | |
194 | ||
11ade432 | 195 | /** |
b522d4f1 | 196 | * @see wcf\data\IDatabaseObjectAction::getParameters() |
11ade432 AE |
197 | */ |
198 | public function getParameters() { | |
199 | return $this->parameters; | |
200 | } | |
201 | ||
202 | /** | |
b522d4f1 | 203 | * @see wcf\data\IDatabaseObjectAction::getReturnValues() |
11ade432 AE |
204 | */ |
205 | public function getReturnValues() { | |
206 | return array( | |
207 | 'objectIDs' => $this->getObjectIDs(), | |
208 | 'returnValues' => $this->returnValues | |
209 | ); | |
210 | } | |
211 | ||
212 | /** | |
213 | * Validates permissions and parameters. | |
214 | */ | |
215 | public function validateCreate() { | |
216 | // validate permissions | |
217 | if (is_array($this->permissionsCreate) && count($this->permissionsCreate)) { | |
218 | try { | |
7c720e36 | 219 | WCF::getSession()->checkPermissions($this->permissionsCreate); |
11ade432 AE |
220 | } |
221 | catch (PermissionDeniedException $e) { | |
222 | throw new ValidateActionException('Insufficient permissions'); | |
223 | } | |
224 | } | |
225 | else { | |
226 | throw new ValidateActionException('Insufficient permissions'); | |
227 | } | |
228 | } | |
229 | ||
230 | /** | |
a427a8c8 | 231 | * @see wcf\data\IDeleteAction::validateDelete() |
11ade432 AE |
232 | */ |
233 | public function validateDelete() { | |
234 | // validate permissions | |
235 | if (is_array($this->permissionsDelete) && count($this->permissionsDelete)) { | |
236 | try { | |
7c720e36 | 237 | WCF::getSession()->checkPermissions($this->permissionsDelete); |
11ade432 AE |
238 | } |
239 | catch (PermissionDeniedException $e) { | |
240 | throw new ValidateActionException('Insufficient permissions'); | |
241 | } | |
242 | } | |
243 | else { | |
244 | throw new ValidateActionException('Insufficient permissions'); | |
245 | } | |
246 | ||
046f3d7b | 247 | // read objects |
e9aeabca MW |
248 | if (!count($this->objects)) { |
249 | $this->readObjects(); | |
250 | } | |
11ade432 AE |
251 | |
252 | if (!count($this->objects)) { | |
253 | throw new ValidateActionException('Invalid object id'); | |
254 | } | |
255 | } | |
256 | ||
257 | /** | |
258 | * Validates permissions and parameters. | |
259 | */ | |
260 | public function validateUpdate() { | |
261 | // validate permissions | |
262 | if (is_array($this->permissionsUpdate) && count($this->permissionsUpdate)) { | |
263 | try { | |
7c720e36 | 264 | WCF::getSession()->checkPermissions($this->permissionsUpdate); |
11ade432 AE |
265 | } |
266 | catch (PermissionDeniedException $e) { | |
267 | throw new ValidateActionException('Insufficient permissions'); | |
268 | } | |
269 | } | |
270 | else { | |
271 | throw new ValidateActionException('Insufficient permissions'); | |
272 | } | |
273 | ||
046f3d7b | 274 | // read objects |
e9aeabca MW |
275 | if (!count($this->objects)) { |
276 | $this->readObjects(); | |
277 | } | |
11ade432 AE |
278 | |
279 | if (!count($this->objects)) { | |
280 | throw new ValidateActionException('Invalid object id'); | |
281 | } | |
282 | } | |
283 | ||
284 | /** | |
832371b2 | 285 | * Creates new database object. |
11ade432 | 286 | * |
a2554026 | 287 | * @return wcf\data\DatabaseObject |
11ade432 AE |
288 | */ |
289 | public function create() { | |
11ade432 AE |
290 | return call_user_func(array($this->className, 'create'), $this->parameters['data']); |
291 | } | |
292 | ||
293 | /** | |
a427a8c8 | 294 | * @see wcf\data\IDeleteAction::delete() |
11ade432 AE |
295 | */ |
296 | public function delete() { | |
297 | if (!count($this->objects)) { | |
298 | $this->readObjects(); | |
299 | } | |
300 | ||
301 | // get index name | |
302 | $indexName = call_user_func(array($this->className, 'getDatabaseTableIndexName')); | |
303 | ||
304 | // get ids | |
305 | $objectIDs = array(); | |
306 | foreach ($this->objects as $object) { | |
307 | $objectIDs[] = $object->__get($indexName); | |
308 | } | |
309 | ||
310 | // execute action | |
311 | return call_user_func(array($this->className, 'deleteAll'), $objectIDs); | |
312 | } | |
313 | ||
314 | /** | |
315 | * Updates data. | |
316 | */ | |
317 | public function update() { | |
318 | if (!count($this->objects)) { | |
319 | $this->readObjects(); | |
320 | } | |
321 | ||
046f3d7b MS |
322 | if (isset($this->parameters['data'])) { |
323 | foreach ($this->objects as $object) { | |
324 | $object->update($this->parameters['data']); | |
325 | } | |
11ade432 AE |
326 | } |
327 | } | |
328 | ||
329 | /** | |
330 | * Reads data by data id. | |
331 | */ | |
332 | protected function readObjects() { | |
333 | if (!count($this->objectIDs)) { | |
334 | return; | |
335 | } | |
336 | ||
337 | // get base class | |
338 | $baseClass = call_user_func(array($this->className, 'getBaseClass')); | |
339 | ||
340 | // get db information | |
341 | $tableName = call_user_func(array($this->className, 'getDatabaseTableName')); | |
342 | $indexName = call_user_func(array($this->className, 'getDatabaseTableIndexName')); | |
343 | ||
344 | // get objects | |
345 | $sql = "SELECT * | |
346 | FROM ".$tableName." | |
347 | WHERE ".$indexName." IN (".str_repeat('?,', count($this->objectIDs) - 1)."?)"; | |
348 | $statement = WCF::getDB()->prepareStatement($sql); | |
349 | $statement->execute($this->objectIDs); | |
350 | while ($object = $statement->fetchObject($baseClass)) { | |
351 | $this->objects[] = new $this->className($object); | |
352 | } | |
353 | } | |
764fe46c AE |
354 | |
355 | /** | |
356 | * Returns object class name. | |
357 | * | |
358 | * @return string | |
359 | */ | |
360 | public function getClassName() { | |
361 | return $this->className; | |
362 | } | |
363 | ||
364 | /** | |
365 | * Returns a list of currently loaded objects. | |
366 | * | |
367 | * @return array<wcf\data\IEditableObject> | |
368 | */ | |
369 | public function getObjects() { | |
370 | return $this->objects; | |
371 | } | |
11ade432 | 372 | } |