@@ -301,7 +301,7 @@ discard block |
||
301 | 301 | * @param string $name The name of the collection. |
302 | 302 | * @param int $owner_guid The GUID of the owner (default: currently logged in user). |
303 | 303 | * |
304 | - * @return int|false The collection ID if successful and false on failure. |
|
304 | + * @return integer The collection ID if successful and false on failure. |
|
305 | 305 | * @see update_access_collection() |
306 | 306 | * @see delete_access_collection() |
307 | 307 | */ |
@@ -517,7 +517,7 @@ discard block |
||
517 | 517 | * @param string $type |
518 | 518 | * @param array $value |
519 | 519 | * @param array $params |
520 | - * @return array |
|
520 | + * @return string[] |
|
521 | 521 | * |
522 | 522 | * @access private |
523 | 523 | */ |
@@ -44,7 +44,7 @@ discard block |
||
44 | 44 | * @see elgg_get_ignore_access() |
45 | 45 | */ |
46 | 46 | function elgg_set_ignore_access($ignore = true) { |
47 | - return _elgg_services()->session->setIgnoreAccess($ignore); |
|
47 | + return _elgg_services()->session->setIgnoreAccess($ignore); |
|
48 | 48 | } |
49 | 49 | |
50 | 50 | /** |
@@ -55,7 +55,7 @@ discard block |
||
55 | 55 | * @see elgg_set_ignore_access() |
56 | 56 | */ |
57 | 57 | function elgg_get_ignore_access() { |
58 | - return _elgg_services()->session->getIgnoreAccess(); |
|
58 | + return _elgg_services()->session->getIgnoreAccess(); |
|
59 | 59 | } |
60 | 60 | |
61 | 61 | /** |
@@ -74,7 +74,7 @@ discard block |
||
74 | 74 | * @access private |
75 | 75 | */ |
76 | 76 | function get_access_list($user_guid = 0, $ignored = 0, $flush = false) { |
77 | - return _elgg_services()->accessCollections->getAccessList($user_guid, $flush); |
|
77 | + return _elgg_services()->accessCollections->getAccessList($user_guid, $flush); |
|
78 | 78 | } |
79 | 79 | |
80 | 80 | /** |
@@ -103,7 +103,7 @@ discard block |
||
103 | 103 | * @return array An array of access collections ids |
104 | 104 | */ |
105 | 105 | function get_access_array($user_guid = 0, $ignored = 0, $flush = false) { |
106 | - return _elgg_services()->accessCollections->getAccessArray($user_guid, $flush); |
|
106 | + return _elgg_services()->accessCollections->getAccessArray($user_guid, $flush); |
|
107 | 107 | } |
108 | 108 | |
109 | 109 | /** |
@@ -119,26 +119,26 @@ discard block |
||
119 | 119 | * @return int default access id (see ACCESS defines in elgglib.php) |
120 | 120 | */ |
121 | 121 | function get_default_access(ElggUser $user = null, array $input_params = []) { |
122 | - // site default access |
|
123 | - $default_access = _elgg_config()->default_access; |
|
124 | - |
|
125 | - // user default access if enabled |
|
126 | - if (_elgg_config()->allow_user_default_access) { |
|
127 | - $user = $user ? $user : _elgg_services()->session->getLoggedInUser(); |
|
128 | - if ($user) { |
|
129 | - $user_access = $user->getPrivateSetting('elgg_default_access'); |
|
130 | - if ($user_access !== null) { |
|
131 | - $default_access = $user_access; |
|
132 | - } |
|
133 | - } |
|
134 | - } |
|
135 | - |
|
136 | - $params = [ |
|
137 | - 'user' => $user, |
|
138 | - 'default_access' => $default_access, |
|
139 | - 'input_params' => $input_params, |
|
140 | - ]; |
|
141 | - return _elgg_services()->hooks->trigger('default', 'access', $params, $default_access); |
|
122 | + // site default access |
|
123 | + $default_access = _elgg_config()->default_access; |
|
124 | + |
|
125 | + // user default access if enabled |
|
126 | + if (_elgg_config()->allow_user_default_access) { |
|
127 | + $user = $user ? $user : _elgg_services()->session->getLoggedInUser(); |
|
128 | + if ($user) { |
|
129 | + $user_access = $user->getPrivateSetting('elgg_default_access'); |
|
130 | + if ($user_access !== null) { |
|
131 | + $default_access = $user_access; |
|
132 | + } |
|
133 | + } |
|
134 | + } |
|
135 | + |
|
136 | + $params = [ |
|
137 | + 'user' => $user, |
|
138 | + 'default_access' => $default_access, |
|
139 | + 'input_params' => $input_params, |
|
140 | + ]; |
|
141 | + return _elgg_services()->hooks->trigger('default', 'access', $params, $default_access); |
|
142 | 142 | } |
143 | 143 | |
144 | 144 | /** |
@@ -157,10 +157,10 @@ discard block |
||
157 | 157 | * @return bool |
158 | 158 | */ |
159 | 159 | function access_show_hidden_entities($show_hidden) { |
160 | - global $ENTITY_SHOW_HIDDEN_OVERRIDE; |
|
161 | - $current_value = $ENTITY_SHOW_HIDDEN_OVERRIDE; |
|
162 | - $ENTITY_SHOW_HIDDEN_OVERRIDE = $show_hidden; |
|
163 | - return $current_value; |
|
160 | + global $ENTITY_SHOW_HIDDEN_OVERRIDE; |
|
161 | + $current_value = $ENTITY_SHOW_HIDDEN_OVERRIDE; |
|
162 | + $ENTITY_SHOW_HIDDEN_OVERRIDE = $show_hidden; |
|
163 | + return $current_value; |
|
164 | 164 | } |
165 | 165 | |
166 | 166 | /** |
@@ -169,8 +169,8 @@ discard block |
||
169 | 169 | * @return bool |
170 | 170 | */ |
171 | 171 | function access_get_show_hidden_status() { |
172 | - global $ENTITY_SHOW_HIDDEN_OVERRIDE; |
|
173 | - return $ENTITY_SHOW_HIDDEN_OVERRIDE; |
|
172 | + global $ENTITY_SHOW_HIDDEN_OVERRIDE; |
|
173 | + return $ENTITY_SHOW_HIDDEN_OVERRIDE; |
|
174 | 174 | } |
175 | 175 | |
176 | 176 | /** |
@@ -213,7 +213,7 @@ discard block |
||
213 | 213 | * @access private |
214 | 214 | */ |
215 | 215 | function _elgg_get_access_where_sql(array $options = []) { |
216 | - return _elgg_services()->accessCollections->getWhereSql($options); |
|
216 | + return _elgg_services()->accessCollections->getWhereSql($options); |
|
217 | 217 | } |
218 | 218 | |
219 | 219 | /** |
@@ -236,7 +236,7 @@ discard block |
||
236 | 236 | * @return bool |
237 | 237 | */ |
238 | 238 | function has_access_to_entity($entity, $user = null) { |
239 | - return _elgg_services()->accessCollections->hasAccessToEntity($entity, $user); |
|
239 | + return _elgg_services()->accessCollections->hasAccessToEntity($entity, $user); |
|
240 | 240 | } |
241 | 241 | |
242 | 242 | /** |
@@ -266,7 +266,7 @@ discard block |
||
266 | 266 | * @return array List of access permissions |
267 | 267 | */ |
268 | 268 | function get_write_access_array($user_guid = 0, $ignored = 0, $flush = false, array $input_params = []) { |
269 | - return _elgg_services()->accessCollections->getWriteAccessArray($user_guid, $flush, $input_params); |
|
269 | + return _elgg_services()->accessCollections->getWriteAccessArray($user_guid, $flush, $input_params); |
|
270 | 270 | } |
271 | 271 | |
272 | 272 | /** |
@@ -284,7 +284,7 @@ discard block |
||
284 | 284 | * @return bool |
285 | 285 | */ |
286 | 286 | function can_edit_access_collection($collection_id, $user_guid = null) { |
287 | - return _elgg_services()->accessCollections->canEdit($collection_id, $user_guid); |
|
287 | + return _elgg_services()->accessCollections->canEdit($collection_id, $user_guid); |
|
288 | 288 | } |
289 | 289 | |
290 | 290 | /** |
@@ -306,7 +306,7 @@ discard block |
||
306 | 306 | * @see delete_access_collection() |
307 | 307 | */ |
308 | 308 | function create_access_collection($name, $owner_guid = 0) { |
309 | - return _elgg_services()->accessCollections->create($name, $owner_guid); |
|
309 | + return _elgg_services()->accessCollections->create($name, $owner_guid); |
|
310 | 310 | } |
311 | 311 | |
312 | 312 | /** |
@@ -326,7 +326,7 @@ discard block |
||
326 | 326 | * @see remove_user_from_access_collection() |
327 | 327 | */ |
328 | 328 | function update_access_collection($collection_id, $members) { |
329 | - return _elgg_services()->accessCollections->update($collection_id, $members); |
|
329 | + return _elgg_services()->accessCollections->update($collection_id, $members); |
|
330 | 330 | } |
331 | 331 | |
332 | 332 | /** |
@@ -339,7 +339,7 @@ discard block |
||
339 | 339 | * @see update_access_collection() |
340 | 340 | */ |
341 | 341 | function delete_access_collection($collection_id) { |
342 | - return _elgg_services()->accessCollections->delete($collection_id); |
|
342 | + return _elgg_services()->accessCollections->delete($collection_id); |
|
343 | 343 | } |
344 | 344 | |
345 | 345 | /** |
@@ -355,7 +355,7 @@ discard block |
||
355 | 355 | * @return ElggAccessCollection|false |
356 | 356 | */ |
357 | 357 | function get_access_collection($collection_id) { |
358 | - return _elgg_services()->accessCollections->get($collection_id); |
|
358 | + return _elgg_services()->accessCollections->get($collection_id); |
|
359 | 359 | } |
360 | 360 | |
361 | 361 | /** |
@@ -371,7 +371,7 @@ discard block |
||
371 | 371 | * @see remove_user_from_access_collection() |
372 | 372 | */ |
373 | 373 | function add_user_to_access_collection($user_guid, $collection_id) { |
374 | - return _elgg_services()->accessCollections->addUser($user_guid, $collection_id); |
|
374 | + return _elgg_services()->accessCollections->addUser($user_guid, $collection_id); |
|
375 | 375 | } |
376 | 376 | |
377 | 377 | /** |
@@ -387,7 +387,7 @@ discard block |
||
387 | 387 | * @see remove_user_from_access_collection() |
388 | 388 | */ |
389 | 389 | function remove_user_from_access_collection($user_guid, $collection_id) { |
390 | - return _elgg_services()->accessCollections->removeUser($user_guid, $collection_id); |
|
390 | + return _elgg_services()->accessCollections->removeUser($user_guid, $collection_id); |
|
391 | 391 | } |
392 | 392 | |
393 | 393 | /** |
@@ -400,7 +400,7 @@ discard block |
||
400 | 400 | * @return \ElggAccessCollection[]|false |
401 | 401 | */ |
402 | 402 | function get_user_access_collections($owner_guid) { |
403 | - return _elgg_services()->accessCollections->getEntityCollections($owner_guid); |
|
403 | + return _elgg_services()->accessCollections->getEntityCollections($owner_guid); |
|
404 | 404 | } |
405 | 405 | |
406 | 406 | /** |
@@ -414,21 +414,21 @@ discard block |
||
414 | 414 | * @see add_user_to_access_collection() |
415 | 415 | */ |
416 | 416 | function get_members_of_access_collection($collection_id, $guids_only = false, array $options = []) { |
417 | - if (!isset($options['limit'])) { |
|
418 | - $options['limit'] = 0; |
|
419 | - } |
|
420 | - |
|
421 | - if (!$guids_only) { |
|
422 | - return _elgg_services()->accessCollections->getMembers($collection_id, $options); |
|
423 | - } |
|
424 | - |
|
425 | - $guids = []; |
|
426 | - $options['callback'] = false; |
|
427 | - $rows = _elgg_services()->accessCollections->getMembers($collection_id, $options); |
|
428 | - foreach ($rows as $row) { |
|
429 | - $guids[] = $row->guid; |
|
430 | - } |
|
431 | - return $guids; |
|
417 | + if (!isset($options['limit'])) { |
|
418 | + $options['limit'] = 0; |
|
419 | + } |
|
420 | + |
|
421 | + if (!$guids_only) { |
|
422 | + return _elgg_services()->accessCollections->getMembers($collection_id, $options); |
|
423 | + } |
|
424 | + |
|
425 | + $guids = []; |
|
426 | + $options['callback'] = false; |
|
427 | + $rows = _elgg_services()->accessCollections->getMembers($collection_id, $options); |
|
428 | + foreach ($rows as $row) { |
|
429 | + $guids[] = $row->guid; |
|
430 | + } |
|
431 | + return $guids; |
|
432 | 432 | } |
433 | 433 | |
434 | 434 | /** |
@@ -444,25 +444,25 @@ discard block |
||
444 | 444 | * @since 1.7.0 |
445 | 445 | */ |
446 | 446 | function elgg_get_entities_from_access_id(array $options = []) { |
447 | - // restrict the resultset to access collection provided |
|
448 | - if (!isset($options['access_id'])) { |
|
449 | - return false; |
|
450 | - } |
|
451 | - |
|
452 | - // @todo add support for an array of collection_ids |
|
453 | - $where = "e.access_id = '{$options['access_id']}'"; |
|
454 | - if (isset($options['wheres'])) { |
|
455 | - if (is_array($options['wheres'])) { |
|
456 | - $options['wheres'][] = $where; |
|
457 | - } else { |
|
458 | - $options['wheres'] = [$options['wheres'], $where]; |
|
459 | - } |
|
460 | - } else { |
|
461 | - $options['wheres'] = [$where]; |
|
462 | - } |
|
463 | - |
|
464 | - // return entities with the desired options |
|
465 | - return _elgg_services()->entityTable->getEntities($options); |
|
447 | + // restrict the resultset to access collection provided |
|
448 | + if (!isset($options['access_id'])) { |
|
449 | + return false; |
|
450 | + } |
|
451 | + |
|
452 | + // @todo add support for an array of collection_ids |
|
453 | + $where = "e.access_id = '{$options['access_id']}'"; |
|
454 | + if (isset($options['wheres'])) { |
|
455 | + if (is_array($options['wheres'])) { |
|
456 | + $options['wheres'][] = $where; |
|
457 | + } else { |
|
458 | + $options['wheres'] = [$options['wheres'], $where]; |
|
459 | + } |
|
460 | + } else { |
|
461 | + $options['wheres'] = [$where]; |
|
462 | + } |
|
463 | + |
|
464 | + // return entities with the desired options |
|
465 | + return _elgg_services()->entityTable->getEntities($options); |
|
466 | 466 | } |
467 | 467 | |
468 | 468 | /** |
@@ -476,7 +476,7 @@ discard block |
||
476 | 476 | * @return string |
477 | 477 | */ |
478 | 478 | function elgg_list_entities_from_access_id(array $options = []) { |
479 | - return elgg_list_entities($options, 'elgg_get_entities_from_access_id'); |
|
479 | + return elgg_list_entities($options, 'elgg_get_entities_from_access_id'); |
|
480 | 480 | } |
481 | 481 | |
482 | 482 | /** |
@@ -496,7 +496,7 @@ discard block |
||
496 | 496 | * @since 1.7.0 |
497 | 497 | */ |
498 | 498 | function get_readable_access_level($entity_access_id) { |
499 | - return _elgg_services()->accessCollections->getReadableAccessLevel($entity_access_id); |
|
499 | + return _elgg_services()->accessCollections->getReadableAccessLevel($entity_access_id); |
|
500 | 500 | } |
501 | 501 | |
502 | 502 | /** |
@@ -507,7 +507,7 @@ discard block |
||
507 | 507 | * @return void |
508 | 508 | */ |
509 | 509 | function access_init() { |
510 | - _elgg_services()->accessCollections->markInitComplete(); |
|
510 | + _elgg_services()->accessCollections->markInitComplete(); |
|
511 | 511 | } |
512 | 512 | |
513 | 513 | /** |
@@ -522,18 +522,18 @@ discard block |
||
522 | 522 | * @access private |
523 | 523 | */ |
524 | 524 | function access_test($hook, $type, $value, $params) { |
525 | - $value[] = Paths::elgg() . 'engine/tests/ElggCoreAccessCollectionsTest.php'; |
|
526 | - $value[] = Paths::elgg() . 'engine/tests/ElggCoreAccessSQLTest.php'; |
|
527 | - return $value; |
|
525 | + $value[] = Paths::elgg() . 'engine/tests/ElggCoreAccessCollectionsTest.php'; |
|
526 | + $value[] = Paths::elgg() . 'engine/tests/ElggCoreAccessSQLTest.php'; |
|
527 | + return $value; |
|
528 | 528 | } |
529 | 529 | |
530 | 530 | /** |
531 | 531 | * @see \Elgg\Application::loadCore Do not do work here. Just register for events. |
532 | 532 | */ |
533 | 533 | return function(\Elgg\EventsService $events, \Elgg\HooksRegistrationService $hooks) { |
534 | - // Tell the access functions the system has booted, plugins are loaded, |
|
535 | - // and the user is logged in so it can start caching |
|
536 | - $events->registerHandler('ready', 'system', 'access_init'); |
|
534 | + // Tell the access functions the system has booted, plugins are loaded, |
|
535 | + // and the user is logged in so it can start caching |
|
536 | + $events->registerHandler('ready', 'system', 'access_init'); |
|
537 | 537 | |
538 | - $hooks->registerHandler('unit_test', 'system', 'access_test'); |
|
538 | + $hooks->registerHandler('unit_test', 'system', 'access_test'); |
|
539 | 539 | }; |
@@ -34,1414 +34,1414 @@ |
||
34 | 34 | */ |
35 | 35 | class ElggInstaller { |
36 | 36 | |
37 | - private $steps = [ |
|
38 | - 'welcome', |
|
39 | - 'requirements', |
|
40 | - 'database', |
|
41 | - 'settings', |
|
42 | - 'admin', |
|
43 | - 'complete', |
|
44 | - ]; |
|
45 | - |
|
46 | - private $has_completed = [ |
|
47 | - 'config' => false, |
|
48 | - 'database' => false, |
|
49 | - 'settings' => false, |
|
50 | - 'admin' => false, |
|
51 | - ]; |
|
52 | - |
|
53 | - private $is_action = false; |
|
54 | - |
|
55 | - private $autoLogin = true; |
|
56 | - |
|
57 | - /** |
|
58 | - * @var ServiceProvider |
|
59 | - */ |
|
60 | - private $services; |
|
61 | - |
|
62 | - /** |
|
63 | - * @var Config |
|
64 | - */ |
|
65 | - private $config; |
|
66 | - |
|
67 | - /** |
|
68 | - * @var Application |
|
69 | - */ |
|
70 | - private $app; |
|
71 | - |
|
72 | - /** |
|
73 | - * Dispatches a request to one of the step controllers |
|
74 | - * |
|
75 | - * @return void |
|
76 | - * @throws InstallationException |
|
77 | - */ |
|
78 | - public function run() { |
|
79 | - $this->getApp(); |
|
80 | - |
|
81 | - $this->is_action = $this->services->request->getMethod() === 'POST'; |
|
82 | - |
|
83 | - $step = get_input('step', 'welcome'); |
|
84 | - |
|
85 | - if (!in_array($step, $this->getSteps())) { |
|
86 | - $msg = elgg_echo('InstallationException:UnknownStep', [$step]); |
|
87 | - throw new InstallationException($msg); |
|
88 | - } |
|
89 | - |
|
90 | - $this->determineInstallStatus(); |
|
37 | + private $steps = [ |
|
38 | + 'welcome', |
|
39 | + 'requirements', |
|
40 | + 'database', |
|
41 | + 'settings', |
|
42 | + 'admin', |
|
43 | + 'complete', |
|
44 | + ]; |
|
45 | + |
|
46 | + private $has_completed = [ |
|
47 | + 'config' => false, |
|
48 | + 'database' => false, |
|
49 | + 'settings' => false, |
|
50 | + 'admin' => false, |
|
51 | + ]; |
|
52 | + |
|
53 | + private $is_action = false; |
|
54 | + |
|
55 | + private $autoLogin = true; |
|
56 | + |
|
57 | + /** |
|
58 | + * @var ServiceProvider |
|
59 | + */ |
|
60 | + private $services; |
|
61 | + |
|
62 | + /** |
|
63 | + * @var Config |
|
64 | + */ |
|
65 | + private $config; |
|
66 | + |
|
67 | + /** |
|
68 | + * @var Application |
|
69 | + */ |
|
70 | + private $app; |
|
71 | + |
|
72 | + /** |
|
73 | + * Dispatches a request to one of the step controllers |
|
74 | + * |
|
75 | + * @return void |
|
76 | + * @throws InstallationException |
|
77 | + */ |
|
78 | + public function run() { |
|
79 | + $this->getApp(); |
|
80 | + |
|
81 | + $this->is_action = $this->services->request->getMethod() === 'POST'; |
|
82 | + |
|
83 | + $step = get_input('step', 'welcome'); |
|
84 | + |
|
85 | + if (!in_array($step, $this->getSteps())) { |
|
86 | + $msg = elgg_echo('InstallationException:UnknownStep', [$step]); |
|
87 | + throw new InstallationException($msg); |
|
88 | + } |
|
89 | + |
|
90 | + $this->determineInstallStatus(); |
|
91 | 91 | |
92 | - $this->checkInstallCompletion($step); |
|
93 | - |
|
94 | - // check if this is an install being resumed |
|
95 | - $this->resumeInstall($step); |
|
96 | - |
|
97 | - $this->finishBootstrapping($step); |
|
98 | - |
|
99 | - $params = $this->services->request->request->all(); |
|
100 | - |
|
101 | - $method = "run" . ucwords($step); |
|
102 | - $this->$method($params); |
|
103 | - } |
|
104 | - |
|
105 | - /** |
|
106 | - * Build the application needed by the installer |
|
107 | - * |
|
108 | - * @return Application |
|
109 | - * @throws InstallationException |
|
110 | - */ |
|
111 | - protected function getApp() { |
|
112 | - if ($this->app) { |
|
113 | - return $this->app; |
|
114 | - } |
|
115 | - |
|
116 | - $config = new Config(); |
|
117 | - $config->elgg_config_locks = false; |
|
118 | - $config->installer_running = true; |
|
119 | - $config->dbencoding = 'utf8mb4'; |
|
120 | - |
|
121 | - $this->config = $config; |
|
122 | - $this->services = new ServiceProvider($config); |
|
123 | - |
|
124 | - $app = Application::factory([ |
|
125 | - 'service_provider' => $this->services, |
|
126 | - 'handle_exceptions' => false, |
|
127 | - 'handle_shutdown' => false, |
|
128 | - ]); |
|
129 | - |
|
130 | - // Don't set global $CONFIG, because loading the settings file may require it to write to |
|
131 | - // it, and it can have array sets (e.g. cookie config) that fail when using a proxy for |
|
132 | - // the config service. |
|
133 | - //$app->setGlobalConfig(); |
|
134 | - |
|
135 | - Application::setInstance($app); |
|
136 | - $app->loadCore(); |
|
137 | - $this->app = $app; |
|
138 | - |
|
139 | - $this->services->setValue('session', \ElggSession::getMock()); |
|
140 | - $this->services->views->setViewtype('installation'); |
|
141 | - $this->services->views->registerPluginViews(Paths::elgg()); |
|
142 | - $this->services->translator->registerTranslations(Paths::elgg() . "install/languages/", true); |
|
143 | - |
|
144 | - return $this->app; |
|
145 | - } |
|
146 | - |
|
147 | - /** |
|
148 | - * Set the auto login flag |
|
149 | - * |
|
150 | - * @param bool $flag Auto login |
|
151 | - * |
|
152 | - * @return void |
|
153 | - */ |
|
154 | - public function setAutoLogin($flag) { |
|
155 | - $this->autoLogin = (bool) $flag; |
|
156 | - } |
|
157 | - |
|
158 | - /** |
|
159 | - * A batch install of Elgg |
|
160 | - * |
|
161 | - * All required parameters must be passed in as an associative array. See |
|
162 | - * $requiredParams for a list of them. This creates the necessary files, |
|
163 | - * loads the database, configures the site settings, and creates the admin |
|
164 | - * account. If it fails, an exception is thrown. It does not check any of |
|
165 | - * the requirements as the multiple step web installer does. |
|
166 | - * |
|
167 | - * @param array $params Array of key value pairs |
|
168 | - * @param bool $create_htaccess Should .htaccess be created |
|
169 | - * |
|
170 | - * @return void |
|
171 | - * @throws InstallationException |
|
172 | - */ |
|
173 | - public function batchInstall(array $params, $create_htaccess = false) { |
|
174 | - $this->getApp(); |
|
175 | - |
|
176 | - $defaults = [ |
|
177 | - 'dbhost' => 'localhost', |
|
178 | - 'dbprefix' => 'elgg_', |
|
179 | - 'language' => 'en', |
|
180 | - 'siteaccess' => ACCESS_PUBLIC, |
|
181 | - ]; |
|
182 | - $params = array_merge($defaults, $params); |
|
183 | - |
|
184 | - $required_params = [ |
|
185 | - 'dbuser', |
|
186 | - 'dbpassword', |
|
187 | - 'dbname', |
|
188 | - 'sitename', |
|
189 | - 'wwwroot', |
|
190 | - 'dataroot', |
|
191 | - 'displayname', |
|
192 | - 'email', |
|
193 | - 'username', |
|
194 | - 'password', |
|
195 | - ]; |
|
196 | - foreach ($required_params as $key) { |
|
197 | - if (empty($params[$key])) { |
|
198 | - $msg = elgg_echo('install:error:requiredfield', [$key]); |
|
199 | - throw new InstallationException($msg); |
|
200 | - } |
|
201 | - } |
|
202 | - |
|
203 | - // password is passed in once |
|
204 | - $params['password1'] = $params['password2'] = $params['password']; |
|
205 | - |
|
206 | - if ($create_htaccess) { |
|
207 | - $rewrite_tester = new ElggRewriteTester(); |
|
208 | - if (!$rewrite_tester->createHtaccess($params['wwwroot'])) { |
|
209 | - throw new InstallationException(elgg_echo('install:error:htaccess')); |
|
210 | - } |
|
211 | - } |
|
212 | - |
|
213 | - $this->determineInstallStatus(); |
|
214 | - |
|
215 | - if (!$this->has_completed['config']) { |
|
216 | - if (!$this->createSettingsFile($params)) { |
|
217 | - throw new InstallationException(elgg_echo('install:error:settings')); |
|
218 | - } |
|
219 | - } |
|
220 | - |
|
221 | - $this->loadSettingsFile(); |
|
222 | - |
|
223 | - // Make sure settings file matches parameters |
|
224 | - $config = $this->config; |
|
225 | - $config_keys = [ |
|
226 | - // param key => config key |
|
227 | - 'dbhost' => 'dbhost', |
|
228 | - 'dbuser' => 'dbuser', |
|
229 | - 'dbpassword' => 'dbpass', |
|
230 | - 'dbname' => 'dbname', |
|
231 | - 'dataroot' => 'dataroot', |
|
232 | - 'dbprefix' => 'dbprefix', |
|
233 | - ]; |
|
234 | - foreach ($config_keys as $params_key => $config_key) { |
|
235 | - if ($params[$params_key] !== $config->$config_key) { |
|
236 | - throw new InstallationException(elgg_echo('install:error:settings_mismatch', [$config_key])); |
|
237 | - } |
|
238 | - } |
|
239 | - |
|
240 | - if (!$this->connectToDatabase()) { |
|
241 | - throw new InstallationException(elgg_echo('install:error:databasesettings')); |
|
242 | - } |
|
243 | - |
|
244 | - if (!$this->has_completed['database']) { |
|
245 | - if (!$this->installDatabase()) { |
|
246 | - throw new InstallationException(elgg_echo('install:error:cannotloadtables')); |
|
247 | - } |
|
248 | - } |
|
249 | - |
|
250 | - // load remaining core libraries |
|
251 | - $this->finishBootstrapping('settings'); |
|
252 | - |
|
253 | - if (!$this->saveSiteSettings($params)) { |
|
254 | - throw new InstallationException(elgg_echo('install:error:savesitesettings')); |
|
255 | - } |
|
256 | - |
|
257 | - if (!$this->createAdminAccount($params)) { |
|
258 | - throw new InstallationException(elgg_echo('install:admin:cannot_create')); |
|
259 | - } |
|
260 | - } |
|
261 | - |
|
262 | - /** |
|
263 | - * Renders the data passed by a controller |
|
264 | - * |
|
265 | - * @param string $step The current step |
|
266 | - * @param array $vars Array of vars to pass to the view |
|
267 | - * |
|
268 | - * @return void |
|
269 | - */ |
|
270 | - protected function render($step, $vars = []) { |
|
271 | - $vars['next_step'] = $this->getNextStep($step); |
|
272 | - |
|
273 | - $title = elgg_echo("install:$step"); |
|
274 | - $body = elgg_view("install/pages/$step", $vars); |
|
92 | + $this->checkInstallCompletion($step); |
|
93 | + |
|
94 | + // check if this is an install being resumed |
|
95 | + $this->resumeInstall($step); |
|
96 | + |
|
97 | + $this->finishBootstrapping($step); |
|
98 | + |
|
99 | + $params = $this->services->request->request->all(); |
|
100 | + |
|
101 | + $method = "run" . ucwords($step); |
|
102 | + $this->$method($params); |
|
103 | + } |
|
104 | + |
|
105 | + /** |
|
106 | + * Build the application needed by the installer |
|
107 | + * |
|
108 | + * @return Application |
|
109 | + * @throws InstallationException |
|
110 | + */ |
|
111 | + protected function getApp() { |
|
112 | + if ($this->app) { |
|
113 | + return $this->app; |
|
114 | + } |
|
115 | + |
|
116 | + $config = new Config(); |
|
117 | + $config->elgg_config_locks = false; |
|
118 | + $config->installer_running = true; |
|
119 | + $config->dbencoding = 'utf8mb4'; |
|
120 | + |
|
121 | + $this->config = $config; |
|
122 | + $this->services = new ServiceProvider($config); |
|
123 | + |
|
124 | + $app = Application::factory([ |
|
125 | + 'service_provider' => $this->services, |
|
126 | + 'handle_exceptions' => false, |
|
127 | + 'handle_shutdown' => false, |
|
128 | + ]); |
|
129 | + |
|
130 | + // Don't set global $CONFIG, because loading the settings file may require it to write to |
|
131 | + // it, and it can have array sets (e.g. cookie config) that fail when using a proxy for |
|
132 | + // the config service. |
|
133 | + //$app->setGlobalConfig(); |
|
134 | + |
|
135 | + Application::setInstance($app); |
|
136 | + $app->loadCore(); |
|
137 | + $this->app = $app; |
|
138 | + |
|
139 | + $this->services->setValue('session', \ElggSession::getMock()); |
|
140 | + $this->services->views->setViewtype('installation'); |
|
141 | + $this->services->views->registerPluginViews(Paths::elgg()); |
|
142 | + $this->services->translator->registerTranslations(Paths::elgg() . "install/languages/", true); |
|
143 | + |
|
144 | + return $this->app; |
|
145 | + } |
|
146 | + |
|
147 | + /** |
|
148 | + * Set the auto login flag |
|
149 | + * |
|
150 | + * @param bool $flag Auto login |
|
151 | + * |
|
152 | + * @return void |
|
153 | + */ |
|
154 | + public function setAutoLogin($flag) { |
|
155 | + $this->autoLogin = (bool) $flag; |
|
156 | + } |
|
157 | + |
|
158 | + /** |
|
159 | + * A batch install of Elgg |
|
160 | + * |
|
161 | + * All required parameters must be passed in as an associative array. See |
|
162 | + * $requiredParams for a list of them. This creates the necessary files, |
|
163 | + * loads the database, configures the site settings, and creates the admin |
|
164 | + * account. If it fails, an exception is thrown. It does not check any of |
|
165 | + * the requirements as the multiple step web installer does. |
|
166 | + * |
|
167 | + * @param array $params Array of key value pairs |
|
168 | + * @param bool $create_htaccess Should .htaccess be created |
|
169 | + * |
|
170 | + * @return void |
|
171 | + * @throws InstallationException |
|
172 | + */ |
|
173 | + public function batchInstall(array $params, $create_htaccess = false) { |
|
174 | + $this->getApp(); |
|
175 | + |
|
176 | + $defaults = [ |
|
177 | + 'dbhost' => 'localhost', |
|
178 | + 'dbprefix' => 'elgg_', |
|
179 | + 'language' => 'en', |
|
180 | + 'siteaccess' => ACCESS_PUBLIC, |
|
181 | + ]; |
|
182 | + $params = array_merge($defaults, $params); |
|
183 | + |
|
184 | + $required_params = [ |
|
185 | + 'dbuser', |
|
186 | + 'dbpassword', |
|
187 | + 'dbname', |
|
188 | + 'sitename', |
|
189 | + 'wwwroot', |
|
190 | + 'dataroot', |
|
191 | + 'displayname', |
|
192 | + 'email', |
|
193 | + 'username', |
|
194 | + 'password', |
|
195 | + ]; |
|
196 | + foreach ($required_params as $key) { |
|
197 | + if (empty($params[$key])) { |
|
198 | + $msg = elgg_echo('install:error:requiredfield', [$key]); |
|
199 | + throw new InstallationException($msg); |
|
200 | + } |
|
201 | + } |
|
202 | + |
|
203 | + // password is passed in once |
|
204 | + $params['password1'] = $params['password2'] = $params['password']; |
|
205 | + |
|
206 | + if ($create_htaccess) { |
|
207 | + $rewrite_tester = new ElggRewriteTester(); |
|
208 | + if (!$rewrite_tester->createHtaccess($params['wwwroot'])) { |
|
209 | + throw new InstallationException(elgg_echo('install:error:htaccess')); |
|
210 | + } |
|
211 | + } |
|
212 | + |
|
213 | + $this->determineInstallStatus(); |
|
214 | + |
|
215 | + if (!$this->has_completed['config']) { |
|
216 | + if (!$this->createSettingsFile($params)) { |
|
217 | + throw new InstallationException(elgg_echo('install:error:settings')); |
|
218 | + } |
|
219 | + } |
|
220 | + |
|
221 | + $this->loadSettingsFile(); |
|
222 | + |
|
223 | + // Make sure settings file matches parameters |
|
224 | + $config = $this->config; |
|
225 | + $config_keys = [ |
|
226 | + // param key => config key |
|
227 | + 'dbhost' => 'dbhost', |
|
228 | + 'dbuser' => 'dbuser', |
|
229 | + 'dbpassword' => 'dbpass', |
|
230 | + 'dbname' => 'dbname', |
|
231 | + 'dataroot' => 'dataroot', |
|
232 | + 'dbprefix' => 'dbprefix', |
|
233 | + ]; |
|
234 | + foreach ($config_keys as $params_key => $config_key) { |
|
235 | + if ($params[$params_key] !== $config->$config_key) { |
|
236 | + throw new InstallationException(elgg_echo('install:error:settings_mismatch', [$config_key])); |
|
237 | + } |
|
238 | + } |
|
239 | + |
|
240 | + if (!$this->connectToDatabase()) { |
|
241 | + throw new InstallationException(elgg_echo('install:error:databasesettings')); |
|
242 | + } |
|
243 | + |
|
244 | + if (!$this->has_completed['database']) { |
|
245 | + if (!$this->installDatabase()) { |
|
246 | + throw new InstallationException(elgg_echo('install:error:cannotloadtables')); |
|
247 | + } |
|
248 | + } |
|
249 | + |
|
250 | + // load remaining core libraries |
|
251 | + $this->finishBootstrapping('settings'); |
|
252 | + |
|
253 | + if (!$this->saveSiteSettings($params)) { |
|
254 | + throw new InstallationException(elgg_echo('install:error:savesitesettings')); |
|
255 | + } |
|
256 | + |
|
257 | + if (!$this->createAdminAccount($params)) { |
|
258 | + throw new InstallationException(elgg_echo('install:admin:cannot_create')); |
|
259 | + } |
|
260 | + } |
|
261 | + |
|
262 | + /** |
|
263 | + * Renders the data passed by a controller |
|
264 | + * |
|
265 | + * @param string $step The current step |
|
266 | + * @param array $vars Array of vars to pass to the view |
|
267 | + * |
|
268 | + * @return void |
|
269 | + */ |
|
270 | + protected function render($step, $vars = []) { |
|
271 | + $vars['next_step'] = $this->getNextStep($step); |
|
272 | + |
|
273 | + $title = elgg_echo("install:$step"); |
|
274 | + $body = elgg_view("install/pages/$step", $vars); |
|
275 | 275 | |
276 | - echo elgg_view_page( |
|
277 | - $title, |
|
278 | - $body, |
|
279 | - 'default', |
|
280 | - [ |
|
281 | - 'step' => $step, |
|
282 | - 'steps' => $this->getSteps(), |
|
283 | - ] |
|
284 | - ); |
|
285 | - exit; |
|
286 | - } |
|
287 | - |
|
288 | - /** |
|
289 | - * Step controllers |
|
290 | - */ |
|
291 | - |
|
292 | - /** |
|
293 | - * Welcome controller |
|
294 | - * |
|
295 | - * @param array $vars Not used |
|
296 | - * |
|
297 | - * @return void |
|
298 | - */ |
|
299 | - protected function runWelcome($vars) { |
|
300 | - $this->render('welcome'); |
|
301 | - } |
|
302 | - |
|
303 | - /** |
|
304 | - * Requirements controller |
|
305 | - * |
|
306 | - * Checks version of php, libraries, permissions, and rewrite rules |
|
307 | - * |
|
308 | - * @param array $vars Vars |
|
309 | - * |
|
310 | - * @return void |
|
311 | - */ |
|
312 | - protected function runRequirements($vars) { |
|
313 | - |
|
314 | - $report = []; |
|
315 | - |
|
316 | - // check PHP parameters and libraries |
|
317 | - $this->checkPHP($report); |
|
318 | - |
|
319 | - // check URL rewriting |
|
320 | - $this->checkRewriteRules($report); |
|
321 | - |
|
322 | - // check for existence of settings file |
|
323 | - if ($this->checkSettingsFile($report) != true) { |
|
324 | - // no file, so check permissions on engine directory |
|
325 | - $this->isInstallDirWritable($report); |
|
326 | - } |
|
327 | - |
|
328 | - // check the database later |
|
329 | - $report['database'] = [[ |
|
330 | - 'severity' => 'info', |
|
331 | - 'message' => elgg_echo('install:check:database') |
|
332 | - ]]; |
|
333 | - |
|
334 | - // any failures? |
|
335 | - $numFailures = $this->countNumConditions($report, 'failure'); |
|
336 | - |
|
337 | - // any warnings |
|
338 | - $numWarnings = $this->countNumConditions($report, 'warning'); |
|
339 | - |
|
340 | - |
|
341 | - $params = [ |
|
342 | - 'report' => $report, |
|
343 | - 'num_failures' => $numFailures, |
|
344 | - 'num_warnings' => $numWarnings, |
|
345 | - ]; |
|
346 | - |
|
347 | - $this->render('requirements', $params); |
|
348 | - } |
|
349 | - |
|
350 | - /** |
|
351 | - * Database set up controller |
|
352 | - * |
|
353 | - * Creates the settings.php file and creates the database tables |
|
354 | - * |
|
355 | - * @param array $submissionVars Submitted form variables |
|
356 | - * |
|
357 | - * @return void |
|
358 | - */ |
|
359 | - protected function runDatabase($submissionVars) { |
|
360 | - |
|
361 | - $formVars = [ |
|
362 | - 'dbuser' => [ |
|
363 | - 'type' => 'text', |
|
364 | - 'value' => '', |
|
365 | - 'required' => true, |
|
366 | - ], |
|
367 | - 'dbpassword' => [ |
|
368 | - 'type' => 'password', |
|
369 | - 'value' => '', |
|
370 | - 'required' => false, |
|
371 | - ], |
|
372 | - 'dbname' => [ |
|
373 | - 'type' => 'text', |
|
374 | - 'value' => '', |
|
375 | - 'required' => true, |
|
376 | - ], |
|
377 | - 'dbhost' => [ |
|
378 | - 'type' => 'text', |
|
379 | - 'value' => 'localhost', |
|
380 | - 'required' => true, |
|
381 | - ], |
|
382 | - 'dbprefix' => [ |
|
383 | - 'type' => 'text', |
|
384 | - 'value' => 'elgg_', |
|
385 | - 'required' => true, |
|
386 | - ], |
|
387 | - 'dataroot' => [ |
|
388 | - 'type' => 'text', |
|
389 | - 'value' => '', |
|
390 | - 'required' => true, |
|
391 | - ], |
|
392 | - 'wwwroot' => [ |
|
393 | - 'type' => 'url', |
|
394 | - 'value' => _elgg_services()->config->wwwroot, |
|
395 | - 'required' => true, |
|
396 | - ], |
|
397 | - 'timezone' => [ |
|
398 | - 'type' => 'dropdown', |
|
399 | - 'value' => 'UTC', |
|
400 | - 'options' => \DateTimeZone::listIdentifiers(), |
|
401 | - 'required' => true |
|
402 | - ] |
|
403 | - ]; |
|
404 | - |
|
405 | - if ($this->checkSettingsFile()) { |
|
406 | - // user manually created settings file so we fake out action test |
|
407 | - $this->is_action = true; |
|
408 | - } |
|
409 | - |
|
410 | - if ($this->is_action) { |
|
411 | - call_user_func(function () use ($submissionVars, $formVars) { |
|
412 | - // only create settings file if it doesn't exist |
|
413 | - if (!$this->checkSettingsFile()) { |
|
414 | - if (!$this->validateDatabaseVars($submissionVars, $formVars)) { |
|
415 | - // error so we break out of action and serve same page |
|
416 | - return; |
|
417 | - } |
|
418 | - |
|
419 | - if (!$this->createSettingsFile($submissionVars)) { |
|
420 | - return; |
|
421 | - } |
|
422 | - } |
|
423 | - |
|
424 | - // check db version and connect |
|
425 | - if (!$this->connectToDatabase()) { |
|
426 | - return; |
|
427 | - } |
|
428 | - |
|
429 | - if (!$this->installDatabase()) { |
|
430 | - return; |
|
431 | - } |
|
432 | - |
|
433 | - system_message(elgg_echo('install:success:database')); |
|
434 | - |
|
435 | - $this->continueToNextStep('database'); |
|
436 | - }); |
|
437 | - } |
|
438 | - |
|
439 | - $formVars = $this->makeFormSticky($formVars, $submissionVars); |
|
440 | - |
|
441 | - $params = ['variables' => $formVars,]; |
|
442 | - |
|
443 | - if ($this->checkSettingsFile()) { |
|
444 | - // settings file exists and we're here so failed to create database |
|
445 | - $params['failure'] = true; |
|
446 | - } |
|
447 | - |
|
448 | - $this->render('database', $params); |
|
449 | - } |
|
450 | - |
|
451 | - /** |
|
452 | - * Site settings controller |
|
453 | - * |
|
454 | - * Sets the site name, URL, data directory, etc. |
|
455 | - * |
|
456 | - * @param array $submissionVars Submitted vars |
|
457 | - * |
|
458 | - * @return void |
|
459 | - */ |
|
460 | - protected function runSettings($submissionVars) { |
|
461 | - $formVars = [ |
|
462 | - 'sitename' => [ |
|
463 | - 'type' => 'text', |
|
464 | - 'value' => 'My New Community', |
|
465 | - 'required' => true, |
|
466 | - ], |
|
467 | - 'siteemail' => [ |
|
468 | - 'type' => 'email', |
|
469 | - 'value' => '', |
|
470 | - 'required' => false, |
|
471 | - ], |
|
472 | - 'siteaccess' => [ |
|
473 | - 'type' => 'access', |
|
474 | - 'value' => ACCESS_PUBLIC, |
|
475 | - 'required' => true, |
|
476 | - ], |
|
477 | - ]; |
|
478 | - |
|
479 | - if ($this->is_action) { |
|
480 | - call_user_func(function () use ($submissionVars, $formVars) { |
|
481 | - if (!$this->validateSettingsVars($submissionVars, $formVars)) { |
|
482 | - return; |
|
483 | - } |
|
484 | - |
|
485 | - if (!$this->saveSiteSettings($submissionVars)) { |
|
486 | - return; |
|
487 | - } |
|
488 | - |
|
489 | - system_message(elgg_echo('install:success:settings')); |
|
490 | - |
|
491 | - $this->continueToNextStep('settings'); |
|
492 | - }); |
|
493 | - } |
|
494 | - |
|
495 | - $formVars = $this->makeFormSticky($formVars, $submissionVars); |
|
496 | - |
|
497 | - $this->render('settings', ['variables' => $formVars]); |
|
498 | - } |
|
499 | - |
|
500 | - /** |
|
501 | - * Admin account controller |
|
502 | - * |
|
503 | - * Creates an admin user account |
|
504 | - * |
|
505 | - * @param array $submissionVars Submitted vars |
|
506 | - * |
|
507 | - * @return void |
|
508 | - */ |
|
509 | - protected function runAdmin($submissionVars) { |
|
510 | - $formVars = [ |
|
511 | - 'displayname' => [ |
|
512 | - 'type' => 'text', |
|
513 | - 'value' => '', |
|
514 | - 'required' => true, |
|
515 | - ], |
|
516 | - 'email' => [ |
|
517 | - 'type' => 'email', |
|
518 | - 'value' => '', |
|
519 | - 'required' => true, |
|
520 | - ], |
|
521 | - 'username' => [ |
|
522 | - 'type' => 'text', |
|
523 | - 'value' => '', |
|
524 | - 'required' => true, |
|
525 | - ], |
|
526 | - 'password1' => [ |
|
527 | - 'type' => 'password', |
|
528 | - 'value' => '', |
|
529 | - 'required' => true, |
|
530 | - 'pattern' => '.{6,}', |
|
531 | - ], |
|
532 | - 'password2' => [ |
|
533 | - 'type' => 'password', |
|
534 | - 'value' => '', |
|
535 | - 'required' => true, |
|
536 | - ], |
|
537 | - ]; |
|
538 | - |
|
539 | - if ($this->is_action) { |
|
540 | - call_user_func(function () use ($submissionVars, $formVars) { |
|
541 | - if (!$this->validateAdminVars($submissionVars, $formVars)) { |
|
542 | - return; |
|
543 | - } |
|
544 | - |
|
545 | - if (!$this->createAdminAccount($submissionVars, $this->autoLogin)) { |
|
546 | - return; |
|
547 | - } |
|
548 | - |
|
549 | - system_message(elgg_echo('install:success:admin')); |
|
550 | - |
|
551 | - $this->continueToNextStep('admin'); |
|
552 | - }); |
|
553 | - } |
|
554 | - |
|
555 | - // Bit of a hack to get the password help to show right number of characters |
|
556 | - // We burn the value into the stored translation. |
|
557 | - $lang = $this->services->translator->getCurrentLanguage(); |
|
558 | - $translations = $this->services->translator->getLoadedTranslations(); |
|
559 | - $this->services->translator->addTranslation($lang, [ |
|
560 | - 'install:admin:help:password1' => sprintf( |
|
561 | - $translations[$lang]['install:admin:help:password1'], |
|
562 | - $this->config->min_password_length |
|
563 | - ), |
|
564 | - ]); |
|
565 | - |
|
566 | - $formVars = $this->makeFormSticky($formVars, $submissionVars); |
|
567 | - |
|
568 | - $this->render('admin', ['variables' => $formVars]); |
|
569 | - } |
|
570 | - |
|
571 | - /** |
|
572 | - * Controller for last step |
|
573 | - * |
|
574 | - * @return void |
|
575 | - */ |
|
576 | - protected function runComplete() { |
|
577 | - |
|
578 | - // nudge to check out settings |
|
579 | - $link = elgg_format_element([ |
|
580 | - '#tag_name' => 'a', |
|
581 | - '#text' => elgg_echo('install:complete:admin_notice:link_text'), |
|
582 | - 'href' => elgg_normalize_url('admin/settings/basic'), |
|
583 | - ]); |
|
584 | - $notice = elgg_echo('install:complete:admin_notice', [$link]); |
|
585 | - elgg_add_admin_notice('fresh_install', $notice); |
|
586 | - |
|
587 | - $this->render('complete'); |
|
588 | - } |
|
589 | - |
|
590 | - /** |
|
591 | - * Step management |
|
592 | - */ |
|
593 | - |
|
594 | - /** |
|
595 | - * Get an array of steps |
|
596 | - * |
|
597 | - * @return array |
|
598 | - */ |
|
599 | - protected function getSteps() { |
|
600 | - return $this->steps; |
|
601 | - } |
|
602 | - |
|
603 | - /** |
|
604 | - * Forwards the browser to the next step |
|
605 | - * |
|
606 | - * @param string $currentStep Current installation step |
|
607 | - * |
|
608 | - * @return void |
|
609 | - */ |
|
610 | - protected function continueToNextStep($currentStep) { |
|
611 | - $this->is_action = false; |
|
612 | - forward($this->getNextStepUrl($currentStep)); |
|
613 | - } |
|
614 | - |
|
615 | - /** |
|
616 | - * Get the next step as a string |
|
617 | - * |
|
618 | - * @param string $currentStep Current installation step |
|
619 | - * |
|
620 | - * @return string |
|
621 | - */ |
|
622 | - protected function getNextStep($currentStep) { |
|
623 | - $index = 1 + array_search($currentStep, $this->steps); |
|
624 | - if (isset($this->steps[$index])) { |
|
625 | - return $this->steps[$index]; |
|
626 | - } else { |
|
627 | - return null; |
|
628 | - } |
|
629 | - } |
|
630 | - |
|
631 | - /** |
|
632 | - * Get the URL of the next step |
|
633 | - * |
|
634 | - * @param string $currentStep Current installation step |
|
635 | - * |
|
636 | - * @return string |
|
637 | - */ |
|
638 | - protected function getNextStepUrl($currentStep) { |
|
639 | - $nextStep = $this->getNextStep($currentStep); |
|
640 | - return $this->config->wwwroot . "install.php?step=$nextStep"; |
|
641 | - } |
|
642 | - |
|
643 | - /** |
|
644 | - * Updates $this->has_completed according to the current installation |
|
645 | - * |
|
646 | - * @return void |
|
647 | - * @throws InstallationException |
|
648 | - */ |
|
649 | - protected function determineInstallStatus() { |
|
650 | - $path = Paths::settingsFile(); |
|
651 | - if (!is_file($path) || !is_readable($path)) { |
|
652 | - return; |
|
653 | - } |
|
654 | - |
|
655 | - $this->loadSettingsFile(); |
|
656 | - |
|
657 | - $this->has_completed['config'] = true; |
|
658 | - |
|
659 | - // must be able to connect to database to jump install steps |
|
660 | - $dbSettingsPass = $this->checkDatabaseSettings( |
|
661 | - $this->config->dbuser, |
|
662 | - $this->config->dbpass, |
|
663 | - $this->config->dbname, |
|
664 | - $this->config->dbhost |
|
665 | - ); |
|
666 | - |
|
667 | - if (!$dbSettingsPass) { |
|
668 | - return; |
|
669 | - } |
|
670 | - |
|
671 | - $db = $this->services->db; |
|
672 | - |
|
673 | - // check that the config table has been created |
|
674 | - $result = $db->getData("SHOW TABLES"); |
|
675 | - if ($result) { |
|
676 | - foreach ($result as $table) { |
|
677 | - $table = (array) $table; |
|
678 | - if (in_array("{$db->prefix}config", $table)) { |
|
679 | - $this->has_completed['database'] = true; |
|
680 | - } |
|
681 | - } |
|
682 | - if ($this->has_completed['database'] == false) { |
|
683 | - return; |
|
684 | - } |
|
685 | - } else { |
|
686 | - // no tables |
|
687 | - return; |
|
688 | - } |
|
689 | - |
|
690 | - // check that the config table has entries |
|
691 | - $query = "SELECT COUNT(*) AS total FROM {$db->prefix}config"; |
|
692 | - $result = $db->getData($query); |
|
693 | - if ($result && $result[0]->total > 0) { |
|
694 | - $this->has_completed['settings'] = true; |
|
695 | - } else { |
|
696 | - return; |
|
697 | - } |
|
698 | - |
|
699 | - // check that the users entity table has an entry |
|
700 | - $query = "SELECT COUNT(*) AS total FROM {$db->prefix}users_entity"; |
|
701 | - $result = $db->getData($query); |
|
702 | - if ($result && $result[0]->total > 0) { |
|
703 | - $this->has_completed['admin'] = true; |
|
704 | - } else { |
|
705 | - return; |
|
706 | - } |
|
707 | - } |
|
708 | - |
|
709 | - /** |
|
710 | - * Security check to ensure the installer cannot be run after installation |
|
711 | - * has finished. If this is detected, the viewer is sent to the front page. |
|
712 | - * |
|
713 | - * @param string $step Installation step to check against |
|
714 | - * |
|
715 | - * @return void |
|
716 | - */ |
|
717 | - protected function checkInstallCompletion($step) { |
|
718 | - if ($step != 'complete') { |
|
719 | - if (!in_array(false, $this->has_completed)) { |
|
720 | - // install complete but someone is trying to view an install page |
|
721 | - forward(); |
|
722 | - } |
|
723 | - } |
|
724 | - } |
|
725 | - |
|
726 | - /** |
|
727 | - * Check if this is a case of a install being resumed and figure |
|
728 | - * out where to continue from. Returns the best guess on the step. |
|
729 | - * |
|
730 | - * @param string $step Installation step to resume from |
|
731 | - * |
|
732 | - * @return string |
|
733 | - */ |
|
734 | - protected function resumeInstall($step) { |
|
735 | - // only do a resume from the first step |
|
736 | - if ($step !== 'welcome') { |
|
737 | - return; |
|
738 | - } |
|
739 | - |
|
740 | - if ($this->has_completed['database'] == false) { |
|
741 | - return; |
|
742 | - } |
|
743 | - |
|
744 | - if ($this->has_completed['settings'] == false) { |
|
745 | - forward("install.php?step=settings"); |
|
746 | - } |
|
747 | - |
|
748 | - if ($this->has_completed['admin'] == false) { |
|
749 | - forward("install.php?step=admin"); |
|
750 | - } |
|
751 | - |
|
752 | - // everything appears to be set up |
|
753 | - forward("install.php?step=complete"); |
|
754 | - } |
|
755 | - |
|
756 | - /** |
|
757 | - * Bootstrapping |
|
758 | - */ |
|
759 | - |
|
760 | - /** |
|
761 | - * Load remaining engine libraries and complete bootstrapping |
|
762 | - * |
|
763 | - * @param string $step Which step to boot strap for. Required because |
|
764 | - * boot strapping is different until the DB is populated. |
|
765 | - * |
|
766 | - * @return void |
|
767 | - * @throws InstallationException |
|
768 | - */ |
|
769 | - protected function finishBootstrapping($step) { |
|
770 | - |
|
771 | - $index_db = array_search('database', $this->getSteps()); |
|
772 | - $index_settings = array_search('settings', $this->getSteps()); |
|
773 | - $index_admin = array_search('admin', $this->getSteps()); |
|
774 | - $index_complete = array_search('complete', $this->getSteps()); |
|
775 | - $index_step = array_search($step, $this->getSteps()); |
|
776 | - |
|
777 | - // To log in the user, we need to use the Elgg core session handling. |
|
778 | - // Otherwise, use default php session handling |
|
779 | - $use_elgg_session = ($index_step == $index_admin && $this->is_action) || ($index_step == $index_complete); |
|
780 | - if (!$use_elgg_session) { |
|
781 | - $session = ElggSession::fromFiles($this->config); |
|
782 | - $session->setName('Elgg_install'); |
|
783 | - $this->services->setValue('session', $session); |
|
784 | - } |
|
785 | - |
|
786 | - if ($index_step > $index_db) { |
|
787 | - // once the database has been created, load rest of engine |
|
788 | - |
|
789 | - // dummy site needed to boot |
|
790 | - $this->config->site = new ElggSite(); |
|
791 | - |
|
792 | - $this->app->bootCore(); |
|
793 | - } |
|
794 | - } |
|
795 | - |
|
796 | - /** |
|
797 | - * Load settings |
|
798 | - * |
|
799 | - * @return void |
|
800 | - * @throws InstallationException |
|
801 | - */ |
|
802 | - protected function loadSettingsFile() { |
|
803 | - try { |
|
804 | - $config = Config::fromFile(Paths::settingsFile()); |
|
805 | - $this->config->mergeValues($config->getValues()); |
|
806 | - |
|
807 | - // in case the DB instance is already captured in services, we re-inject its settings. |
|
808 | - $this->services->db->resetConnections(DbConfig::fromElggConfig($this->config)); |
|
809 | - } catch (\Exception $e) { |
|
810 | - $msg = elgg_echo('InstallationException:CannotLoadSettings'); |
|
811 | - throw new InstallationException($msg, 0, $e); |
|
812 | - } |
|
813 | - } |
|
814 | - |
|
815 | - /** |
|
816 | - * Action handling methods |
|
817 | - */ |
|
818 | - |
|
819 | - /** |
|
820 | - * If form is reshown, remember previously submitted variables |
|
821 | - * |
|
822 | - * @param array $formVars Vars int he form |
|
823 | - * @param array $submissionVars Submitted vars |
|
824 | - * |
|
825 | - * @return array |
|
826 | - */ |
|
827 | - protected function makeFormSticky($formVars, $submissionVars) { |
|
828 | - foreach ($submissionVars as $field => $value) { |
|
829 | - $formVars[$field]['value'] = $value; |
|
830 | - } |
|
831 | - return $formVars; |
|
832 | - } |
|
833 | - |
|
834 | - /* Requirement checks support methods */ |
|
835 | - |
|
836 | - /** |
|
837 | - * Indicates whether the webserver can add settings.php on its own or not. |
|
838 | - * |
|
839 | - * @param array $report The requirements report object |
|
840 | - * |
|
841 | - * @return bool |
|
842 | - */ |
|
843 | - protected function isInstallDirWritable(&$report) { |
|
844 | - if (!is_writable(Paths::projectConfig())) { |
|
845 | - $msg = elgg_echo('install:check:installdir', [Paths::PATH_TO_CONFIG]); |
|
846 | - $report['settings'] = [ |
|
847 | - [ |
|
848 | - 'severity' => 'failure', |
|
849 | - 'message' => $msg, |
|
850 | - ] |
|
851 | - ]; |
|
852 | - return false; |
|
853 | - } |
|
854 | - |
|
855 | - return true; |
|
856 | - } |
|
857 | - |
|
858 | - /** |
|
859 | - * Check that the settings file exists |
|
860 | - * |
|
861 | - * @param array $report The requirements report array |
|
862 | - * |
|
863 | - * @return bool |
|
864 | - */ |
|
865 | - protected function checkSettingsFile(&$report = []) { |
|
866 | - if (!is_file(Paths::settingsFile())) { |
|
867 | - return false; |
|
868 | - } |
|
869 | - |
|
870 | - if (!is_readable(Paths::settingsFile())) { |
|
871 | - $report['settings'] = [ |
|
872 | - [ |
|
873 | - 'severity' => 'failure', |
|
874 | - 'message' => elgg_echo('install:check:readsettings'), |
|
875 | - ] |
|
876 | - ]; |
|
877 | - } |
|
276 | + echo elgg_view_page( |
|
277 | + $title, |
|
278 | + $body, |
|
279 | + 'default', |
|
280 | + [ |
|
281 | + 'step' => $step, |
|
282 | + 'steps' => $this->getSteps(), |
|
283 | + ] |
|
284 | + ); |
|
285 | + exit; |
|
286 | + } |
|
287 | + |
|
288 | + /** |
|
289 | + * Step controllers |
|
290 | + */ |
|
291 | + |
|
292 | + /** |
|
293 | + * Welcome controller |
|
294 | + * |
|
295 | + * @param array $vars Not used |
|
296 | + * |
|
297 | + * @return void |
|
298 | + */ |
|
299 | + protected function runWelcome($vars) { |
|
300 | + $this->render('welcome'); |
|
301 | + } |
|
302 | + |
|
303 | + /** |
|
304 | + * Requirements controller |
|
305 | + * |
|
306 | + * Checks version of php, libraries, permissions, and rewrite rules |
|
307 | + * |
|
308 | + * @param array $vars Vars |
|
309 | + * |
|
310 | + * @return void |
|
311 | + */ |
|
312 | + protected function runRequirements($vars) { |
|
313 | + |
|
314 | + $report = []; |
|
315 | + |
|
316 | + // check PHP parameters and libraries |
|
317 | + $this->checkPHP($report); |
|
318 | + |
|
319 | + // check URL rewriting |
|
320 | + $this->checkRewriteRules($report); |
|
321 | + |
|
322 | + // check for existence of settings file |
|
323 | + if ($this->checkSettingsFile($report) != true) { |
|
324 | + // no file, so check permissions on engine directory |
|
325 | + $this->isInstallDirWritable($report); |
|
326 | + } |
|
327 | + |
|
328 | + // check the database later |
|
329 | + $report['database'] = [[ |
|
330 | + 'severity' => 'info', |
|
331 | + 'message' => elgg_echo('install:check:database') |
|
332 | + ]]; |
|
333 | + |
|
334 | + // any failures? |
|
335 | + $numFailures = $this->countNumConditions($report, 'failure'); |
|
336 | + |
|
337 | + // any warnings |
|
338 | + $numWarnings = $this->countNumConditions($report, 'warning'); |
|
339 | + |
|
340 | + |
|
341 | + $params = [ |
|
342 | + 'report' => $report, |
|
343 | + 'num_failures' => $numFailures, |
|
344 | + 'num_warnings' => $numWarnings, |
|
345 | + ]; |
|
346 | + |
|
347 | + $this->render('requirements', $params); |
|
348 | + } |
|
349 | + |
|
350 | + /** |
|
351 | + * Database set up controller |
|
352 | + * |
|
353 | + * Creates the settings.php file and creates the database tables |
|
354 | + * |
|
355 | + * @param array $submissionVars Submitted form variables |
|
356 | + * |
|
357 | + * @return void |
|
358 | + */ |
|
359 | + protected function runDatabase($submissionVars) { |
|
360 | + |
|
361 | + $formVars = [ |
|
362 | + 'dbuser' => [ |
|
363 | + 'type' => 'text', |
|
364 | + 'value' => '', |
|
365 | + 'required' => true, |
|
366 | + ], |
|
367 | + 'dbpassword' => [ |
|
368 | + 'type' => 'password', |
|
369 | + 'value' => '', |
|
370 | + 'required' => false, |
|
371 | + ], |
|
372 | + 'dbname' => [ |
|
373 | + 'type' => 'text', |
|
374 | + 'value' => '', |
|
375 | + 'required' => true, |
|
376 | + ], |
|
377 | + 'dbhost' => [ |
|
378 | + 'type' => 'text', |
|
379 | + 'value' => 'localhost', |
|
380 | + 'required' => true, |
|
381 | + ], |
|
382 | + 'dbprefix' => [ |
|
383 | + 'type' => 'text', |
|
384 | + 'value' => 'elgg_', |
|
385 | + 'required' => true, |
|
386 | + ], |
|
387 | + 'dataroot' => [ |
|
388 | + 'type' => 'text', |
|
389 | + 'value' => '', |
|
390 | + 'required' => true, |
|
391 | + ], |
|
392 | + 'wwwroot' => [ |
|
393 | + 'type' => 'url', |
|
394 | + 'value' => _elgg_services()->config->wwwroot, |
|
395 | + 'required' => true, |
|
396 | + ], |
|
397 | + 'timezone' => [ |
|
398 | + 'type' => 'dropdown', |
|
399 | + 'value' => 'UTC', |
|
400 | + 'options' => \DateTimeZone::listIdentifiers(), |
|
401 | + 'required' => true |
|
402 | + ] |
|
403 | + ]; |
|
404 | + |
|
405 | + if ($this->checkSettingsFile()) { |
|
406 | + // user manually created settings file so we fake out action test |
|
407 | + $this->is_action = true; |
|
408 | + } |
|
409 | + |
|
410 | + if ($this->is_action) { |
|
411 | + call_user_func(function () use ($submissionVars, $formVars) { |
|
412 | + // only create settings file if it doesn't exist |
|
413 | + if (!$this->checkSettingsFile()) { |
|
414 | + if (!$this->validateDatabaseVars($submissionVars, $formVars)) { |
|
415 | + // error so we break out of action and serve same page |
|
416 | + return; |
|
417 | + } |
|
418 | + |
|
419 | + if (!$this->createSettingsFile($submissionVars)) { |
|
420 | + return; |
|
421 | + } |
|
422 | + } |
|
423 | + |
|
424 | + // check db version and connect |
|
425 | + if (!$this->connectToDatabase()) { |
|
426 | + return; |
|
427 | + } |
|
428 | + |
|
429 | + if (!$this->installDatabase()) { |
|
430 | + return; |
|
431 | + } |
|
432 | + |
|
433 | + system_message(elgg_echo('install:success:database')); |
|
434 | + |
|
435 | + $this->continueToNextStep('database'); |
|
436 | + }); |
|
437 | + } |
|
438 | + |
|
439 | + $formVars = $this->makeFormSticky($formVars, $submissionVars); |
|
440 | + |
|
441 | + $params = ['variables' => $formVars,]; |
|
442 | + |
|
443 | + if ($this->checkSettingsFile()) { |
|
444 | + // settings file exists and we're here so failed to create database |
|
445 | + $params['failure'] = true; |
|
446 | + } |
|
447 | + |
|
448 | + $this->render('database', $params); |
|
449 | + } |
|
450 | + |
|
451 | + /** |
|
452 | + * Site settings controller |
|
453 | + * |
|
454 | + * Sets the site name, URL, data directory, etc. |
|
455 | + * |
|
456 | + * @param array $submissionVars Submitted vars |
|
457 | + * |
|
458 | + * @return void |
|
459 | + */ |
|
460 | + protected function runSettings($submissionVars) { |
|
461 | + $formVars = [ |
|
462 | + 'sitename' => [ |
|
463 | + 'type' => 'text', |
|
464 | + 'value' => 'My New Community', |
|
465 | + 'required' => true, |
|
466 | + ], |
|
467 | + 'siteemail' => [ |
|
468 | + 'type' => 'email', |
|
469 | + 'value' => '', |
|
470 | + 'required' => false, |
|
471 | + ], |
|
472 | + 'siteaccess' => [ |
|
473 | + 'type' => 'access', |
|
474 | + 'value' => ACCESS_PUBLIC, |
|
475 | + 'required' => true, |
|
476 | + ], |
|
477 | + ]; |
|
478 | + |
|
479 | + if ($this->is_action) { |
|
480 | + call_user_func(function () use ($submissionVars, $formVars) { |
|
481 | + if (!$this->validateSettingsVars($submissionVars, $formVars)) { |
|
482 | + return; |
|
483 | + } |
|
484 | + |
|
485 | + if (!$this->saveSiteSettings($submissionVars)) { |
|
486 | + return; |
|
487 | + } |
|
488 | + |
|
489 | + system_message(elgg_echo('install:success:settings')); |
|
490 | + |
|
491 | + $this->continueToNextStep('settings'); |
|
492 | + }); |
|
493 | + } |
|
494 | + |
|
495 | + $formVars = $this->makeFormSticky($formVars, $submissionVars); |
|
496 | + |
|
497 | + $this->render('settings', ['variables' => $formVars]); |
|
498 | + } |
|
499 | + |
|
500 | + /** |
|
501 | + * Admin account controller |
|
502 | + * |
|
503 | + * Creates an admin user account |
|
504 | + * |
|
505 | + * @param array $submissionVars Submitted vars |
|
506 | + * |
|
507 | + * @return void |
|
508 | + */ |
|
509 | + protected function runAdmin($submissionVars) { |
|
510 | + $formVars = [ |
|
511 | + 'displayname' => [ |
|
512 | + 'type' => 'text', |
|
513 | + 'value' => '', |
|
514 | + 'required' => true, |
|
515 | + ], |
|
516 | + 'email' => [ |
|
517 | + 'type' => 'email', |
|
518 | + 'value' => '', |
|
519 | + 'required' => true, |
|
520 | + ], |
|
521 | + 'username' => [ |
|
522 | + 'type' => 'text', |
|
523 | + 'value' => '', |
|
524 | + 'required' => true, |
|
525 | + ], |
|
526 | + 'password1' => [ |
|
527 | + 'type' => 'password', |
|
528 | + 'value' => '', |
|
529 | + 'required' => true, |
|
530 | + 'pattern' => '.{6,}', |
|
531 | + ], |
|
532 | + 'password2' => [ |
|
533 | + 'type' => 'password', |
|
534 | + 'value' => '', |
|
535 | + 'required' => true, |
|
536 | + ], |
|
537 | + ]; |
|
538 | + |
|
539 | + if ($this->is_action) { |
|
540 | + call_user_func(function () use ($submissionVars, $formVars) { |
|
541 | + if (!$this->validateAdminVars($submissionVars, $formVars)) { |
|
542 | + return; |
|
543 | + } |
|
544 | + |
|
545 | + if (!$this->createAdminAccount($submissionVars, $this->autoLogin)) { |
|
546 | + return; |
|
547 | + } |
|
548 | + |
|
549 | + system_message(elgg_echo('install:success:admin')); |
|
550 | + |
|
551 | + $this->continueToNextStep('admin'); |
|
552 | + }); |
|
553 | + } |
|
554 | + |
|
555 | + // Bit of a hack to get the password help to show right number of characters |
|
556 | + // We burn the value into the stored translation. |
|
557 | + $lang = $this->services->translator->getCurrentLanguage(); |
|
558 | + $translations = $this->services->translator->getLoadedTranslations(); |
|
559 | + $this->services->translator->addTranslation($lang, [ |
|
560 | + 'install:admin:help:password1' => sprintf( |
|
561 | + $translations[$lang]['install:admin:help:password1'], |
|
562 | + $this->config->min_password_length |
|
563 | + ), |
|
564 | + ]); |
|
565 | + |
|
566 | + $formVars = $this->makeFormSticky($formVars, $submissionVars); |
|
567 | + |
|
568 | + $this->render('admin', ['variables' => $formVars]); |
|
569 | + } |
|
570 | + |
|
571 | + /** |
|
572 | + * Controller for last step |
|
573 | + * |
|
574 | + * @return void |
|
575 | + */ |
|
576 | + protected function runComplete() { |
|
577 | + |
|
578 | + // nudge to check out settings |
|
579 | + $link = elgg_format_element([ |
|
580 | + '#tag_name' => 'a', |
|
581 | + '#text' => elgg_echo('install:complete:admin_notice:link_text'), |
|
582 | + 'href' => elgg_normalize_url('admin/settings/basic'), |
|
583 | + ]); |
|
584 | + $notice = elgg_echo('install:complete:admin_notice', [$link]); |
|
585 | + elgg_add_admin_notice('fresh_install', $notice); |
|
586 | + |
|
587 | + $this->render('complete'); |
|
588 | + } |
|
589 | + |
|
590 | + /** |
|
591 | + * Step management |
|
592 | + */ |
|
593 | + |
|
594 | + /** |
|
595 | + * Get an array of steps |
|
596 | + * |
|
597 | + * @return array |
|
598 | + */ |
|
599 | + protected function getSteps() { |
|
600 | + return $this->steps; |
|
601 | + } |
|
602 | + |
|
603 | + /** |
|
604 | + * Forwards the browser to the next step |
|
605 | + * |
|
606 | + * @param string $currentStep Current installation step |
|
607 | + * |
|
608 | + * @return void |
|
609 | + */ |
|
610 | + protected function continueToNextStep($currentStep) { |
|
611 | + $this->is_action = false; |
|
612 | + forward($this->getNextStepUrl($currentStep)); |
|
613 | + } |
|
614 | + |
|
615 | + /** |
|
616 | + * Get the next step as a string |
|
617 | + * |
|
618 | + * @param string $currentStep Current installation step |
|
619 | + * |
|
620 | + * @return string |
|
621 | + */ |
|
622 | + protected function getNextStep($currentStep) { |
|
623 | + $index = 1 + array_search($currentStep, $this->steps); |
|
624 | + if (isset($this->steps[$index])) { |
|
625 | + return $this->steps[$index]; |
|
626 | + } else { |
|
627 | + return null; |
|
628 | + } |
|
629 | + } |
|
630 | + |
|
631 | + /** |
|
632 | + * Get the URL of the next step |
|
633 | + * |
|
634 | + * @param string $currentStep Current installation step |
|
635 | + * |
|
636 | + * @return string |
|
637 | + */ |
|
638 | + protected function getNextStepUrl($currentStep) { |
|
639 | + $nextStep = $this->getNextStep($currentStep); |
|
640 | + return $this->config->wwwroot . "install.php?step=$nextStep"; |
|
641 | + } |
|
642 | + |
|
643 | + /** |
|
644 | + * Updates $this->has_completed according to the current installation |
|
645 | + * |
|
646 | + * @return void |
|
647 | + * @throws InstallationException |
|
648 | + */ |
|
649 | + protected function determineInstallStatus() { |
|
650 | + $path = Paths::settingsFile(); |
|
651 | + if (!is_file($path) || !is_readable($path)) { |
|
652 | + return; |
|
653 | + } |
|
654 | + |
|
655 | + $this->loadSettingsFile(); |
|
656 | + |
|
657 | + $this->has_completed['config'] = true; |
|
658 | + |
|
659 | + // must be able to connect to database to jump install steps |
|
660 | + $dbSettingsPass = $this->checkDatabaseSettings( |
|
661 | + $this->config->dbuser, |
|
662 | + $this->config->dbpass, |
|
663 | + $this->config->dbname, |
|
664 | + $this->config->dbhost |
|
665 | + ); |
|
666 | + |
|
667 | + if (!$dbSettingsPass) { |
|
668 | + return; |
|
669 | + } |
|
670 | + |
|
671 | + $db = $this->services->db; |
|
672 | + |
|
673 | + // check that the config table has been created |
|
674 | + $result = $db->getData("SHOW TABLES"); |
|
675 | + if ($result) { |
|
676 | + foreach ($result as $table) { |
|
677 | + $table = (array) $table; |
|
678 | + if (in_array("{$db->prefix}config", $table)) { |
|
679 | + $this->has_completed['database'] = true; |
|
680 | + } |
|
681 | + } |
|
682 | + if ($this->has_completed['database'] == false) { |
|
683 | + return; |
|
684 | + } |
|
685 | + } else { |
|
686 | + // no tables |
|
687 | + return; |
|
688 | + } |
|
689 | + |
|
690 | + // check that the config table has entries |
|
691 | + $query = "SELECT COUNT(*) AS total FROM {$db->prefix}config"; |
|
692 | + $result = $db->getData($query); |
|
693 | + if ($result && $result[0]->total > 0) { |
|
694 | + $this->has_completed['settings'] = true; |
|
695 | + } else { |
|
696 | + return; |
|
697 | + } |
|
698 | + |
|
699 | + // check that the users entity table has an entry |
|
700 | + $query = "SELECT COUNT(*) AS total FROM {$db->prefix}users_entity"; |
|
701 | + $result = $db->getData($query); |
|
702 | + if ($result && $result[0]->total > 0) { |
|
703 | + $this->has_completed['admin'] = true; |
|
704 | + } else { |
|
705 | + return; |
|
706 | + } |
|
707 | + } |
|
708 | + |
|
709 | + /** |
|
710 | + * Security check to ensure the installer cannot be run after installation |
|
711 | + * has finished. If this is detected, the viewer is sent to the front page. |
|
712 | + * |
|
713 | + * @param string $step Installation step to check against |
|
714 | + * |
|
715 | + * @return void |
|
716 | + */ |
|
717 | + protected function checkInstallCompletion($step) { |
|
718 | + if ($step != 'complete') { |
|
719 | + if (!in_array(false, $this->has_completed)) { |
|
720 | + // install complete but someone is trying to view an install page |
|
721 | + forward(); |
|
722 | + } |
|
723 | + } |
|
724 | + } |
|
725 | + |
|
726 | + /** |
|
727 | + * Check if this is a case of a install being resumed and figure |
|
728 | + * out where to continue from. Returns the best guess on the step. |
|
729 | + * |
|
730 | + * @param string $step Installation step to resume from |
|
731 | + * |
|
732 | + * @return string |
|
733 | + */ |
|
734 | + protected function resumeInstall($step) { |
|
735 | + // only do a resume from the first step |
|
736 | + if ($step !== 'welcome') { |
|
737 | + return; |
|
738 | + } |
|
739 | + |
|
740 | + if ($this->has_completed['database'] == false) { |
|
741 | + return; |
|
742 | + } |
|
743 | + |
|
744 | + if ($this->has_completed['settings'] == false) { |
|
745 | + forward("install.php?step=settings"); |
|
746 | + } |
|
747 | + |
|
748 | + if ($this->has_completed['admin'] == false) { |
|
749 | + forward("install.php?step=admin"); |
|
750 | + } |
|
751 | + |
|
752 | + // everything appears to be set up |
|
753 | + forward("install.php?step=complete"); |
|
754 | + } |
|
755 | + |
|
756 | + /** |
|
757 | + * Bootstrapping |
|
758 | + */ |
|
759 | + |
|
760 | + /** |
|
761 | + * Load remaining engine libraries and complete bootstrapping |
|
762 | + * |
|
763 | + * @param string $step Which step to boot strap for. Required because |
|
764 | + * boot strapping is different until the DB is populated. |
|
765 | + * |
|
766 | + * @return void |
|
767 | + * @throws InstallationException |
|
768 | + */ |
|
769 | + protected function finishBootstrapping($step) { |
|
770 | + |
|
771 | + $index_db = array_search('database', $this->getSteps()); |
|
772 | + $index_settings = array_search('settings', $this->getSteps()); |
|
773 | + $index_admin = array_search('admin', $this->getSteps()); |
|
774 | + $index_complete = array_search('complete', $this->getSteps()); |
|
775 | + $index_step = array_search($step, $this->getSteps()); |
|
776 | + |
|
777 | + // To log in the user, we need to use the Elgg core session handling. |
|
778 | + // Otherwise, use default php session handling |
|
779 | + $use_elgg_session = ($index_step == $index_admin && $this->is_action) || ($index_step == $index_complete); |
|
780 | + if (!$use_elgg_session) { |
|
781 | + $session = ElggSession::fromFiles($this->config); |
|
782 | + $session->setName('Elgg_install'); |
|
783 | + $this->services->setValue('session', $session); |
|
784 | + } |
|
785 | + |
|
786 | + if ($index_step > $index_db) { |
|
787 | + // once the database has been created, load rest of engine |
|
788 | + |
|
789 | + // dummy site needed to boot |
|
790 | + $this->config->site = new ElggSite(); |
|
791 | + |
|
792 | + $this->app->bootCore(); |
|
793 | + } |
|
794 | + } |
|
795 | + |
|
796 | + /** |
|
797 | + * Load settings |
|
798 | + * |
|
799 | + * @return void |
|
800 | + * @throws InstallationException |
|
801 | + */ |
|
802 | + protected function loadSettingsFile() { |
|
803 | + try { |
|
804 | + $config = Config::fromFile(Paths::settingsFile()); |
|
805 | + $this->config->mergeValues($config->getValues()); |
|
806 | + |
|
807 | + // in case the DB instance is already captured in services, we re-inject its settings. |
|
808 | + $this->services->db->resetConnections(DbConfig::fromElggConfig($this->config)); |
|
809 | + } catch (\Exception $e) { |
|
810 | + $msg = elgg_echo('InstallationException:CannotLoadSettings'); |
|
811 | + throw new InstallationException($msg, 0, $e); |
|
812 | + } |
|
813 | + } |
|
814 | + |
|
815 | + /** |
|
816 | + * Action handling methods |
|
817 | + */ |
|
818 | + |
|
819 | + /** |
|
820 | + * If form is reshown, remember previously submitted variables |
|
821 | + * |
|
822 | + * @param array $formVars Vars int he form |
|
823 | + * @param array $submissionVars Submitted vars |
|
824 | + * |
|
825 | + * @return array |
|
826 | + */ |
|
827 | + protected function makeFormSticky($formVars, $submissionVars) { |
|
828 | + foreach ($submissionVars as $field => $value) { |
|
829 | + $formVars[$field]['value'] = $value; |
|
830 | + } |
|
831 | + return $formVars; |
|
832 | + } |
|
833 | + |
|
834 | + /* Requirement checks support methods */ |
|
835 | + |
|
836 | + /** |
|
837 | + * Indicates whether the webserver can add settings.php on its own or not. |
|
838 | + * |
|
839 | + * @param array $report The requirements report object |
|
840 | + * |
|
841 | + * @return bool |
|
842 | + */ |
|
843 | + protected function isInstallDirWritable(&$report) { |
|
844 | + if (!is_writable(Paths::projectConfig())) { |
|
845 | + $msg = elgg_echo('install:check:installdir', [Paths::PATH_TO_CONFIG]); |
|
846 | + $report['settings'] = [ |
|
847 | + [ |
|
848 | + 'severity' => 'failure', |
|
849 | + 'message' => $msg, |
|
850 | + ] |
|
851 | + ]; |
|
852 | + return false; |
|
853 | + } |
|
854 | + |
|
855 | + return true; |
|
856 | + } |
|
857 | + |
|
858 | + /** |
|
859 | + * Check that the settings file exists |
|
860 | + * |
|
861 | + * @param array $report The requirements report array |
|
862 | + * |
|
863 | + * @return bool |
|
864 | + */ |
|
865 | + protected function checkSettingsFile(&$report = []) { |
|
866 | + if (!is_file(Paths::settingsFile())) { |
|
867 | + return false; |
|
868 | + } |
|
869 | + |
|
870 | + if (!is_readable(Paths::settingsFile())) { |
|
871 | + $report['settings'] = [ |
|
872 | + [ |
|
873 | + 'severity' => 'failure', |
|
874 | + 'message' => elgg_echo('install:check:readsettings'), |
|
875 | + ] |
|
876 | + ]; |
|
877 | + } |
|
878 | 878 | |
879 | - return true; |
|
880 | - } |
|
879 | + return true; |
|
880 | + } |
|
881 | 881 | |
882 | - /** |
|
883 | - * Check version of PHP, extensions, and variables |
|
884 | - * |
|
885 | - * @param array $report The requirements report array |
|
886 | - * |
|
887 | - * @return void |
|
888 | - */ |
|
889 | - protected function checkPHP(&$report) { |
|
890 | - $phpReport = []; |
|
891 | - |
|
892 | - $min_php_version = '5.6.0'; |
|
893 | - if (version_compare(PHP_VERSION, $min_php_version, '<')) { |
|
894 | - $phpReport[] = [ |
|
895 | - 'severity' => 'failure', |
|
896 | - 'message' => elgg_echo('install:check:php:version', [$min_php_version, PHP_VERSION]) |
|
897 | - ]; |
|
898 | - } |
|
899 | - |
|
900 | - $this->checkPhpExtensions($phpReport); |
|
901 | - |
|
902 | - $this->checkPhpDirectives($phpReport); |
|
903 | - |
|
904 | - if (count($phpReport) == 0) { |
|
905 | - $phpReport[] = [ |
|
906 | - 'severity' => 'pass', |
|
907 | - 'message' => elgg_echo('install:check:php:success') |
|
908 | - ]; |
|
909 | - } |
|
910 | - |
|
911 | - $report['php'] = $phpReport; |
|
912 | - } |
|
913 | - |
|
914 | - /** |
|
915 | - * Check the server's PHP extensions |
|
916 | - * |
|
917 | - * @param array $phpReport The PHP requirements report array |
|
918 | - * |
|
919 | - * @return void |
|
920 | - */ |
|
921 | - protected function checkPhpExtensions(&$phpReport) { |
|
922 | - $extensions = get_loaded_extensions(); |
|
923 | - $requiredExtensions = [ |
|
924 | - 'pdo_mysql', |
|
925 | - 'json', |
|
926 | - 'xml', |
|
927 | - 'gd', |
|
928 | - ]; |
|
929 | - foreach ($requiredExtensions as $extension) { |
|
930 | - if (!in_array($extension, $extensions)) { |
|
931 | - $phpReport[] = [ |
|
932 | - 'severity' => 'failure', |
|
933 | - 'message' => elgg_echo('install:check:php:extension', [$extension]) |
|
934 | - ]; |
|
935 | - } |
|
936 | - } |
|
937 | - |
|
938 | - $recommendedExtensions = [ |
|
939 | - 'mbstring', |
|
940 | - ]; |
|
941 | - foreach ($recommendedExtensions as $extension) { |
|
942 | - if (!in_array($extension, $extensions)) { |
|
943 | - $phpReport[] = [ |
|
944 | - 'severity' => 'warning', |
|
945 | - 'message' => elgg_echo('install:check:php:extension:recommend', [$extension]) |
|
946 | - ]; |
|
947 | - } |
|
948 | - } |
|
949 | - } |
|
950 | - |
|
951 | - /** |
|
952 | - * Check PHP parameters |
|
953 | - * |
|
954 | - * @param array $phpReport The PHP requirements report array |
|
955 | - * |
|
956 | - * @return void |
|
957 | - */ |
|
958 | - protected function checkPhpDirectives(&$phpReport) { |
|
959 | - if (ini_get('open_basedir')) { |
|
960 | - $phpReport[] = [ |
|
961 | - 'severity' => 'warning', |
|
962 | - 'message' => elgg_echo("install:check:php:open_basedir") |
|
963 | - ]; |
|
964 | - } |
|
965 | - |
|
966 | - if (ini_get('safe_mode')) { |
|
967 | - $phpReport[] = [ |
|
968 | - 'severity' => 'warning', |
|
969 | - 'message' => elgg_echo("install:check:php:safe_mode") |
|
970 | - ]; |
|
971 | - } |
|
972 | - |
|
973 | - if (ini_get('arg_separator.output') !== '&') { |
|
974 | - $separator = htmlspecialchars(ini_get('arg_separator.output')); |
|
975 | - $msg = elgg_echo("install:check:php:arg_separator", [$separator]); |
|
976 | - $phpReport[] = [ |
|
977 | - 'severity' => 'failure', |
|
978 | - 'message' => $msg, |
|
979 | - ]; |
|
980 | - } |
|
981 | - |
|
982 | - if (ini_get('register_globals')) { |
|
983 | - $phpReport[] = [ |
|
984 | - 'severity' => 'failure', |
|
985 | - 'message' => elgg_echo("install:check:php:register_globals") |
|
986 | - ]; |
|
987 | - } |
|
988 | - |
|
989 | - if (ini_get('session.auto_start')) { |
|
990 | - $phpReport[] = [ |
|
991 | - 'severity' => 'failure', |
|
992 | - 'message' => elgg_echo("install:check:php:session.auto_start") |
|
993 | - ]; |
|
994 | - } |
|
995 | - } |
|
996 | - |
|
997 | - /** |
|
998 | - * Confirm that the rewrite rules are firing |
|
999 | - * |
|
1000 | - * @param array $report The requirements report array |
|
1001 | - * |
|
1002 | - * @return void |
|
1003 | - */ |
|
1004 | - protected function checkRewriteRules(&$report) { |
|
1005 | - $tester = new ElggRewriteTester(); |
|
1006 | - $url = $this->config->wwwroot; |
|
1007 | - $url .= Request::REWRITE_TEST_TOKEN . '?' . http_build_query([ |
|
1008 | - Request::REWRITE_TEST_TOKEN => '1', |
|
1009 | - ]); |
|
1010 | - $report['rewrite'] = [$tester->run($url, Paths::project())]; |
|
1011 | - } |
|
1012 | - |
|
1013 | - /** |
|
1014 | - * Count the number of failures in the requirements report |
|
1015 | - * |
|
1016 | - * @param array $report The requirements report array |
|
1017 | - * @param string $condition 'failure' or 'warning' |
|
1018 | - * |
|
1019 | - * @return int |
|
1020 | - */ |
|
1021 | - protected function countNumConditions($report, $condition) { |
|
1022 | - $count = 0; |
|
1023 | - foreach ($report as $category => $checks) { |
|
1024 | - foreach ($checks as $check) { |
|
1025 | - if ($check['severity'] === $condition) { |
|
1026 | - $count++; |
|
1027 | - } |
|
1028 | - } |
|
1029 | - } |
|
1030 | - |
|
1031 | - return $count; |
|
1032 | - } |
|
1033 | - |
|
1034 | - |
|
1035 | - /** |
|
1036 | - * Database support methods |
|
1037 | - */ |
|
1038 | - |
|
1039 | - /** |
|
1040 | - * Validate the variables for the database step |
|
1041 | - * |
|
1042 | - * @param array $submissionVars Submitted vars |
|
1043 | - * @param array $formVars Vars in the form |
|
1044 | - * |
|
1045 | - * @return bool |
|
1046 | - */ |
|
1047 | - protected function validateDatabaseVars($submissionVars, $formVars) { |
|
1048 | - |
|
1049 | - foreach ($formVars as $field => $info) { |
|
1050 | - if ($info['required'] == true && !$submissionVars[$field]) { |
|
1051 | - $name = elgg_echo("install:database:label:$field"); |
|
1052 | - register_error(elgg_echo('install:error:requiredfield', [$name])); |
|
1053 | - return false; |
|
1054 | - } |
|
1055 | - } |
|
1056 | - |
|
1057 | - // check that data root is absolute path |
|
1058 | - if (stripos(PHP_OS, 'win') === 0) { |
|
1059 | - if (strpos($submissionVars['dataroot'], ':') !== 1) { |
|
1060 | - $msg = elgg_echo('install:error:relative_path', [$submissionVars['dataroot']]); |
|
1061 | - register_error($msg); |
|
1062 | - return false; |
|
1063 | - } |
|
1064 | - } else { |
|
1065 | - if (strpos($submissionVars['dataroot'], '/') !== 0) { |
|
1066 | - $msg = elgg_echo('install:error:relative_path', [$submissionVars['dataroot']]); |
|
1067 | - register_error($msg); |
|
1068 | - return false; |
|
1069 | - } |
|
1070 | - } |
|
1071 | - |
|
1072 | - // check that data root exists |
|
1073 | - if (!is_dir($submissionVars['dataroot'])) { |
|
1074 | - $msg = elgg_echo('install:error:datadirectoryexists', [$submissionVars['dataroot']]); |
|
1075 | - register_error($msg); |
|
1076 | - return false; |
|
1077 | - } |
|
1078 | - |
|
1079 | - // check that data root is writable |
|
1080 | - if (!is_writable($submissionVars['dataroot'])) { |
|
1081 | - $msg = elgg_echo('install:error:writedatadirectory', [$submissionVars['dataroot']]); |
|
1082 | - register_error($msg); |
|
1083 | - return false; |
|
1084 | - } |
|
1085 | - |
|
1086 | - if (!$this->config->data_dir_override) { |
|
1087 | - // check that data root is not subdirectory of Elgg root |
|
1088 | - if (stripos($submissionVars['dataroot'], $this->config->path) === 0) { |
|
1089 | - $msg = elgg_echo('install:error:locationdatadirectory', [$submissionVars['dataroot']]); |
|
1090 | - register_error($msg); |
|
1091 | - return false; |
|
1092 | - } |
|
1093 | - } |
|
1094 | - |
|
1095 | - // according to postgres documentation: SQL identifiers and key words must |
|
1096 | - // begin with a letter (a-z, but also letters with diacritical marks and |
|
1097 | - // non-Latin letters) or an underscore (_). Subsequent characters in an |
|
1098 | - // identifier or key word can be letters, underscores, digits (0-9), or dollar signs ($). |
|
1099 | - // Refs #4994 |
|
1100 | - if (!preg_match("/^[a-zA-Z_][\w]*$/", $submissionVars['dbprefix'])) { |
|
1101 | - register_error(elgg_echo('install:error:database_prefix')); |
|
1102 | - return false; |
|
1103 | - } |
|
1104 | - |
|
1105 | - return $this->checkDatabaseSettings( |
|
1106 | - $submissionVars['dbuser'], |
|
1107 | - $submissionVars['dbpassword'], |
|
1108 | - $submissionVars['dbname'], |
|
1109 | - $submissionVars['dbhost'] |
|
1110 | - ); |
|
1111 | - } |
|
1112 | - |
|
1113 | - /** |
|
1114 | - * Confirm the settings for the database |
|
1115 | - * |
|
1116 | - * @param string $user Username |
|
1117 | - * @param string $password Password |
|
1118 | - * @param string $dbname Database name |
|
1119 | - * @param string $host Host |
|
1120 | - * |
|
1121 | - * @return bool |
|
1122 | - */ |
|
1123 | - protected function checkDatabaseSettings($user, $password, $dbname, $host) { |
|
1124 | - $config = new DbConfig((object) [ |
|
1125 | - 'dbhost' => $host, |
|
1126 | - 'dbuser' => $user, |
|
1127 | - 'dbpass' => $password, |
|
1128 | - 'dbname' => $dbname, |
|
1129 | - 'dbencoding' => 'utf8mb4', |
|
1130 | - ]); |
|
1131 | - $db = new \Elgg\Database($config); |
|
1132 | - |
|
1133 | - try { |
|
1134 | - $db->getDataRow("SELECT 1"); |
|
1135 | - } catch (DatabaseException $e) { |
|
1136 | - if (0 === strpos($e->getMessage(), "Elgg couldn't connect")) { |
|
1137 | - register_error(elgg_echo('install:error:databasesettings')); |
|
1138 | - } else { |
|
1139 | - register_error(elgg_echo('install:error:nodatabase', [$dbname])); |
|
1140 | - } |
|
1141 | - return false; |
|
1142 | - } |
|
1143 | - |
|
1144 | - // check MySQL version |
|
1145 | - $version = $db->getServerVersion(DbConfig::READ_WRITE); |
|
1146 | - if (version_compare($version, '5.5.3', '<')) { |
|
1147 | - register_error(elgg_echo('install:error:oldmysql2', [$version])); |
|
1148 | - return false; |
|
1149 | - } |
|
1150 | - |
|
1151 | - return true; |
|
1152 | - } |
|
1153 | - |
|
1154 | - /** |
|
1155 | - * Writes the settings file to the engine directory |
|
1156 | - * |
|
1157 | - * @param array $params Array of inputted params from the user |
|
1158 | - * |
|
1159 | - * @return bool |
|
1160 | - */ |
|
1161 | - protected function createSettingsFile($params) { |
|
1162 | - $template = Application::elggDir()->getContents("elgg-config/settings.example.php"); |
|
1163 | - if (!$template) { |
|
1164 | - register_error(elgg_echo('install:error:readsettingsphp')); |
|
1165 | - return false; |
|
1166 | - } |
|
1167 | - |
|
1168 | - foreach ($params as $k => $v) { |
|
1169 | - $template = str_replace("{{" . $k . "}}", $v, $template); |
|
1170 | - } |
|
1171 | - |
|
1172 | - $result = file_put_contents(Paths::settingsFile(), $template); |
|
1173 | - if (!$result) { |
|
1174 | - register_error(elgg_echo('install:error:writesettingphp')); |
|
1175 | - return false; |
|
1176 | - } |
|
1177 | - |
|
1178 | - return true; |
|
1179 | - } |
|
1180 | - |
|
1181 | - /** |
|
1182 | - * Bootstrap database connection before entire engine is available |
|
1183 | - * |
|
1184 | - * @return bool |
|
1185 | - */ |
|
1186 | - protected function connectToDatabase() { |
|
1187 | - try { |
|
1188 | - $this->services->db->setupConnections(); |
|
1189 | - } catch (DatabaseException $e) { |
|
1190 | - register_error($e->getMessage()); |
|
1191 | - return false; |
|
1192 | - } |
|
1193 | - |
|
1194 | - return true; |
|
1195 | - } |
|
1196 | - |
|
1197 | - /** |
|
1198 | - * Create the database tables |
|
1199 | - * |
|
1200 | - * @return bool |
|
1201 | - */ |
|
1202 | - protected function installDatabase() { |
|
1203 | - $ret = \Elgg\Application::migrate(); |
|
1204 | - if ($ret) { |
|
1205 | - init_site_secret(); |
|
1206 | - } |
|
1207 | - return $ret; |
|
1208 | - } |
|
1209 | - |
|
1210 | - /** |
|
1211 | - * Site settings support methods |
|
1212 | - */ |
|
1213 | - |
|
1214 | - /** |
|
1215 | - * Create the data directory if requested |
|
1216 | - * |
|
1217 | - * @param array $submissionVars Submitted vars |
|
1218 | - * @param array $formVars Variables in the form |
|
1219 | - * |
|
1220 | - * @return bool |
|
1221 | - */ |
|
1222 | - protected function createDataDirectory(&$submissionVars, $formVars) { |
|
1223 | - // did the user have option of Elgg creating the data directory |
|
1224 | - if ($formVars['dataroot']['type'] != 'combo') { |
|
1225 | - return true; |
|
1226 | - } |
|
1227 | - |
|
1228 | - // did the user select the option |
|
1229 | - if ($submissionVars['dataroot'] != 'dataroot-checkbox') { |
|
1230 | - return true; |
|
1231 | - } |
|
1232 | - |
|
1233 | - $dir = sanitise_filepath($submissionVars['path']) . 'data'; |
|
1234 | - if (file_exists($dir) || mkdir($dir, 0700)) { |
|
1235 | - $submissionVars['dataroot'] = $dir; |
|
1236 | - if (!file_exists("$dir/.htaccess")) { |
|
1237 | - $htaccess = "Order Deny,Allow\nDeny from All\n"; |
|
1238 | - if (!file_put_contents("$dir/.htaccess", $htaccess)) { |
|
1239 | - return false; |
|
1240 | - } |
|
1241 | - } |
|
1242 | - return true; |
|
1243 | - } |
|
1244 | - |
|
1245 | - return false; |
|
1246 | - } |
|
1247 | - |
|
1248 | - /** |
|
1249 | - * Validate the site settings form variables |
|
1250 | - * |
|
1251 | - * @param array $submissionVars Submitted vars |
|
1252 | - * @param array $formVars Vars in the form |
|
1253 | - * |
|
1254 | - * @return bool |
|
1255 | - */ |
|
1256 | - protected function validateSettingsVars($submissionVars, $formVars) { |
|
1257 | - foreach ($formVars as $field => $info) { |
|
1258 | - $submissionVars[$field] = trim($submissionVars[$field]); |
|
1259 | - if ($info['required'] == true && $submissionVars[$field] === '') { |
|
1260 | - $name = elgg_echo("install:settings:label:$field"); |
|
1261 | - register_error(elgg_echo('install:error:requiredfield', [$name])); |
|
1262 | - return false; |
|
1263 | - } |
|
1264 | - } |
|
1265 | - |
|
1266 | - // check that email address is email address |
|
1267 | - if ($submissionVars['siteemail'] && !is_email_address($submissionVars['siteemail'])) { |
|
1268 | - $msg = elgg_echo('install:error:emailaddress', [$submissionVars['siteemail']]); |
|
1269 | - register_error($msg); |
|
1270 | - return false; |
|
1271 | - } |
|
1272 | - |
|
1273 | - // @todo check that url is a url |
|
1274 | - // @note filter_var cannot be used because it doesn't work on international urls |
|
1275 | - |
|
1276 | - return true; |
|
1277 | - } |
|
1278 | - |
|
1279 | - /** |
|
1280 | - * Initialize the site including site entity, plugins, and configuration |
|
1281 | - * |
|
1282 | - * @param array $submissionVars Submitted vars |
|
1283 | - * |
|
1284 | - * @return bool |
|
1285 | - */ |
|
1286 | - protected function saveSiteSettings($submissionVars) { |
|
1287 | - $site = new ElggSite(); |
|
1288 | - $site->name = strip_tags($submissionVars['sitename']); |
|
1289 | - $site->access_id = ACCESS_PUBLIC; |
|
1290 | - $site->email = $submissionVars['siteemail']; |
|
1291 | - |
|
1292 | - $guid = $site->save(); |
|
1293 | - if ($guid !== 1) { |
|
1294 | - register_error(elgg_echo('install:error:createsite')); |
|
1295 | - return false; |
|
1296 | - } |
|
1297 | - |
|
1298 | - $this->config->site = $site; |
|
1299 | - |
|
1300 | - // new installations have run all the upgrades |
|
1301 | - $upgrades = elgg_get_upgrade_files(Paths::elgg() . "engine/lib/upgrades/"); |
|
1302 | - |
|
1303 | - $sets = [ |
|
1304 | - 'installed' => time(), |
|
1305 | - 'version' => elgg_get_version(), |
|
1306 | - 'simplecache_enabled' => 1, |
|
1307 | - 'system_cache_enabled' => 1, |
|
1308 | - 'simplecache_lastupdate' => time(), |
|
1309 | - 'processed_upgrades' => $upgrades, |
|
1310 | - 'language' => 'en', |
|
1311 | - 'default_access' => $submissionVars['siteaccess'], |
|
1312 | - 'allow_registration' => false, |
|
1313 | - 'walled_garden' => false, |
|
1314 | - 'allow_user_default_access' => '', |
|
1315 | - 'default_limit' => 10, |
|
1316 | - 'security_protect_upgrade' => true, |
|
1317 | - 'security_notify_admins' => true, |
|
1318 | - 'security_notify_user_password' => true, |
|
1319 | - 'security_email_require_password' => true, |
|
1320 | - ]; |
|
1321 | - foreach ($sets as $key => $value) { |
|
1322 | - elgg_save_config($key, $value); |
|
1323 | - } |
|
1324 | - |
|
1325 | - // Enable a set of default plugins |
|
1326 | - _elgg_generate_plugin_entities(); |
|
1327 | - |
|
1328 | - foreach (elgg_get_plugins('any') as $plugin) { |
|
1329 | - if ($plugin->getManifest()) { |
|
1330 | - if ($plugin->getManifest()->getActivateOnInstall()) { |
|
1331 | - $plugin->activate(); |
|
1332 | - } |
|
1333 | - if (in_array('theme', $plugin->getManifest()->getCategories())) { |
|
1334 | - $plugin->setPriority('last'); |
|
1335 | - } |
|
1336 | - } |
|
1337 | - } |
|
1338 | - |
|
1339 | - return true; |
|
1340 | - } |
|
1341 | - |
|
1342 | - /** |
|
1343 | - * Admin account support methods |
|
1344 | - */ |
|
1345 | - |
|
1346 | - /** |
|
1347 | - * Validate account form variables |
|
1348 | - * |
|
1349 | - * @param array $submissionVars Submitted vars |
|
1350 | - * @param array $formVars Form vars |
|
1351 | - * |
|
1352 | - * @return bool |
|
1353 | - */ |
|
1354 | - protected function validateAdminVars($submissionVars, $formVars) { |
|
1355 | - |
|
1356 | - foreach ($formVars as $field => $info) { |
|
1357 | - if ($info['required'] == true && !$submissionVars[$field]) { |
|
1358 | - $name = elgg_echo("install:admin:label:$field"); |
|
1359 | - register_error(elgg_echo('install:error:requiredfield', [$name])); |
|
1360 | - return false; |
|
1361 | - } |
|
1362 | - } |
|
1363 | - |
|
1364 | - if ($submissionVars['password1'] !== $submissionVars['password2']) { |
|
1365 | - register_error(elgg_echo('install:admin:password:mismatch')); |
|
1366 | - return false; |
|
1367 | - } |
|
1368 | - |
|
1369 | - if (trim($submissionVars['password1']) == "") { |
|
1370 | - register_error(elgg_echo('install:admin:password:empty')); |
|
1371 | - return false; |
|
1372 | - } |
|
1373 | - |
|
1374 | - $minLength = $this->services->configTable->get('min_password_length'); |
|
1375 | - if (strlen($submissionVars['password1']) < $minLength) { |
|
1376 | - register_error(elgg_echo('install:admin:password:tooshort')); |
|
1377 | - return false; |
|
1378 | - } |
|
1379 | - |
|
1380 | - // check that email address is email address |
|
1381 | - if ($submissionVars['email'] && !is_email_address($submissionVars['email'])) { |
|
1382 | - $msg = elgg_echo('install:error:emailaddress', [$submissionVars['email']]); |
|
1383 | - register_error($msg); |
|
1384 | - return false; |
|
1385 | - } |
|
1386 | - |
|
1387 | - return true; |
|
1388 | - } |
|
1389 | - |
|
1390 | - /** |
|
1391 | - * Create a user account for the admin |
|
1392 | - * |
|
1393 | - * @param array $submissionVars Submitted vars |
|
1394 | - * @param bool $login Login in the admin user? |
|
1395 | - * |
|
1396 | - * @return bool |
|
1397 | - */ |
|
1398 | - protected function createAdminAccount($submissionVars, $login = false) { |
|
1399 | - try { |
|
1400 | - $guid = register_user( |
|
1401 | - $submissionVars['username'], |
|
1402 | - $submissionVars['password1'], |
|
1403 | - $submissionVars['displayname'], |
|
1404 | - $submissionVars['email'] |
|
1405 | - ); |
|
1406 | - } catch (Exception $e) { |
|
1407 | - register_error($e->getMessage()); |
|
1408 | - return false; |
|
1409 | - } |
|
1410 | - |
|
1411 | - if (!$guid) { |
|
1412 | - register_error(elgg_echo('install:admin:cannot_create')); |
|
1413 | - return false; |
|
1414 | - } |
|
1415 | - |
|
1416 | - $user = get_entity($guid); |
|
1417 | - if (!$user instanceof ElggUser) { |
|
1418 | - register_error(elgg_echo('install:error:loadadmin')); |
|
1419 | - return false; |
|
1420 | - } |
|
1421 | - |
|
1422 | - $ia = elgg_set_ignore_access(true); |
|
1423 | - if ($user->makeAdmin() == false) { |
|
1424 | - register_error(elgg_echo('install:error:adminaccess')); |
|
1425 | - } else { |
|
1426 | - $this->services->configTable->set('admin_registered', 1); |
|
1427 | - } |
|
1428 | - elgg_set_ignore_access($ia); |
|
1429 | - |
|
1430 | - // add validation data to satisfy user validation plugins |
|
1431 | - $user->validated = 1; |
|
1432 | - $user->validated_method = 'admin_user'; |
|
1433 | - |
|
1434 | - if (!$login) { |
|
1435 | - return true; |
|
1436 | - } |
|
1437 | - |
|
1438 | - $session = ElggSession::fromDatabase($this->config, $this->services->db); |
|
1439 | - $session->start(); |
|
1440 | - $this->services->setValue('session', $session); |
|
1441 | - if (login($user) == false) { |
|
1442 | - register_error(elgg_echo('install:error:adminlogin')); |
|
1443 | - } |
|
1444 | - |
|
1445 | - return true; |
|
1446 | - } |
|
882 | + /** |
|
883 | + * Check version of PHP, extensions, and variables |
|
884 | + * |
|
885 | + * @param array $report The requirements report array |
|
886 | + * |
|
887 | + * @return void |
|
888 | + */ |
|
889 | + protected function checkPHP(&$report) { |
|
890 | + $phpReport = []; |
|
891 | + |
|
892 | + $min_php_version = '5.6.0'; |
|
893 | + if (version_compare(PHP_VERSION, $min_php_version, '<')) { |
|
894 | + $phpReport[] = [ |
|
895 | + 'severity' => 'failure', |
|
896 | + 'message' => elgg_echo('install:check:php:version', [$min_php_version, PHP_VERSION]) |
|
897 | + ]; |
|
898 | + } |
|
899 | + |
|
900 | + $this->checkPhpExtensions($phpReport); |
|
901 | + |
|
902 | + $this->checkPhpDirectives($phpReport); |
|
903 | + |
|
904 | + if (count($phpReport) == 0) { |
|
905 | + $phpReport[] = [ |
|
906 | + 'severity' => 'pass', |
|
907 | + 'message' => elgg_echo('install:check:php:success') |
|
908 | + ]; |
|
909 | + } |
|
910 | + |
|
911 | + $report['php'] = $phpReport; |
|
912 | + } |
|
913 | + |
|
914 | + /** |
|
915 | + * Check the server's PHP extensions |
|
916 | + * |
|
917 | + * @param array $phpReport The PHP requirements report array |
|
918 | + * |
|
919 | + * @return void |
|
920 | + */ |
|
921 | + protected function checkPhpExtensions(&$phpReport) { |
|
922 | + $extensions = get_loaded_extensions(); |
|
923 | + $requiredExtensions = [ |
|
924 | + 'pdo_mysql', |
|
925 | + 'json', |
|
926 | + 'xml', |
|
927 | + 'gd', |
|
928 | + ]; |
|
929 | + foreach ($requiredExtensions as $extension) { |
|
930 | + if (!in_array($extension, $extensions)) { |
|
931 | + $phpReport[] = [ |
|
932 | + 'severity' => 'failure', |
|
933 | + 'message' => elgg_echo('install:check:php:extension', [$extension]) |
|
934 | + ]; |
|
935 | + } |
|
936 | + } |
|
937 | + |
|
938 | + $recommendedExtensions = [ |
|
939 | + 'mbstring', |
|
940 | + ]; |
|
941 | + foreach ($recommendedExtensions as $extension) { |
|
942 | + if (!in_array($extension, $extensions)) { |
|
943 | + $phpReport[] = [ |
|
944 | + 'severity' => 'warning', |
|
945 | + 'message' => elgg_echo('install:check:php:extension:recommend', [$extension]) |
|
946 | + ]; |
|
947 | + } |
|
948 | + } |
|
949 | + } |
|
950 | + |
|
951 | + /** |
|
952 | + * Check PHP parameters |
|
953 | + * |
|
954 | + * @param array $phpReport The PHP requirements report array |
|
955 | + * |
|
956 | + * @return void |
|
957 | + */ |
|
958 | + protected function checkPhpDirectives(&$phpReport) { |
|
959 | + if (ini_get('open_basedir')) { |
|
960 | + $phpReport[] = [ |
|
961 | + 'severity' => 'warning', |
|
962 | + 'message' => elgg_echo("install:check:php:open_basedir") |
|
963 | + ]; |
|
964 | + } |
|
965 | + |
|
966 | + if (ini_get('safe_mode')) { |
|
967 | + $phpReport[] = [ |
|
968 | + 'severity' => 'warning', |
|
969 | + 'message' => elgg_echo("install:check:php:safe_mode") |
|
970 | + ]; |
|
971 | + } |
|
972 | + |
|
973 | + if (ini_get('arg_separator.output') !== '&') { |
|
974 | + $separator = htmlspecialchars(ini_get('arg_separator.output')); |
|
975 | + $msg = elgg_echo("install:check:php:arg_separator", [$separator]); |
|
976 | + $phpReport[] = [ |
|
977 | + 'severity' => 'failure', |
|
978 | + 'message' => $msg, |
|
979 | + ]; |
|
980 | + } |
|
981 | + |
|
982 | + if (ini_get('register_globals')) { |
|
983 | + $phpReport[] = [ |
|
984 | + 'severity' => 'failure', |
|
985 | + 'message' => elgg_echo("install:check:php:register_globals") |
|
986 | + ]; |
|
987 | + } |
|
988 | + |
|
989 | + if (ini_get('session.auto_start')) { |
|
990 | + $phpReport[] = [ |
|
991 | + 'severity' => 'failure', |
|
992 | + 'message' => elgg_echo("install:check:php:session.auto_start") |
|
993 | + ]; |
|
994 | + } |
|
995 | + } |
|
996 | + |
|
997 | + /** |
|
998 | + * Confirm that the rewrite rules are firing |
|
999 | + * |
|
1000 | + * @param array $report The requirements report array |
|
1001 | + * |
|
1002 | + * @return void |
|
1003 | + */ |
|
1004 | + protected function checkRewriteRules(&$report) { |
|
1005 | + $tester = new ElggRewriteTester(); |
|
1006 | + $url = $this->config->wwwroot; |
|
1007 | + $url .= Request::REWRITE_TEST_TOKEN . '?' . http_build_query([ |
|
1008 | + Request::REWRITE_TEST_TOKEN => '1', |
|
1009 | + ]); |
|
1010 | + $report['rewrite'] = [$tester->run($url, Paths::project())]; |
|
1011 | + } |
|
1012 | + |
|
1013 | + /** |
|
1014 | + * Count the number of failures in the requirements report |
|
1015 | + * |
|
1016 | + * @param array $report The requirements report array |
|
1017 | + * @param string $condition 'failure' or 'warning' |
|
1018 | + * |
|
1019 | + * @return int |
|
1020 | + */ |
|
1021 | + protected function countNumConditions($report, $condition) { |
|
1022 | + $count = 0; |
|
1023 | + foreach ($report as $category => $checks) { |
|
1024 | + foreach ($checks as $check) { |
|
1025 | + if ($check['severity'] === $condition) { |
|
1026 | + $count++; |
|
1027 | + } |
|
1028 | + } |
|
1029 | + } |
|
1030 | + |
|
1031 | + return $count; |
|
1032 | + } |
|
1033 | + |
|
1034 | + |
|
1035 | + /** |
|
1036 | + * Database support methods |
|
1037 | + */ |
|
1038 | + |
|
1039 | + /** |
|
1040 | + * Validate the variables for the database step |
|
1041 | + * |
|
1042 | + * @param array $submissionVars Submitted vars |
|
1043 | + * @param array $formVars Vars in the form |
|
1044 | + * |
|
1045 | + * @return bool |
|
1046 | + */ |
|
1047 | + protected function validateDatabaseVars($submissionVars, $formVars) { |
|
1048 | + |
|
1049 | + foreach ($formVars as $field => $info) { |
|
1050 | + if ($info['required'] == true && !$submissionVars[$field]) { |
|
1051 | + $name = elgg_echo("install:database:label:$field"); |
|
1052 | + register_error(elgg_echo('install:error:requiredfield', [$name])); |
|
1053 | + return false; |
|
1054 | + } |
|
1055 | + } |
|
1056 | + |
|
1057 | + // check that data root is absolute path |
|
1058 | + if (stripos(PHP_OS, 'win') === 0) { |
|
1059 | + if (strpos($submissionVars['dataroot'], ':') !== 1) { |
|
1060 | + $msg = elgg_echo('install:error:relative_path', [$submissionVars['dataroot']]); |
|
1061 | + register_error($msg); |
|
1062 | + return false; |
|
1063 | + } |
|
1064 | + } else { |
|
1065 | + if (strpos($submissionVars['dataroot'], '/') !== 0) { |
|
1066 | + $msg = elgg_echo('install:error:relative_path', [$submissionVars['dataroot']]); |
|
1067 | + register_error($msg); |
|
1068 | + return false; |
|
1069 | + } |
|
1070 | + } |
|
1071 | + |
|
1072 | + // check that data root exists |
|
1073 | + if (!is_dir($submissionVars['dataroot'])) { |
|
1074 | + $msg = elgg_echo('install:error:datadirectoryexists', [$submissionVars['dataroot']]); |
|
1075 | + register_error($msg); |
|
1076 | + return false; |
|
1077 | + } |
|
1078 | + |
|
1079 | + // check that data root is writable |
|
1080 | + if (!is_writable($submissionVars['dataroot'])) { |
|
1081 | + $msg = elgg_echo('install:error:writedatadirectory', [$submissionVars['dataroot']]); |
|
1082 | + register_error($msg); |
|
1083 | + return false; |
|
1084 | + } |
|
1085 | + |
|
1086 | + if (!$this->config->data_dir_override) { |
|
1087 | + // check that data root is not subdirectory of Elgg root |
|
1088 | + if (stripos($submissionVars['dataroot'], $this->config->path) === 0) { |
|
1089 | + $msg = elgg_echo('install:error:locationdatadirectory', [$submissionVars['dataroot']]); |
|
1090 | + register_error($msg); |
|
1091 | + return false; |
|
1092 | + } |
|
1093 | + } |
|
1094 | + |
|
1095 | + // according to postgres documentation: SQL identifiers and key words must |
|
1096 | + // begin with a letter (a-z, but also letters with diacritical marks and |
|
1097 | + // non-Latin letters) or an underscore (_). Subsequent characters in an |
|
1098 | + // identifier or key word can be letters, underscores, digits (0-9), or dollar signs ($). |
|
1099 | + // Refs #4994 |
|
1100 | + if (!preg_match("/^[a-zA-Z_][\w]*$/", $submissionVars['dbprefix'])) { |
|
1101 | + register_error(elgg_echo('install:error:database_prefix')); |
|
1102 | + return false; |
|
1103 | + } |
|
1104 | + |
|
1105 | + return $this->checkDatabaseSettings( |
|
1106 | + $submissionVars['dbuser'], |
|
1107 | + $submissionVars['dbpassword'], |
|
1108 | + $submissionVars['dbname'], |
|
1109 | + $submissionVars['dbhost'] |
|
1110 | + ); |
|
1111 | + } |
|
1112 | + |
|
1113 | + /** |
|
1114 | + * Confirm the settings for the database |
|
1115 | + * |
|
1116 | + * @param string $user Username |
|
1117 | + * @param string $password Password |
|
1118 | + * @param string $dbname Database name |
|
1119 | + * @param string $host Host |
|
1120 | + * |
|
1121 | + * @return bool |
|
1122 | + */ |
|
1123 | + protected function checkDatabaseSettings($user, $password, $dbname, $host) { |
|
1124 | + $config = new DbConfig((object) [ |
|
1125 | + 'dbhost' => $host, |
|
1126 | + 'dbuser' => $user, |
|
1127 | + 'dbpass' => $password, |
|
1128 | + 'dbname' => $dbname, |
|
1129 | + 'dbencoding' => 'utf8mb4', |
|
1130 | + ]); |
|
1131 | + $db = new \Elgg\Database($config); |
|
1132 | + |
|
1133 | + try { |
|
1134 | + $db->getDataRow("SELECT 1"); |
|
1135 | + } catch (DatabaseException $e) { |
|
1136 | + if (0 === strpos($e->getMessage(), "Elgg couldn't connect")) { |
|
1137 | + register_error(elgg_echo('install:error:databasesettings')); |
|
1138 | + } else { |
|
1139 | + register_error(elgg_echo('install:error:nodatabase', [$dbname])); |
|
1140 | + } |
|
1141 | + return false; |
|
1142 | + } |
|
1143 | + |
|
1144 | + // check MySQL version |
|
1145 | + $version = $db->getServerVersion(DbConfig::READ_WRITE); |
|
1146 | + if (version_compare($version, '5.5.3', '<')) { |
|
1147 | + register_error(elgg_echo('install:error:oldmysql2', [$version])); |
|
1148 | + return false; |
|
1149 | + } |
|
1150 | + |
|
1151 | + return true; |
|
1152 | + } |
|
1153 | + |
|
1154 | + /** |
|
1155 | + * Writes the settings file to the engine directory |
|
1156 | + * |
|
1157 | + * @param array $params Array of inputted params from the user |
|
1158 | + * |
|
1159 | + * @return bool |
|
1160 | + */ |
|
1161 | + protected function createSettingsFile($params) { |
|
1162 | + $template = Application::elggDir()->getContents("elgg-config/settings.example.php"); |
|
1163 | + if (!$template) { |
|
1164 | + register_error(elgg_echo('install:error:readsettingsphp')); |
|
1165 | + return false; |
|
1166 | + } |
|
1167 | + |
|
1168 | + foreach ($params as $k => $v) { |
|
1169 | + $template = str_replace("{{" . $k . "}}", $v, $template); |
|
1170 | + } |
|
1171 | + |
|
1172 | + $result = file_put_contents(Paths::settingsFile(), $template); |
|
1173 | + if (!$result) { |
|
1174 | + register_error(elgg_echo('install:error:writesettingphp')); |
|
1175 | + return false; |
|
1176 | + } |
|
1177 | + |
|
1178 | + return true; |
|
1179 | + } |
|
1180 | + |
|
1181 | + /** |
|
1182 | + * Bootstrap database connection before entire engine is available |
|
1183 | + * |
|
1184 | + * @return bool |
|
1185 | + */ |
|
1186 | + protected function connectToDatabase() { |
|
1187 | + try { |
|
1188 | + $this->services->db->setupConnections(); |
|
1189 | + } catch (DatabaseException $e) { |
|
1190 | + register_error($e->getMessage()); |
|
1191 | + return false; |
|
1192 | + } |
|
1193 | + |
|
1194 | + return true; |
|
1195 | + } |
|
1196 | + |
|
1197 | + /** |
|
1198 | + * Create the database tables |
|
1199 | + * |
|
1200 | + * @return bool |
|
1201 | + */ |
|
1202 | + protected function installDatabase() { |
|
1203 | + $ret = \Elgg\Application::migrate(); |
|
1204 | + if ($ret) { |
|
1205 | + init_site_secret(); |
|
1206 | + } |
|
1207 | + return $ret; |
|
1208 | + } |
|
1209 | + |
|
1210 | + /** |
|
1211 | + * Site settings support methods |
|
1212 | + */ |
|
1213 | + |
|
1214 | + /** |
|
1215 | + * Create the data directory if requested |
|
1216 | + * |
|
1217 | + * @param array $submissionVars Submitted vars |
|
1218 | + * @param array $formVars Variables in the form |
|
1219 | + * |
|
1220 | + * @return bool |
|
1221 | + */ |
|
1222 | + protected function createDataDirectory(&$submissionVars, $formVars) { |
|
1223 | + // did the user have option of Elgg creating the data directory |
|
1224 | + if ($formVars['dataroot']['type'] != 'combo') { |
|
1225 | + return true; |
|
1226 | + } |
|
1227 | + |
|
1228 | + // did the user select the option |
|
1229 | + if ($submissionVars['dataroot'] != 'dataroot-checkbox') { |
|
1230 | + return true; |
|
1231 | + } |
|
1232 | + |
|
1233 | + $dir = sanitise_filepath($submissionVars['path']) . 'data'; |
|
1234 | + if (file_exists($dir) || mkdir($dir, 0700)) { |
|
1235 | + $submissionVars['dataroot'] = $dir; |
|
1236 | + if (!file_exists("$dir/.htaccess")) { |
|
1237 | + $htaccess = "Order Deny,Allow\nDeny from All\n"; |
|
1238 | + if (!file_put_contents("$dir/.htaccess", $htaccess)) { |
|
1239 | + return false; |
|
1240 | + } |
|
1241 | + } |
|
1242 | + return true; |
|
1243 | + } |
|
1244 | + |
|
1245 | + return false; |
|
1246 | + } |
|
1247 | + |
|
1248 | + /** |
|
1249 | + * Validate the site settings form variables |
|
1250 | + * |
|
1251 | + * @param array $submissionVars Submitted vars |
|
1252 | + * @param array $formVars Vars in the form |
|
1253 | + * |
|
1254 | + * @return bool |
|
1255 | + */ |
|
1256 | + protected function validateSettingsVars($submissionVars, $formVars) { |
|
1257 | + foreach ($formVars as $field => $info) { |
|
1258 | + $submissionVars[$field] = trim($submissionVars[$field]); |
|
1259 | + if ($info['required'] == true && $submissionVars[$field] === '') { |
|
1260 | + $name = elgg_echo("install:settings:label:$field"); |
|
1261 | + register_error(elgg_echo('install:error:requiredfield', [$name])); |
|
1262 | + return false; |
|
1263 | + } |
|
1264 | + } |
|
1265 | + |
|
1266 | + // check that email address is email address |
|
1267 | + if ($submissionVars['siteemail'] && !is_email_address($submissionVars['siteemail'])) { |
|
1268 | + $msg = elgg_echo('install:error:emailaddress', [$submissionVars['siteemail']]); |
|
1269 | + register_error($msg); |
|
1270 | + return false; |
|
1271 | + } |
|
1272 | + |
|
1273 | + // @todo check that url is a url |
|
1274 | + // @note filter_var cannot be used because it doesn't work on international urls |
|
1275 | + |
|
1276 | + return true; |
|
1277 | + } |
|
1278 | + |
|
1279 | + /** |
|
1280 | + * Initialize the site including site entity, plugins, and configuration |
|
1281 | + * |
|
1282 | + * @param array $submissionVars Submitted vars |
|
1283 | + * |
|
1284 | + * @return bool |
|
1285 | + */ |
|
1286 | + protected function saveSiteSettings($submissionVars) { |
|
1287 | + $site = new ElggSite(); |
|
1288 | + $site->name = strip_tags($submissionVars['sitename']); |
|
1289 | + $site->access_id = ACCESS_PUBLIC; |
|
1290 | + $site->email = $submissionVars['siteemail']; |
|
1291 | + |
|
1292 | + $guid = $site->save(); |
|
1293 | + if ($guid !== 1) { |
|
1294 | + register_error(elgg_echo('install:error:createsite')); |
|
1295 | + return false; |
|
1296 | + } |
|
1297 | + |
|
1298 | + $this->config->site = $site; |
|
1299 | + |
|
1300 | + // new installations have run all the upgrades |
|
1301 | + $upgrades = elgg_get_upgrade_files(Paths::elgg() . "engine/lib/upgrades/"); |
|
1302 | + |
|
1303 | + $sets = [ |
|
1304 | + 'installed' => time(), |
|
1305 | + 'version' => elgg_get_version(), |
|
1306 | + 'simplecache_enabled' => 1, |
|
1307 | + 'system_cache_enabled' => 1, |
|
1308 | + 'simplecache_lastupdate' => time(), |
|
1309 | + 'processed_upgrades' => $upgrades, |
|
1310 | + 'language' => 'en', |
|
1311 | + 'default_access' => $submissionVars['siteaccess'], |
|
1312 | + 'allow_registration' => false, |
|
1313 | + 'walled_garden' => false, |
|
1314 | + 'allow_user_default_access' => '', |
|
1315 | + 'default_limit' => 10, |
|
1316 | + 'security_protect_upgrade' => true, |
|
1317 | + 'security_notify_admins' => true, |
|
1318 | + 'security_notify_user_password' => true, |
|
1319 | + 'security_email_require_password' => true, |
|
1320 | + ]; |
|
1321 | + foreach ($sets as $key => $value) { |
|
1322 | + elgg_save_config($key, $value); |
|
1323 | + } |
|
1324 | + |
|
1325 | + // Enable a set of default plugins |
|
1326 | + _elgg_generate_plugin_entities(); |
|
1327 | + |
|
1328 | + foreach (elgg_get_plugins('any') as $plugin) { |
|
1329 | + if ($plugin->getManifest()) { |
|
1330 | + if ($plugin->getManifest()->getActivateOnInstall()) { |
|
1331 | + $plugin->activate(); |
|
1332 | + } |
|
1333 | + if (in_array('theme', $plugin->getManifest()->getCategories())) { |
|
1334 | + $plugin->setPriority('last'); |
|
1335 | + } |
|
1336 | + } |
|
1337 | + } |
|
1338 | + |
|
1339 | + return true; |
|
1340 | + } |
|
1341 | + |
|
1342 | + /** |
|
1343 | + * Admin account support methods |
|
1344 | + */ |
|
1345 | + |
|
1346 | + /** |
|
1347 | + * Validate account form variables |
|
1348 | + * |
|
1349 | + * @param array $submissionVars Submitted vars |
|
1350 | + * @param array $formVars Form vars |
|
1351 | + * |
|
1352 | + * @return bool |
|
1353 | + */ |
|
1354 | + protected function validateAdminVars($submissionVars, $formVars) { |
|
1355 | + |
|
1356 | + foreach ($formVars as $field => $info) { |
|
1357 | + if ($info['required'] == true && !$submissionVars[$field]) { |
|
1358 | + $name = elgg_echo("install:admin:label:$field"); |
|
1359 | + register_error(elgg_echo('install:error:requiredfield', [$name])); |
|
1360 | + return false; |
|
1361 | + } |
|
1362 | + } |
|
1363 | + |
|
1364 | + if ($submissionVars['password1'] !== $submissionVars['password2']) { |
|
1365 | + register_error(elgg_echo('install:admin:password:mismatch')); |
|
1366 | + return false; |
|
1367 | + } |
|
1368 | + |
|
1369 | + if (trim($submissionVars['password1']) == "") { |
|
1370 | + register_error(elgg_echo('install:admin:password:empty')); |
|
1371 | + return false; |
|
1372 | + } |
|
1373 | + |
|
1374 | + $minLength = $this->services->configTable->get('min_password_length'); |
|
1375 | + if (strlen($submissionVars['password1']) < $minLength) { |
|
1376 | + register_error(elgg_echo('install:admin:password:tooshort')); |
|
1377 | + return false; |
|
1378 | + } |
|
1379 | + |
|
1380 | + // check that email address is email address |
|
1381 | + if ($submissionVars['email'] && !is_email_address($submissionVars['email'])) { |
|
1382 | + $msg = elgg_echo('install:error:emailaddress', [$submissionVars['email']]); |
|
1383 | + register_error($msg); |
|
1384 | + return false; |
|
1385 | + } |
|
1386 | + |
|
1387 | + return true; |
|
1388 | + } |
|
1389 | + |
|
1390 | + /** |
|
1391 | + * Create a user account for the admin |
|
1392 | + * |
|
1393 | + * @param array $submissionVars Submitted vars |
|
1394 | + * @param bool $login Login in the admin user? |
|
1395 | + * |
|
1396 | + * @return bool |
|
1397 | + */ |
|
1398 | + protected function createAdminAccount($submissionVars, $login = false) { |
|
1399 | + try { |
|
1400 | + $guid = register_user( |
|
1401 | + $submissionVars['username'], |
|
1402 | + $submissionVars['password1'], |
|
1403 | + $submissionVars['displayname'], |
|
1404 | + $submissionVars['email'] |
|
1405 | + ); |
|
1406 | + } catch (Exception $e) { |
|
1407 | + register_error($e->getMessage()); |
|
1408 | + return false; |
|
1409 | + } |
|
1410 | + |
|
1411 | + if (!$guid) { |
|
1412 | + register_error(elgg_echo('install:admin:cannot_create')); |
|
1413 | + return false; |
|
1414 | + } |
|
1415 | + |
|
1416 | + $user = get_entity($guid); |
|
1417 | + if (!$user instanceof ElggUser) { |
|
1418 | + register_error(elgg_echo('install:error:loadadmin')); |
|
1419 | + return false; |
|
1420 | + } |
|
1421 | + |
|
1422 | + $ia = elgg_set_ignore_access(true); |
|
1423 | + if ($user->makeAdmin() == false) { |
|
1424 | + register_error(elgg_echo('install:error:adminaccess')); |
|
1425 | + } else { |
|
1426 | + $this->services->configTable->set('admin_registered', 1); |
|
1427 | + } |
|
1428 | + elgg_set_ignore_access($ia); |
|
1429 | + |
|
1430 | + // add validation data to satisfy user validation plugins |
|
1431 | + $user->validated = 1; |
|
1432 | + $user->validated_method = 'admin_user'; |
|
1433 | + |
|
1434 | + if (!$login) { |
|
1435 | + return true; |
|
1436 | + } |
|
1437 | + |
|
1438 | + $session = ElggSession::fromDatabase($this->config, $this->services->db); |
|
1439 | + $session->start(); |
|
1440 | + $this->services->setValue('session', $session); |
|
1441 | + if (login($user) == false) { |
|
1442 | + register_error(elgg_echo('install:error:adminlogin')); |
|
1443 | + } |
|
1444 | + |
|
1445 | + return true; |
|
1446 | + } |
|
1447 | 1447 | } |
@@ -95,404 +95,404 @@ |
||
95 | 95 | */ |
96 | 96 | class ServiceProvider extends DiContainer { |
97 | 97 | |
98 | - /** |
|
99 | - * Constructor |
|
100 | - * |
|
101 | - * @param Config $config Elgg Config service |
|
102 | - */ |
|
103 | - public function __construct(Config $config) { |
|
104 | - |
|
105 | - $this->setFactory('autoloadManager', function(ServiceProvider $c) { |
|
106 | - $manager = new \Elgg\AutoloadManager($c->classLoader); |
|
107 | - if (!$c->config->AutoloaderManager_skip_storage) { |
|
108 | - $manager->setStorage($c->fileCache); |
|
109 | - $manager->loadCache(); |
|
110 | - } |
|
111 | - return $manager; |
|
112 | - }); |
|
113 | - |
|
114 | - $this->setFactory('accessCache', function(ServiceProvider $c) { |
|
115 | - return new \ElggStaticVariableCache('access'); |
|
116 | - }); |
|
117 | - |
|
118 | - $this->setFactory('accessCollections', function(ServiceProvider $c) { |
|
119 | - return new \Elgg\Database\AccessCollections( |
|
120 | - $c->config, $c->db, $c->entityTable, $c->userCapabilities, $c->accessCache, $c->hooks, $c->session, $c->translator); |
|
121 | - }); |
|
122 | - |
|
123 | - $this->setFactory('actions', function(ServiceProvider $c) { |
|
124 | - return new \Elgg\ActionsService($c->config, $c->session, $c->crypto); |
|
125 | - }); |
|
126 | - |
|
127 | - $this->setClassName('adminNotices', \Elgg\Database\AdminNotices::class); |
|
128 | - |
|
129 | - $this->setFactory('ajax', function(ServiceProvider $c) { |
|
130 | - return new \Elgg\Ajax\Service($c->hooks, $c->systemMessages, $c->input, $c->amdConfig); |
|
131 | - }); |
|
132 | - |
|
133 | - $this->setFactory('amdConfig', function(ServiceProvider $c) { |
|
134 | - $obj = new \Elgg\Amd\Config($c->hooks); |
|
135 | - $obj->setBaseUrl($c->simpleCache->getRoot()); |
|
136 | - return $obj; |
|
137 | - }); |
|
138 | - |
|
139 | - $this->setFactory('annotations', function(ServiceProvider $c) { |
|
140 | - return new \Elgg\Database\Annotations($c->db, $c->session, $c->hooks->getEvents()); |
|
141 | - }); |
|
142 | - |
|
143 | - $this->setClassName('autoP', \ElggAutoP::class); |
|
144 | - |
|
145 | - $this->setFactory('boot', function(ServiceProvider $c) { |
|
146 | - $boot = new \Elgg\BootService(); |
|
147 | - if ($c->config->enable_profiling) { |
|
148 | - $boot->setTimer($c->timer); |
|
149 | - } |
|
150 | - return $boot; |
|
151 | - }); |
|
152 | - |
|
153 | - $this->setFactory('batchUpgrader', function(ServiceProvider $c) { |
|
154 | - return new \Elgg\BatchUpgrader($c->config); |
|
155 | - }); |
|
156 | - |
|
157 | - $this->setFactory('cacheHandler', function(ServiceProvider $c) { |
|
158 | - $simplecache_enabled = $c->config->simplecache_enabled; |
|
159 | - if ($simplecache_enabled === null) { |
|
160 | - $simplecache_enabled = $c->configTable->get('simplecache_enabled'); |
|
161 | - } |
|
162 | - return new \Elgg\Application\CacheHandler($c->config, $c->request, $simplecache_enabled); |
|
163 | - }); |
|
164 | - |
|
165 | - $this->setFactory('classLoader', function(ServiceProvider $c) { |
|
166 | - $loader = new \Elgg\ClassLoader(new \Elgg\ClassMap()); |
|
167 | - $loader->register(); |
|
168 | - return $loader; |
|
169 | - }); |
|
170 | - |
|
171 | - $this->setValue('config', $config); |
|
172 | - |
|
173 | - $this->setFactory('configTable', function(ServiceProvider $c) { |
|
174 | - return new \Elgg\Database\ConfigTable($c->db, $c->boot, $c->logger); |
|
175 | - }); |
|
176 | - |
|
177 | - $this->setFactory('context', function(ServiceProvider $c) { |
|
178 | - $context = new \Elgg\Context(); |
|
179 | - $context->initialize($c->request); |
|
180 | - return $context; |
|
181 | - }); |
|
182 | - |
|
183 | - $this->setClassName('crypto', \ElggCrypto::class); |
|
184 | - |
|
185 | - $this->setFactory('db', function(ServiceProvider $c) { |
|
186 | - $db = new \Elgg\Database($c->dbConfig); |
|
187 | - $db->setLogger($c->logger); |
|
188 | - |
|
189 | - if ($c->config->profiling_sql) { |
|
190 | - $db->setTimer($c->timer); |
|
191 | - } |
|
192 | - |
|
193 | - return $db; |
|
194 | - }); |
|
195 | - |
|
196 | - $this->setFactory('dbConfig', function(ServiceProvider $c) { |
|
197 | - $config = $c->config; |
|
198 | - $db_config = \Elgg\Database\DbConfig::fromElggConfig($config); |
|
199 | - |
|
200 | - // get this stuff out of config! |
|
201 | - unset($config->db); |
|
202 | - unset($config->dbname); |
|
203 | - unset($config->dbhost); |
|
204 | - unset($config->dbuser); |
|
205 | - unset($config->dbpass); |
|
206 | - |
|
207 | - return $db_config; |
|
208 | - }); |
|
209 | - |
|
210 | - $this->setFactory('deprecation', function(ServiceProvider $c) { |
|
211 | - return new \Elgg\DeprecationService($c->logger); |
|
212 | - }); |
|
213 | - |
|
214 | - $this->setFactory('emails', function(ServiceProvider $c) { |
|
215 | - return new \Elgg\EmailService($c->config, $c->hooks, $c->mailer, $c->logger); |
|
216 | - }); |
|
217 | - |
|
218 | - $this->setFactory('entityCache', function(ServiceProvider $c) { |
|
219 | - return new \Elgg\Cache\EntityCache($c->session, $c->metadataCache); |
|
220 | - }); |
|
221 | - |
|
222 | - $this->setFactory('entityPreloader', function(ServiceProvider $c) { |
|
223 | - return new \Elgg\EntityPreloader($c->entityCache, $c->entityTable); |
|
224 | - }); |
|
225 | - |
|
226 | - $this->setFactory('entityTable', function(ServiceProvider $c) { |
|
227 | - return new \Elgg\Database\EntityTable( |
|
228 | - $c->config, |
|
229 | - $c->db, |
|
230 | - $c->entityCache, |
|
231 | - $c->metadataCache, |
|
232 | - $c->subtypeTable, |
|
233 | - $c->hooks->getEvents(), |
|
234 | - $c->session, |
|
235 | - $c->translator, |
|
236 | - $c->logger |
|
237 | - ); |
|
238 | - }); |
|
239 | - |
|
240 | - $this->setClassName('externalFiles', \Elgg\Assets\ExternalFiles::class); |
|
241 | - |
|
242 | - $this->setFactory('fileCache', function(ServiceProvider $c) { |
|
243 | - return new \ElggFileCache($c->config->cacheroot . 'system_cache/'); |
|
244 | - }); |
|
245 | - |
|
246 | - $this->setFactory('filestore', function(ServiceProvider $c) { |
|
247 | - return new \ElggDiskFilestore($c->config->dataroot); |
|
248 | - }); |
|
249 | - |
|
250 | - $this->setFactory('forms', function(ServiceProvider $c) { |
|
251 | - return new \Elgg\FormsService($c->views, $c->logger); |
|
252 | - }); |
|
253 | - |
|
254 | - $this->setClassName('handlers', \Elgg\HandlersService::class); |
|
255 | - |
|
256 | - $this->setFactory('hmac', function(ServiceProvider $c) { |
|
257 | - return new \Elgg\Security\HmacFactory($c->siteSecret, $c->crypto); |
|
258 | - }); |
|
259 | - |
|
260 | - $this->setFactory('hooks', function(ServiceProvider $c) { |
|
261 | - $events = new \Elgg\EventsService($c->handlers); |
|
262 | - if ($c->config->enable_profiling) { |
|
263 | - $events->setTimer($c->timer); |
|
264 | - } |
|
265 | - return new \Elgg\PluginHooksService($events); |
|
266 | - }); |
|
267 | - |
|
268 | - $this->setFactory('iconService', function(ServiceProvider $c) { |
|
269 | - return new \Elgg\EntityIconService($c->config, $c->hooks, $c->request, $c->logger, $c->entityTable); |
|
270 | - }); |
|
271 | - |
|
272 | - $this->setClassName('input', \Elgg\Http\Input::class); |
|
273 | - |
|
274 | - $this->setFactory('imageService', function(ServiceProvider $c) { |
|
275 | - $imagine = new \Imagine\Gd\Imagine(); |
|
276 | - return new \Elgg\ImageService($imagine, $c->config); |
|
277 | - }); |
|
278 | - |
|
279 | - $this->setFactory('logger', function (ServiceProvider $c) { |
|
280 | - $logger = new \Elgg\Logger($c->hooks, $c->context); |
|
281 | - $logger->setLevel($c->config->debug); |
|
282 | - return $logger; |
|
283 | - }); |
|
284 | - |
|
285 | - // TODO(evan): Support configurable transports... |
|
286 | - $this->setClassName('mailer', 'Zend\Mail\Transport\Sendmail'); |
|
287 | - |
|
288 | - $this->setFactory('menus', function(ServiceProvider $c) { |
|
289 | - return new \Elgg\Menu\Service($c->hooks, $c->config); |
|
290 | - }); |
|
291 | - |
|
292 | - $this->setFactory('metadataCache', function (ServiceProvider $c) { |
|
293 | - $cache = _elgg_get_memcache('metadata'); |
|
294 | - return new \Elgg\Cache\MetadataCache($cache); |
|
295 | - }); |
|
296 | - |
|
297 | - $this->setFactory('memcacheStashPool', function(ServiceProvider $c) { |
|
298 | - if (!$c->config->memcache) { |
|
299 | - return null; |
|
300 | - } |
|
301 | - |
|
302 | - $servers = $c->config->memcache_servers; |
|
303 | - if (!$servers) { |
|
304 | - return null; |
|
305 | - } |
|
306 | - $driver = new \Stash\Driver\Memcache([ |
|
307 | - 'servers' => $servers, |
|
308 | - ]); |
|
309 | - return new \Stash\Pool($driver); |
|
310 | - }); |
|
311 | - |
|
312 | - $this->setFactory('metadataTable', function(ServiceProvider $c) { |
|
313 | - // TODO(ewinslow): Use Pool instead of MetadataCache for caching |
|
314 | - return new \Elgg\Database\MetadataTable( |
|
315 | - $c->metadataCache, $c->db, $c->entityTable, $c->hooks->getEvents(), $c->session); |
|
316 | - }); |
|
317 | - |
|
318 | - $this->setFactory('mutex', function(ServiceProvider $c) { |
|
319 | - return new \Elgg\Database\Mutex( |
|
320 | - $c->db, |
|
321 | - $c->logger |
|
322 | - ); |
|
323 | - }); |
|
324 | - |
|
325 | - $this->setFactory('notifications', function(ServiceProvider $c) { |
|
326 | - // @todo move queue in service provider |
|
327 | - $queue_name = \Elgg\Notifications\NotificationsService::QUEUE_NAME; |
|
328 | - $queue = new \Elgg\Queue\DatabaseQueue($queue_name, $c->db); |
|
329 | - $sub = new \Elgg\Notifications\SubscriptionsService($c->db); |
|
330 | - return new \Elgg\Notifications\NotificationsService($sub, $queue, $c->hooks, $c->session, $c->translator, $c->entityTable, $c->logger); |
|
331 | - }); |
|
332 | - |
|
333 | - $this->setClassName('nullCache', \Elgg\Cache\NullCache::class); |
|
334 | - |
|
335 | - $this->setFactory('persistentLogin', function(ServiceProvider $c) { |
|
336 | - $global_cookies_config = $c->config->getCookieConfig(); |
|
337 | - $cookie_config = $global_cookies_config['remember_me']; |
|
338 | - $cookie_name = $cookie_config['name']; |
|
339 | - $cookie_token = $c->request->cookies->get($cookie_name, ''); |
|
340 | - return new \Elgg\PersistentLoginService( |
|
341 | - $c->db, $c->session, $c->crypto, $cookie_config, $cookie_token); |
|
342 | - }); |
|
343 | - |
|
344 | - $this->setClassName('passwords', \Elgg\PasswordService::class); |
|
345 | - |
|
346 | - $this->setFactory('plugins', function(ServiceProvider $c) { |
|
347 | - $pool = new Pool\InMemory(); |
|
348 | - $plugins = new \Elgg\Database\Plugins($pool, $c->pluginSettingsCache); |
|
349 | - if ($c->config->enable_profiling) { |
|
350 | - $plugins->setTimer($c->timer); |
|
351 | - } |
|
352 | - return $plugins; |
|
353 | - }); |
|
354 | - |
|
355 | - $this->setClassName('pluginSettingsCache', \Elgg\Cache\PluginSettingsCache::class); |
|
356 | - |
|
357 | - $this->setFactory('privateSettings', function(ServiceProvider $c) { |
|
358 | - return new \Elgg\Database\PrivateSettingsTable($c->db, $c->entityTable, $c->pluginSettingsCache); |
|
359 | - }); |
|
360 | - |
|
361 | - $this->setFactory('publicDb', function(ServiceProvider $c) { |
|
362 | - return new \Elgg\Application\Database($c->db); |
|
363 | - }); |
|
364 | - |
|
365 | - $this->setFactory('queryCounter', function(ServiceProvider $c) { |
|
366 | - return new \Elgg\Database\QueryCounter($c->db); |
|
367 | - }, false); |
|
368 | - |
|
369 | - $this->setFactory('redirects', function(ServiceProvider $c) { |
|
370 | - $url = current_page_url(); |
|
371 | - $is_xhr = $c->request->isXmlHttpRequest(); |
|
372 | - return new \Elgg\RedirectService($c->session, $is_xhr, $c->config->wwwroot, $url); |
|
373 | - }); |
|
374 | - |
|
375 | - $this->setFactory('relationshipsTable', function(ServiceProvider $c) { |
|
376 | - return new \Elgg\Database\RelationshipsTable($c->db, $c->entityTable, $c->metadataTable, $c->hooks->getEvents()); |
|
377 | - }); |
|
378 | - |
|
379 | - $this->setFactory('request', [\Elgg\Http\Request::class, 'createFromGlobals']); |
|
380 | - |
|
381 | - $this->setFactory('responseFactory', function(ServiceProvider $c) { |
|
382 | - if (PHP_SAPI === 'cli') { |
|
383 | - $transport = new \Elgg\Http\OutputBufferTransport(); |
|
384 | - } else { |
|
385 | - $transport = new \Elgg\Http\HttpProtocolTransport(); |
|
386 | - } |
|
387 | - return new \Elgg\Http\ResponseFactory($c->request, $c->hooks, $c->ajax, $transport); |
|
388 | - }); |
|
389 | - |
|
390 | - $this->setFactory('router', function(ServiceProvider $c) { |
|
391 | - // TODO(evan): Init routes from plugins or cache |
|
392 | - $router = new \Elgg\Router($c->hooks); |
|
393 | - if ($c->config->enable_profiling) { |
|
394 | - $router->setTimer($c->timer); |
|
395 | - } |
|
396 | - return $router; |
|
397 | - }); |
|
398 | - |
|
399 | - $this->setFactory('seeder', function(ServiceProvider $c) { |
|
400 | - return new \Elgg\Database\Seeder($c->hooks); |
|
401 | - }); |
|
402 | - |
|
403 | - $this->setFactory('serveFileHandler', function(ServiceProvider $c) { |
|
404 | - return new \Elgg\Application\ServeFileHandler($c->hmac, $c->config); |
|
405 | - }); |
|
406 | - |
|
407 | - $this->setFactory('session', function(ServiceProvider $c) { |
|
408 | - return \ElggSession::fromDatabase($c->config, $c->db); |
|
409 | - }); |
|
410 | - |
|
411 | - $this->setClassName('urlSigner', \Elgg\Security\UrlSigner::class); |
|
412 | - |
|
413 | - $this->setFactory('simpleCache', function(ServiceProvider $c) { |
|
414 | - return new \Elgg\Cache\SimpleCache($c->config); |
|
415 | - }); |
|
416 | - |
|
417 | - /** |
|
418 | - * If the key is in the settings file, this is injected early. |
|
419 | - * |
|
420 | - * @see \Elgg\Application::initConfig |
|
421 | - */ |
|
422 | - $this->setFactory('siteSecret', function(ServiceProvider $c) { |
|
423 | - return \Elgg\Database\SiteSecret::fromDatabase($c->configTable); |
|
424 | - }); |
|
425 | - |
|
426 | - $this->setClassName('stickyForms', \Elgg\Forms\StickyForms::class); |
|
427 | - |
|
428 | - $this->setFactory('subtypeTable', function(ServiceProvider $c) { |
|
429 | - return new \Elgg\Database\SubtypeTable($c->db); |
|
430 | - }); |
|
431 | - |
|
432 | - $this->setFactory('systemCache', function (ServiceProvider $c) { |
|
433 | - $cache = new \Elgg\Cache\SystemCache($c->fileCache, $c->config); |
|
434 | - if ($c->config->enable_profiling) { |
|
435 | - $cache->setTimer($c->timer); |
|
436 | - } |
|
437 | - return $cache; |
|
438 | - }); |
|
439 | - |
|
440 | - $this->setFactory('systemMessages', function(ServiceProvider $c) { |
|
441 | - return new \Elgg\SystemMessagesService($c->session); |
|
442 | - }); |
|
443 | - |
|
444 | - $this->setClassName('table_columns', \Elgg\Views\TableColumn\ColumnFactory::class); |
|
445 | - |
|
446 | - $this->setClassName('timer', \Elgg\Timer::class); |
|
447 | - |
|
448 | - $this->setFactory('translator', function(ServiceProvider $c) { |
|
449 | - return new \Elgg\I18n\Translator($c->config); |
|
450 | - }); |
|
451 | - |
|
452 | - $this->setFactory('uploads', function(ServiceProvider $c) { |
|
453 | - return new \Elgg\UploadService($c->request); |
|
454 | - }); |
|
455 | - |
|
456 | - $this->setFactory('upgrades', function(ServiceProvider $c) { |
|
457 | - return new \Elgg\UpgradeService( |
|
458 | - $c->translator, |
|
459 | - $c->hooks, |
|
460 | - $c->config, |
|
461 | - $c->logger, |
|
462 | - $c->mutex |
|
463 | - ); |
|
464 | - }); |
|
465 | - |
|
466 | - $this->setFactory('userCapabilities', function(ServiceProvider $c) { |
|
467 | - return new \Elgg\UserCapabilities($c->hooks, $c->entityTable, $c->session); |
|
468 | - }); |
|
469 | - |
|
470 | - $this->setFactory('usersTable', function(ServiceProvider $c) { |
|
471 | - return new \Elgg\Database\UsersTable( |
|
472 | - $c->config, |
|
473 | - $c->db, |
|
474 | - $c->entityTable, |
|
475 | - $c->entityCache, |
|
476 | - $c->hooks->getEvents() |
|
477 | - ); |
|
478 | - }); |
|
479 | - |
|
480 | - $this->setFactory('upgradeLocator', function(ServiceProvider $c) { |
|
481 | - return new \Elgg\Upgrade\Locator( |
|
482 | - $c->plugins, |
|
483 | - $c->logger, |
|
484 | - $c->privateSettings |
|
485 | - ); |
|
486 | - }); |
|
487 | - |
|
488 | - $this->setFactory('views', function(ServiceProvider $c) { |
|
489 | - return new \Elgg\ViewsService($c->hooks, $c->logger, $c->input); |
|
490 | - }); |
|
491 | - |
|
492 | - $this->setFactory('viewCacher', function(ServiceProvider $c) { |
|
493 | - return new \Elgg\Cache\ViewCacher($c->views, $c->config); |
|
494 | - }); |
|
495 | - |
|
496 | - $this->setClassName('widgets', \Elgg\WidgetsService::class); |
|
497 | - } |
|
98 | + /** |
|
99 | + * Constructor |
|
100 | + * |
|
101 | + * @param Config $config Elgg Config service |
|
102 | + */ |
|
103 | + public function __construct(Config $config) { |
|
104 | + |
|
105 | + $this->setFactory('autoloadManager', function(ServiceProvider $c) { |
|
106 | + $manager = new \Elgg\AutoloadManager($c->classLoader); |
|
107 | + if (!$c->config->AutoloaderManager_skip_storage) { |
|
108 | + $manager->setStorage($c->fileCache); |
|
109 | + $manager->loadCache(); |
|
110 | + } |
|
111 | + return $manager; |
|
112 | + }); |
|
113 | + |
|
114 | + $this->setFactory('accessCache', function(ServiceProvider $c) { |
|
115 | + return new \ElggStaticVariableCache('access'); |
|
116 | + }); |
|
117 | + |
|
118 | + $this->setFactory('accessCollections', function(ServiceProvider $c) { |
|
119 | + return new \Elgg\Database\AccessCollections( |
|
120 | + $c->config, $c->db, $c->entityTable, $c->userCapabilities, $c->accessCache, $c->hooks, $c->session, $c->translator); |
|
121 | + }); |
|
122 | + |
|
123 | + $this->setFactory('actions', function(ServiceProvider $c) { |
|
124 | + return new \Elgg\ActionsService($c->config, $c->session, $c->crypto); |
|
125 | + }); |
|
126 | + |
|
127 | + $this->setClassName('adminNotices', \Elgg\Database\AdminNotices::class); |
|
128 | + |
|
129 | + $this->setFactory('ajax', function(ServiceProvider $c) { |
|
130 | + return new \Elgg\Ajax\Service($c->hooks, $c->systemMessages, $c->input, $c->amdConfig); |
|
131 | + }); |
|
132 | + |
|
133 | + $this->setFactory('amdConfig', function(ServiceProvider $c) { |
|
134 | + $obj = new \Elgg\Amd\Config($c->hooks); |
|
135 | + $obj->setBaseUrl($c->simpleCache->getRoot()); |
|
136 | + return $obj; |
|
137 | + }); |
|
138 | + |
|
139 | + $this->setFactory('annotations', function(ServiceProvider $c) { |
|
140 | + return new \Elgg\Database\Annotations($c->db, $c->session, $c->hooks->getEvents()); |
|
141 | + }); |
|
142 | + |
|
143 | + $this->setClassName('autoP', \ElggAutoP::class); |
|
144 | + |
|
145 | + $this->setFactory('boot', function(ServiceProvider $c) { |
|
146 | + $boot = new \Elgg\BootService(); |
|
147 | + if ($c->config->enable_profiling) { |
|
148 | + $boot->setTimer($c->timer); |
|
149 | + } |
|
150 | + return $boot; |
|
151 | + }); |
|
152 | + |
|
153 | + $this->setFactory('batchUpgrader', function(ServiceProvider $c) { |
|
154 | + return new \Elgg\BatchUpgrader($c->config); |
|
155 | + }); |
|
156 | + |
|
157 | + $this->setFactory('cacheHandler', function(ServiceProvider $c) { |
|
158 | + $simplecache_enabled = $c->config->simplecache_enabled; |
|
159 | + if ($simplecache_enabled === null) { |
|
160 | + $simplecache_enabled = $c->configTable->get('simplecache_enabled'); |
|
161 | + } |
|
162 | + return new \Elgg\Application\CacheHandler($c->config, $c->request, $simplecache_enabled); |
|
163 | + }); |
|
164 | + |
|
165 | + $this->setFactory('classLoader', function(ServiceProvider $c) { |
|
166 | + $loader = new \Elgg\ClassLoader(new \Elgg\ClassMap()); |
|
167 | + $loader->register(); |
|
168 | + return $loader; |
|
169 | + }); |
|
170 | + |
|
171 | + $this->setValue('config', $config); |
|
172 | + |
|
173 | + $this->setFactory('configTable', function(ServiceProvider $c) { |
|
174 | + return new \Elgg\Database\ConfigTable($c->db, $c->boot, $c->logger); |
|
175 | + }); |
|
176 | + |
|
177 | + $this->setFactory('context', function(ServiceProvider $c) { |
|
178 | + $context = new \Elgg\Context(); |
|
179 | + $context->initialize($c->request); |
|
180 | + return $context; |
|
181 | + }); |
|
182 | + |
|
183 | + $this->setClassName('crypto', \ElggCrypto::class); |
|
184 | + |
|
185 | + $this->setFactory('db', function(ServiceProvider $c) { |
|
186 | + $db = new \Elgg\Database($c->dbConfig); |
|
187 | + $db->setLogger($c->logger); |
|
188 | + |
|
189 | + if ($c->config->profiling_sql) { |
|
190 | + $db->setTimer($c->timer); |
|
191 | + } |
|
192 | + |
|
193 | + return $db; |
|
194 | + }); |
|
195 | + |
|
196 | + $this->setFactory('dbConfig', function(ServiceProvider $c) { |
|
197 | + $config = $c->config; |
|
198 | + $db_config = \Elgg\Database\DbConfig::fromElggConfig($config); |
|
199 | + |
|
200 | + // get this stuff out of config! |
|
201 | + unset($config->db); |
|
202 | + unset($config->dbname); |
|
203 | + unset($config->dbhost); |
|
204 | + unset($config->dbuser); |
|
205 | + unset($config->dbpass); |
|
206 | + |
|
207 | + return $db_config; |
|
208 | + }); |
|
209 | + |
|
210 | + $this->setFactory('deprecation', function(ServiceProvider $c) { |
|
211 | + return new \Elgg\DeprecationService($c->logger); |
|
212 | + }); |
|
213 | + |
|
214 | + $this->setFactory('emails', function(ServiceProvider $c) { |
|
215 | + return new \Elgg\EmailService($c->config, $c->hooks, $c->mailer, $c->logger); |
|
216 | + }); |
|
217 | + |
|
218 | + $this->setFactory('entityCache', function(ServiceProvider $c) { |
|
219 | + return new \Elgg\Cache\EntityCache($c->session, $c->metadataCache); |
|
220 | + }); |
|
221 | + |
|
222 | + $this->setFactory('entityPreloader', function(ServiceProvider $c) { |
|
223 | + return new \Elgg\EntityPreloader($c->entityCache, $c->entityTable); |
|
224 | + }); |
|
225 | + |
|
226 | + $this->setFactory('entityTable', function(ServiceProvider $c) { |
|
227 | + return new \Elgg\Database\EntityTable( |
|
228 | + $c->config, |
|
229 | + $c->db, |
|
230 | + $c->entityCache, |
|
231 | + $c->metadataCache, |
|
232 | + $c->subtypeTable, |
|
233 | + $c->hooks->getEvents(), |
|
234 | + $c->session, |
|
235 | + $c->translator, |
|
236 | + $c->logger |
|
237 | + ); |
|
238 | + }); |
|
239 | + |
|
240 | + $this->setClassName('externalFiles', \Elgg\Assets\ExternalFiles::class); |
|
241 | + |
|
242 | + $this->setFactory('fileCache', function(ServiceProvider $c) { |
|
243 | + return new \ElggFileCache($c->config->cacheroot . 'system_cache/'); |
|
244 | + }); |
|
245 | + |
|
246 | + $this->setFactory('filestore', function(ServiceProvider $c) { |
|
247 | + return new \ElggDiskFilestore($c->config->dataroot); |
|
248 | + }); |
|
249 | + |
|
250 | + $this->setFactory('forms', function(ServiceProvider $c) { |
|
251 | + return new \Elgg\FormsService($c->views, $c->logger); |
|
252 | + }); |
|
253 | + |
|
254 | + $this->setClassName('handlers', \Elgg\HandlersService::class); |
|
255 | + |
|
256 | + $this->setFactory('hmac', function(ServiceProvider $c) { |
|
257 | + return new \Elgg\Security\HmacFactory($c->siteSecret, $c->crypto); |
|
258 | + }); |
|
259 | + |
|
260 | + $this->setFactory('hooks', function(ServiceProvider $c) { |
|
261 | + $events = new \Elgg\EventsService($c->handlers); |
|
262 | + if ($c->config->enable_profiling) { |
|
263 | + $events->setTimer($c->timer); |
|
264 | + } |
|
265 | + return new \Elgg\PluginHooksService($events); |
|
266 | + }); |
|
267 | + |
|
268 | + $this->setFactory('iconService', function(ServiceProvider $c) { |
|
269 | + return new \Elgg\EntityIconService($c->config, $c->hooks, $c->request, $c->logger, $c->entityTable); |
|
270 | + }); |
|
271 | + |
|
272 | + $this->setClassName('input', \Elgg\Http\Input::class); |
|
273 | + |
|
274 | + $this->setFactory('imageService', function(ServiceProvider $c) { |
|
275 | + $imagine = new \Imagine\Gd\Imagine(); |
|
276 | + return new \Elgg\ImageService($imagine, $c->config); |
|
277 | + }); |
|
278 | + |
|
279 | + $this->setFactory('logger', function (ServiceProvider $c) { |
|
280 | + $logger = new \Elgg\Logger($c->hooks, $c->context); |
|
281 | + $logger->setLevel($c->config->debug); |
|
282 | + return $logger; |
|
283 | + }); |
|
284 | + |
|
285 | + // TODO(evan): Support configurable transports... |
|
286 | + $this->setClassName('mailer', 'Zend\Mail\Transport\Sendmail'); |
|
287 | + |
|
288 | + $this->setFactory('menus', function(ServiceProvider $c) { |
|
289 | + return new \Elgg\Menu\Service($c->hooks, $c->config); |
|
290 | + }); |
|
291 | + |
|
292 | + $this->setFactory('metadataCache', function (ServiceProvider $c) { |
|
293 | + $cache = _elgg_get_memcache('metadata'); |
|
294 | + return new \Elgg\Cache\MetadataCache($cache); |
|
295 | + }); |
|
296 | + |
|
297 | + $this->setFactory('memcacheStashPool', function(ServiceProvider $c) { |
|
298 | + if (!$c->config->memcache) { |
|
299 | + return null; |
|
300 | + } |
|
301 | + |
|
302 | + $servers = $c->config->memcache_servers; |
|
303 | + if (!$servers) { |
|
304 | + return null; |
|
305 | + } |
|
306 | + $driver = new \Stash\Driver\Memcache([ |
|
307 | + 'servers' => $servers, |
|
308 | + ]); |
|
309 | + return new \Stash\Pool($driver); |
|
310 | + }); |
|
311 | + |
|
312 | + $this->setFactory('metadataTable', function(ServiceProvider $c) { |
|
313 | + // TODO(ewinslow): Use Pool instead of MetadataCache for caching |
|
314 | + return new \Elgg\Database\MetadataTable( |
|
315 | + $c->metadataCache, $c->db, $c->entityTable, $c->hooks->getEvents(), $c->session); |
|
316 | + }); |
|
317 | + |
|
318 | + $this->setFactory('mutex', function(ServiceProvider $c) { |
|
319 | + return new \Elgg\Database\Mutex( |
|
320 | + $c->db, |
|
321 | + $c->logger |
|
322 | + ); |
|
323 | + }); |
|
324 | + |
|
325 | + $this->setFactory('notifications', function(ServiceProvider $c) { |
|
326 | + // @todo move queue in service provider |
|
327 | + $queue_name = \Elgg\Notifications\NotificationsService::QUEUE_NAME; |
|
328 | + $queue = new \Elgg\Queue\DatabaseQueue($queue_name, $c->db); |
|
329 | + $sub = new \Elgg\Notifications\SubscriptionsService($c->db); |
|
330 | + return new \Elgg\Notifications\NotificationsService($sub, $queue, $c->hooks, $c->session, $c->translator, $c->entityTable, $c->logger); |
|
331 | + }); |
|
332 | + |
|
333 | + $this->setClassName('nullCache', \Elgg\Cache\NullCache::class); |
|
334 | + |
|
335 | + $this->setFactory('persistentLogin', function(ServiceProvider $c) { |
|
336 | + $global_cookies_config = $c->config->getCookieConfig(); |
|
337 | + $cookie_config = $global_cookies_config['remember_me']; |
|
338 | + $cookie_name = $cookie_config['name']; |
|
339 | + $cookie_token = $c->request->cookies->get($cookie_name, ''); |
|
340 | + return new \Elgg\PersistentLoginService( |
|
341 | + $c->db, $c->session, $c->crypto, $cookie_config, $cookie_token); |
|
342 | + }); |
|
343 | + |
|
344 | + $this->setClassName('passwords', \Elgg\PasswordService::class); |
|
345 | + |
|
346 | + $this->setFactory('plugins', function(ServiceProvider $c) { |
|
347 | + $pool = new Pool\InMemory(); |
|
348 | + $plugins = new \Elgg\Database\Plugins($pool, $c->pluginSettingsCache); |
|
349 | + if ($c->config->enable_profiling) { |
|
350 | + $plugins->setTimer($c->timer); |
|
351 | + } |
|
352 | + return $plugins; |
|
353 | + }); |
|
354 | + |
|
355 | + $this->setClassName('pluginSettingsCache', \Elgg\Cache\PluginSettingsCache::class); |
|
356 | + |
|
357 | + $this->setFactory('privateSettings', function(ServiceProvider $c) { |
|
358 | + return new \Elgg\Database\PrivateSettingsTable($c->db, $c->entityTable, $c->pluginSettingsCache); |
|
359 | + }); |
|
360 | + |
|
361 | + $this->setFactory('publicDb', function(ServiceProvider $c) { |
|
362 | + return new \Elgg\Application\Database($c->db); |
|
363 | + }); |
|
364 | + |
|
365 | + $this->setFactory('queryCounter', function(ServiceProvider $c) { |
|
366 | + return new \Elgg\Database\QueryCounter($c->db); |
|
367 | + }, false); |
|
368 | + |
|
369 | + $this->setFactory('redirects', function(ServiceProvider $c) { |
|
370 | + $url = current_page_url(); |
|
371 | + $is_xhr = $c->request->isXmlHttpRequest(); |
|
372 | + return new \Elgg\RedirectService($c->session, $is_xhr, $c->config->wwwroot, $url); |
|
373 | + }); |
|
374 | + |
|
375 | + $this->setFactory('relationshipsTable', function(ServiceProvider $c) { |
|
376 | + return new \Elgg\Database\RelationshipsTable($c->db, $c->entityTable, $c->metadataTable, $c->hooks->getEvents()); |
|
377 | + }); |
|
378 | + |
|
379 | + $this->setFactory('request', [\Elgg\Http\Request::class, 'createFromGlobals']); |
|
380 | + |
|
381 | + $this->setFactory('responseFactory', function(ServiceProvider $c) { |
|
382 | + if (PHP_SAPI === 'cli') { |
|
383 | + $transport = new \Elgg\Http\OutputBufferTransport(); |
|
384 | + } else { |
|
385 | + $transport = new \Elgg\Http\HttpProtocolTransport(); |
|
386 | + } |
|
387 | + return new \Elgg\Http\ResponseFactory($c->request, $c->hooks, $c->ajax, $transport); |
|
388 | + }); |
|
389 | + |
|
390 | + $this->setFactory('router', function(ServiceProvider $c) { |
|
391 | + // TODO(evan): Init routes from plugins or cache |
|
392 | + $router = new \Elgg\Router($c->hooks); |
|
393 | + if ($c->config->enable_profiling) { |
|
394 | + $router->setTimer($c->timer); |
|
395 | + } |
|
396 | + return $router; |
|
397 | + }); |
|
398 | + |
|
399 | + $this->setFactory('seeder', function(ServiceProvider $c) { |
|
400 | + return new \Elgg\Database\Seeder($c->hooks); |
|
401 | + }); |
|
402 | + |
|
403 | + $this->setFactory('serveFileHandler', function(ServiceProvider $c) { |
|
404 | + return new \Elgg\Application\ServeFileHandler($c->hmac, $c->config); |
|
405 | + }); |
|
406 | + |
|
407 | + $this->setFactory('session', function(ServiceProvider $c) { |
|
408 | + return \ElggSession::fromDatabase($c->config, $c->db); |
|
409 | + }); |
|
410 | + |
|
411 | + $this->setClassName('urlSigner', \Elgg\Security\UrlSigner::class); |
|
412 | + |
|
413 | + $this->setFactory('simpleCache', function(ServiceProvider $c) { |
|
414 | + return new \Elgg\Cache\SimpleCache($c->config); |
|
415 | + }); |
|
416 | + |
|
417 | + /** |
|
418 | + * If the key is in the settings file, this is injected early. |
|
419 | + * |
|
420 | + * @see \Elgg\Application::initConfig |
|
421 | + */ |
|
422 | + $this->setFactory('siteSecret', function(ServiceProvider $c) { |
|
423 | + return \Elgg\Database\SiteSecret::fromDatabase($c->configTable); |
|
424 | + }); |
|
425 | + |
|
426 | + $this->setClassName('stickyForms', \Elgg\Forms\StickyForms::class); |
|
427 | + |
|
428 | + $this->setFactory('subtypeTable', function(ServiceProvider $c) { |
|
429 | + return new \Elgg\Database\SubtypeTable($c->db); |
|
430 | + }); |
|
431 | + |
|
432 | + $this->setFactory('systemCache', function (ServiceProvider $c) { |
|
433 | + $cache = new \Elgg\Cache\SystemCache($c->fileCache, $c->config); |
|
434 | + if ($c->config->enable_profiling) { |
|
435 | + $cache->setTimer($c->timer); |
|
436 | + } |
|
437 | + return $cache; |
|
438 | + }); |
|
439 | + |
|
440 | + $this->setFactory('systemMessages', function(ServiceProvider $c) { |
|
441 | + return new \Elgg\SystemMessagesService($c->session); |
|
442 | + }); |
|
443 | + |
|
444 | + $this->setClassName('table_columns', \Elgg\Views\TableColumn\ColumnFactory::class); |
|
445 | + |
|
446 | + $this->setClassName('timer', \Elgg\Timer::class); |
|
447 | + |
|
448 | + $this->setFactory('translator', function(ServiceProvider $c) { |
|
449 | + return new \Elgg\I18n\Translator($c->config); |
|
450 | + }); |
|
451 | + |
|
452 | + $this->setFactory('uploads', function(ServiceProvider $c) { |
|
453 | + return new \Elgg\UploadService($c->request); |
|
454 | + }); |
|
455 | + |
|
456 | + $this->setFactory('upgrades', function(ServiceProvider $c) { |
|
457 | + return new \Elgg\UpgradeService( |
|
458 | + $c->translator, |
|
459 | + $c->hooks, |
|
460 | + $c->config, |
|
461 | + $c->logger, |
|
462 | + $c->mutex |
|
463 | + ); |
|
464 | + }); |
|
465 | + |
|
466 | + $this->setFactory('userCapabilities', function(ServiceProvider $c) { |
|
467 | + return new \Elgg\UserCapabilities($c->hooks, $c->entityTable, $c->session); |
|
468 | + }); |
|
469 | + |
|
470 | + $this->setFactory('usersTable', function(ServiceProvider $c) { |
|
471 | + return new \Elgg\Database\UsersTable( |
|
472 | + $c->config, |
|
473 | + $c->db, |
|
474 | + $c->entityTable, |
|
475 | + $c->entityCache, |
|
476 | + $c->hooks->getEvents() |
|
477 | + ); |
|
478 | + }); |
|
479 | + |
|
480 | + $this->setFactory('upgradeLocator', function(ServiceProvider $c) { |
|
481 | + return new \Elgg\Upgrade\Locator( |
|
482 | + $c->plugins, |
|
483 | + $c->logger, |
|
484 | + $c->privateSettings |
|
485 | + ); |
|
486 | + }); |
|
487 | + |
|
488 | + $this->setFactory('views', function(ServiceProvider $c) { |
|
489 | + return new \Elgg\ViewsService($c->hooks, $c->logger, $c->input); |
|
490 | + }); |
|
491 | + |
|
492 | + $this->setFactory('viewCacher', function(ServiceProvider $c) { |
|
493 | + return new \Elgg\Cache\ViewCacher($c->views, $c->config); |
|
494 | + }); |
|
495 | + |
|
496 | + $this->setClassName('widgets', \Elgg\WidgetsService::class); |
|
497 | + } |
|
498 | 498 | } |
@@ -17,713 +17,713 @@ discard block |
||
17 | 17 | * @since 1.10.0 |
18 | 18 | */ |
19 | 19 | class Plugins { |
20 | - use Profilable; |
|
20 | + use Profilable; |
|
21 | 21 | |
22 | - /** |
|
23 | - * @var \ElggPlugin[] |
|
24 | - */ |
|
25 | - private $boot_plugins = []; |
|
22 | + /** |
|
23 | + * @var \ElggPlugin[] |
|
24 | + */ |
|
25 | + private $boot_plugins = []; |
|
26 | 26 | |
27 | - /** |
|
28 | - * @var array|null |
|
29 | - */ |
|
30 | - private $provides_cache; |
|
27 | + /** |
|
28 | + * @var array|null |
|
29 | + */ |
|
30 | + private $provides_cache; |
|
31 | 31 | |
32 | - /** |
|
33 | - * @var string[] Active plugins, with plugin ID => GUID. Missing keys imply inactive plugins. |
|
34 | - */ |
|
35 | - private $active_guids = []; |
|
32 | + /** |
|
33 | + * @var string[] Active plugins, with plugin ID => GUID. Missing keys imply inactive plugins. |
|
34 | + */ |
|
35 | + private $active_guids = []; |
|
36 | 36 | |
37 | - /** |
|
38 | - * @var bool Has $active_guids been populated? |
|
39 | - */ |
|
40 | - private $active_guids_known = false; |
|
37 | + /** |
|
38 | + * @var bool Has $active_guids been populated? |
|
39 | + */ |
|
40 | + private $active_guids_known = false; |
|
41 | 41 | |
42 | - /** |
|
43 | - * @var Pool |
|
44 | - */ |
|
45 | - private $plugins_by_id; |
|
42 | + /** |
|
43 | + * @var Pool |
|
44 | + */ |
|
45 | + private $plugins_by_id; |
|
46 | 46 | |
47 | - /** |
|
48 | - * @var PluginSettingsCache |
|
49 | - */ |
|
50 | - private $settings_cache; |
|
47 | + /** |
|
48 | + * @var PluginSettingsCache |
|
49 | + */ |
|
50 | + private $settings_cache; |
|
51 | 51 | |
52 | - /** |
|
53 | - * Constructor |
|
54 | - * |
|
55 | - * @param Pool $pool Cache for referencing plugins by ID |
|
56 | - * @param PluginSettingsCache $cache Plugin settings cache |
|
57 | - */ |
|
58 | - public function __construct(Pool $pool, PluginSettingsCache $cache) { |
|
59 | - $this->plugins_by_id = $pool; |
|
60 | - $this->settings_cache = $cache; |
|
61 | - } |
|
52 | + /** |
|
53 | + * Constructor |
|
54 | + * |
|
55 | + * @param Pool $pool Cache for referencing plugins by ID |
|
56 | + * @param PluginSettingsCache $cache Plugin settings cache |
|
57 | + */ |
|
58 | + public function __construct(Pool $pool, PluginSettingsCache $cache) { |
|
59 | + $this->plugins_by_id = $pool; |
|
60 | + $this->settings_cache = $cache; |
|
61 | + } |
|
62 | 62 | |
63 | - /** |
|
64 | - * Set the list of active plugins according to the boot data cache |
|
65 | - * |
|
66 | - * @param \ElggPlugin[] $plugins Set of active plugins |
|
67 | - * @return void |
|
68 | - */ |
|
69 | - public function setBootPlugins(array $plugins) { |
|
70 | - $this->boot_plugins = $plugins; |
|
71 | - foreach ($plugins as $plugin) { |
|
72 | - $this->plugins_by_id->put($plugin->getID(), $plugin); |
|
73 | - } |
|
74 | - } |
|
63 | + /** |
|
64 | + * Set the list of active plugins according to the boot data cache |
|
65 | + * |
|
66 | + * @param \ElggPlugin[] $plugins Set of active plugins |
|
67 | + * @return void |
|
68 | + */ |
|
69 | + public function setBootPlugins(array $plugins) { |
|
70 | + $this->boot_plugins = $plugins; |
|
71 | + foreach ($plugins as $plugin) { |
|
72 | + $this->plugins_by_id->put($plugin->getID(), $plugin); |
|
73 | + } |
|
74 | + } |
|
75 | 75 | |
76 | - /** |
|
77 | - * Returns a list of plugin directory names from a base directory. |
|
78 | - * |
|
79 | - * @param string $dir A dir to scan for plugins. Defaults to config's plugins_path. |
|
80 | - * Must have a trailing slash. |
|
81 | - * |
|
82 | - * @return array Array of directory names (not full paths) |
|
83 | - * @access private |
|
84 | - */ |
|
85 | - function getDirsInDir($dir = null) { |
|
86 | - if (!$dir) { |
|
87 | - $dir = elgg_get_plugins_path(); |
|
88 | - } |
|
89 | - |
|
90 | - $plugin_dirs = []; |
|
91 | - $handle = opendir($dir); |
|
92 | - |
|
93 | - if ($handle) { |
|
94 | - while ($plugin_dir = readdir($handle)) { |
|
95 | - // must be directory and not begin with a . |
|
96 | - if (substr($plugin_dir, 0, 1) !== '.' && is_dir($dir . $plugin_dir)) { |
|
97 | - $plugin_dirs[] = $plugin_dir; |
|
98 | - } |
|
99 | - } |
|
100 | - } |
|
101 | - |
|
102 | - sort($plugin_dirs); |
|
103 | - |
|
104 | - return $plugin_dirs; |
|
105 | - } |
|
106 | - |
|
107 | - /** |
|
108 | - * Discovers plugins in the plugins_path setting and creates \ElggPlugin |
|
109 | - * entities for them if they don't exist. If there are plugins with entities |
|
110 | - * but not actual files, will disable the \ElggPlugin entities and mark as inactive. |
|
111 | - * The \ElggPlugin object holds config data, so don't delete. |
|
112 | - * |
|
113 | - * @return bool |
|
114 | - * @access private |
|
115 | - */ |
|
116 | - function generateEntities() { |
|
117 | - |
|
118 | - $mod_dir = elgg_get_plugins_path(); |
|
119 | - $db_prefix = _elgg_config()->dbprefix; |
|
120 | - |
|
121 | - // ignore access in case this is called with no admin logged in - needed for creating plugins perhaps? |
|
122 | - $old_ia = elgg_set_ignore_access(true); |
|
123 | - |
|
124 | - // show hidden entities so that we can enable them if appropriate |
|
125 | - $old_access = access_show_hidden_entities(true); |
|
126 | - |
|
127 | - $known_plugins = elgg_get_entities_from_relationship([ |
|
128 | - 'type' => 'object', |
|
129 | - 'subtype' => 'plugin', |
|
130 | - 'selects' => ['plugin_oe.*'], |
|
131 | - 'joins' => ["JOIN {$db_prefix}objects_entity plugin_oe on plugin_oe.guid = e.guid"], |
|
132 | - 'limit' => ELGG_ENTITIES_NO_VALUE, |
|
133 | - ]); |
|
134 | - /* @var \ElggPlugin[] $known_plugins */ |
|
135 | - |
|
136 | - if (!$known_plugins) { |
|
137 | - $known_plugins = []; |
|
138 | - } |
|
139 | - |
|
140 | - // map paths to indexes |
|
141 | - $id_map = []; |
|
142 | - foreach ($known_plugins as $i => $plugin) { |
|
143 | - // if the ID is wrong, delete the plugin because we can never load it. |
|
144 | - $id = $plugin->getID(); |
|
145 | - if (!$id) { |
|
146 | - $plugin->delete(); |
|
147 | - unset($known_plugins[$i]); |
|
148 | - continue; |
|
149 | - } |
|
150 | - $id_map[$plugin->getID()] = $i; |
|
151 | - } |
|
152 | - |
|
153 | - $physical_plugins = $this->getDirsInDir($mod_dir); |
|
154 | - if (!$physical_plugins) { |
|
155 | - elgg_set_ignore_access($old_ia); |
|
156 | - return false; |
|
157 | - } |
|
158 | - |
|
159 | - // check real plugins against known ones |
|
160 | - foreach ($physical_plugins as $plugin_id) { |
|
161 | - // is this already in the db? |
|
162 | - if (array_key_exists($plugin_id, $id_map)) { |
|
163 | - $index = $id_map[$plugin_id]; |
|
164 | - $plugin = $known_plugins[$index]; |
|
165 | - // was this plugin deleted and its entity disabled? |
|
166 | - if (!$plugin->isEnabled()) { |
|
167 | - $plugin->enable(); |
|
168 | - $plugin->deactivate(); |
|
169 | - $plugin->setPriority('last'); |
|
170 | - } |
|
171 | - |
|
172 | - // remove from the list of plugins to disable |
|
173 | - unset($known_plugins[$index]); |
|
174 | - } else { |
|
175 | - // create new plugin |
|
176 | - // priority is forced to last in save() if not set. |
|
177 | - $plugin = new \ElggPlugin($mod_dir . $plugin_id); |
|
178 | - $plugin->save(); |
|
179 | - } |
|
180 | - } |
|
181 | - |
|
182 | - // everything remaining in $known_plugins needs to be disabled |
|
183 | - // because they are entities, but their dirs were removed. |
|
184 | - // don't delete the entities because they hold settings. |
|
185 | - foreach ($known_plugins as $plugin) { |
|
186 | - if ($plugin->isActive()) { |
|
187 | - $plugin->deactivate(); |
|
188 | - } |
|
189 | - // remove the priority. |
|
190 | - $name = $this->namespacePrivateSetting('internal', 'priority'); |
|
191 | - remove_private_setting($plugin->guid, $name); |
|
192 | - if ($plugin->isEnabled()) { |
|
193 | - $plugin->disable(); |
|
194 | - } |
|
195 | - } |
|
196 | - |
|
197 | - access_show_hidden_entities($old_access); |
|
198 | - elgg_set_ignore_access($old_ia); |
|
199 | - |
|
200 | - return true; |
|
201 | - } |
|
202 | - |
|
203 | - /** |
|
204 | - * Cache a reference to this plugin by its ID |
|
205 | - * |
|
206 | - * @param \ElggPlugin $plugin |
|
207 | - * |
|
208 | - * @access private |
|
209 | - */ |
|
210 | - function cache(\ElggPlugin $plugin) { |
|
211 | - $this->plugins_by_id->put($plugin->getID(), $plugin); |
|
212 | - } |
|
213 | - |
|
214 | - /** |
|
215 | - * Returns an \ElggPlugin object with the path $path. |
|
216 | - * |
|
217 | - * @param string $plugin_id The id (dir name) of the plugin. NOT the guid. |
|
218 | - * @return \ElggPlugin|null |
|
219 | - */ |
|
220 | - function get($plugin_id) { |
|
221 | - return $this->plugins_by_id->get($plugin_id, function () use ($plugin_id) { |
|
222 | - $plugin_id = sanitize_string($plugin_id); |
|
223 | - $db_prefix = _elgg_config()->dbprefix; |
|
76 | + /** |
|
77 | + * Returns a list of plugin directory names from a base directory. |
|
78 | + * |
|
79 | + * @param string $dir A dir to scan for plugins. Defaults to config's plugins_path. |
|
80 | + * Must have a trailing slash. |
|
81 | + * |
|
82 | + * @return array Array of directory names (not full paths) |
|
83 | + * @access private |
|
84 | + */ |
|
85 | + function getDirsInDir($dir = null) { |
|
86 | + if (!$dir) { |
|
87 | + $dir = elgg_get_plugins_path(); |
|
88 | + } |
|
89 | + |
|
90 | + $plugin_dirs = []; |
|
91 | + $handle = opendir($dir); |
|
92 | + |
|
93 | + if ($handle) { |
|
94 | + while ($plugin_dir = readdir($handle)) { |
|
95 | + // must be directory and not begin with a . |
|
96 | + if (substr($plugin_dir, 0, 1) !== '.' && is_dir($dir . $plugin_dir)) { |
|
97 | + $plugin_dirs[] = $plugin_dir; |
|
98 | + } |
|
99 | + } |
|
100 | + } |
|
101 | + |
|
102 | + sort($plugin_dirs); |
|
103 | + |
|
104 | + return $plugin_dirs; |
|
105 | + } |
|
106 | + |
|
107 | + /** |
|
108 | + * Discovers plugins in the plugins_path setting and creates \ElggPlugin |
|
109 | + * entities for them if they don't exist. If there are plugins with entities |
|
110 | + * but not actual files, will disable the \ElggPlugin entities and mark as inactive. |
|
111 | + * The \ElggPlugin object holds config data, so don't delete. |
|
112 | + * |
|
113 | + * @return bool |
|
114 | + * @access private |
|
115 | + */ |
|
116 | + function generateEntities() { |
|
117 | + |
|
118 | + $mod_dir = elgg_get_plugins_path(); |
|
119 | + $db_prefix = _elgg_config()->dbprefix; |
|
120 | + |
|
121 | + // ignore access in case this is called with no admin logged in - needed for creating plugins perhaps? |
|
122 | + $old_ia = elgg_set_ignore_access(true); |
|
123 | + |
|
124 | + // show hidden entities so that we can enable them if appropriate |
|
125 | + $old_access = access_show_hidden_entities(true); |
|
126 | + |
|
127 | + $known_plugins = elgg_get_entities_from_relationship([ |
|
128 | + 'type' => 'object', |
|
129 | + 'subtype' => 'plugin', |
|
130 | + 'selects' => ['plugin_oe.*'], |
|
131 | + 'joins' => ["JOIN {$db_prefix}objects_entity plugin_oe on plugin_oe.guid = e.guid"], |
|
132 | + 'limit' => ELGG_ENTITIES_NO_VALUE, |
|
133 | + ]); |
|
134 | + /* @var \ElggPlugin[] $known_plugins */ |
|
135 | + |
|
136 | + if (!$known_plugins) { |
|
137 | + $known_plugins = []; |
|
138 | + } |
|
139 | + |
|
140 | + // map paths to indexes |
|
141 | + $id_map = []; |
|
142 | + foreach ($known_plugins as $i => $plugin) { |
|
143 | + // if the ID is wrong, delete the plugin because we can never load it. |
|
144 | + $id = $plugin->getID(); |
|
145 | + if (!$id) { |
|
146 | + $plugin->delete(); |
|
147 | + unset($known_plugins[$i]); |
|
148 | + continue; |
|
149 | + } |
|
150 | + $id_map[$plugin->getID()] = $i; |
|
151 | + } |
|
152 | + |
|
153 | + $physical_plugins = $this->getDirsInDir($mod_dir); |
|
154 | + if (!$physical_plugins) { |
|
155 | + elgg_set_ignore_access($old_ia); |
|
156 | + return false; |
|
157 | + } |
|
158 | + |
|
159 | + // check real plugins against known ones |
|
160 | + foreach ($physical_plugins as $plugin_id) { |
|
161 | + // is this already in the db? |
|
162 | + if (array_key_exists($plugin_id, $id_map)) { |
|
163 | + $index = $id_map[$plugin_id]; |
|
164 | + $plugin = $known_plugins[$index]; |
|
165 | + // was this plugin deleted and its entity disabled? |
|
166 | + if (!$plugin->isEnabled()) { |
|
167 | + $plugin->enable(); |
|
168 | + $plugin->deactivate(); |
|
169 | + $plugin->setPriority('last'); |
|
170 | + } |
|
171 | + |
|
172 | + // remove from the list of plugins to disable |
|
173 | + unset($known_plugins[$index]); |
|
174 | + } else { |
|
175 | + // create new plugin |
|
176 | + // priority is forced to last in save() if not set. |
|
177 | + $plugin = new \ElggPlugin($mod_dir . $plugin_id); |
|
178 | + $plugin->save(); |
|
179 | + } |
|
180 | + } |
|
181 | + |
|
182 | + // everything remaining in $known_plugins needs to be disabled |
|
183 | + // because they are entities, but their dirs were removed. |
|
184 | + // don't delete the entities because they hold settings. |
|
185 | + foreach ($known_plugins as $plugin) { |
|
186 | + if ($plugin->isActive()) { |
|
187 | + $plugin->deactivate(); |
|
188 | + } |
|
189 | + // remove the priority. |
|
190 | + $name = $this->namespacePrivateSetting('internal', 'priority'); |
|
191 | + remove_private_setting($plugin->guid, $name); |
|
192 | + if ($plugin->isEnabled()) { |
|
193 | + $plugin->disable(); |
|
194 | + } |
|
195 | + } |
|
196 | + |
|
197 | + access_show_hidden_entities($old_access); |
|
198 | + elgg_set_ignore_access($old_ia); |
|
199 | + |
|
200 | + return true; |
|
201 | + } |
|
202 | + |
|
203 | + /** |
|
204 | + * Cache a reference to this plugin by its ID |
|
205 | + * |
|
206 | + * @param \ElggPlugin $plugin |
|
207 | + * |
|
208 | + * @access private |
|
209 | + */ |
|
210 | + function cache(\ElggPlugin $plugin) { |
|
211 | + $this->plugins_by_id->put($plugin->getID(), $plugin); |
|
212 | + } |
|
213 | + |
|
214 | + /** |
|
215 | + * Returns an \ElggPlugin object with the path $path. |
|
216 | + * |
|
217 | + * @param string $plugin_id The id (dir name) of the plugin. NOT the guid. |
|
218 | + * @return \ElggPlugin|null |
|
219 | + */ |
|
220 | + function get($plugin_id) { |
|
221 | + return $this->plugins_by_id->get($plugin_id, function () use ($plugin_id) { |
|
222 | + $plugin_id = sanitize_string($plugin_id); |
|
223 | + $db_prefix = _elgg_config()->dbprefix; |
|
224 | 224 | |
225 | - $options = [ |
|
226 | - 'type' => 'object', |
|
227 | - 'subtype' => 'plugin', |
|
228 | - 'joins' => ["JOIN {$db_prefix}objects_entity oe on oe.guid = e.guid"], |
|
229 | - 'selects' => ["oe.title", "oe.description"], |
|
230 | - 'wheres' => ["oe.title = '$plugin_id'"], |
|
231 | - 'limit' => 1, |
|
232 | - 'distinct' => false, |
|
233 | - ]; |
|
225 | + $options = [ |
|
226 | + 'type' => 'object', |
|
227 | + 'subtype' => 'plugin', |
|
228 | + 'joins' => ["JOIN {$db_prefix}objects_entity oe on oe.guid = e.guid"], |
|
229 | + 'selects' => ["oe.title", "oe.description"], |
|
230 | + 'wheres' => ["oe.title = '$plugin_id'"], |
|
231 | + 'limit' => 1, |
|
232 | + 'distinct' => false, |
|
233 | + ]; |
|
234 | 234 | |
235 | - $plugins = elgg_get_entities($options); |
|
235 | + $plugins = elgg_get_entities($options); |
|
236 | 236 | |
237 | - if ($plugins) { |
|
238 | - return $plugins[0]; |
|
239 | - } |
|
237 | + if ($plugins) { |
|
238 | + return $plugins[0]; |
|
239 | + } |
|
240 | 240 | |
241 | - return null; |
|
242 | - }); |
|
243 | - } |
|
244 | - |
|
245 | - /** |
|
246 | - * Returns if a plugin exists in the system. |
|
247 | - * |
|
248 | - * @warning This checks only plugins that are registered in the system! |
|
249 | - * If the plugin cache is outdated, be sure to regenerate it with |
|
250 | - * {@link _elgg_generate_plugin_objects()} first. |
|
251 | - * |
|
252 | - * @param string $id The plugin ID. |
|
253 | - * @return bool |
|
254 | - */ |
|
255 | - function exists($id) { |
|
256 | - return (bool) $this->get($id); |
|
257 | - } |
|
258 | - |
|
259 | - /** |
|
260 | - * Returns the highest priority of the plugins |
|
261 | - * |
|
262 | - * @return int |
|
263 | - * @access private |
|
264 | - */ |
|
265 | - function getMaxPriority() { |
|
266 | - $db_prefix = _elgg_config()->dbprefix; |
|
267 | - $priority = $this->namespacePrivateSetting('internal', 'priority'); |
|
268 | - $plugin_subtype = get_subtype_id('object', 'plugin'); |
|
269 | - |
|
270 | - $q = "SELECT MAX(CAST(ps.value AS unsigned)) as max |
|
241 | + return null; |
|
242 | + }); |
|
243 | + } |
|
244 | + |
|
245 | + /** |
|
246 | + * Returns if a plugin exists in the system. |
|
247 | + * |
|
248 | + * @warning This checks only plugins that are registered in the system! |
|
249 | + * If the plugin cache is outdated, be sure to regenerate it with |
|
250 | + * {@link _elgg_generate_plugin_objects()} first. |
|
251 | + * |
|
252 | + * @param string $id The plugin ID. |
|
253 | + * @return bool |
|
254 | + */ |
|
255 | + function exists($id) { |
|
256 | + return (bool) $this->get($id); |
|
257 | + } |
|
258 | + |
|
259 | + /** |
|
260 | + * Returns the highest priority of the plugins |
|
261 | + * |
|
262 | + * @return int |
|
263 | + * @access private |
|
264 | + */ |
|
265 | + function getMaxPriority() { |
|
266 | + $db_prefix = _elgg_config()->dbprefix; |
|
267 | + $priority = $this->namespacePrivateSetting('internal', 'priority'); |
|
268 | + $plugin_subtype = get_subtype_id('object', 'plugin'); |
|
269 | + |
|
270 | + $q = "SELECT MAX(CAST(ps.value AS unsigned)) as max |
|
271 | 271 | FROM {$db_prefix}entities e, {$db_prefix}private_settings ps |
272 | 272 | WHERE ps.name = '$priority' |
273 | 273 | AND ps.entity_guid = e.guid |
274 | 274 | AND e.type = 'object' and e.subtype = $plugin_subtype"; |
275 | 275 | |
276 | - $data = get_data($q); |
|
277 | - if ($data) { |
|
278 | - $max = $data[0]->max; |
|
279 | - } else { |
|
280 | - $max = 1; |
|
281 | - } |
|
282 | - |
|
283 | - // can't have a priority of 0. |
|
284 | - return ($max) ? $max : 1; |
|
285 | - } |
|
286 | - |
|
287 | - /** |
|
288 | - * Returns if a plugin is active for a current site. |
|
289 | - * |
|
290 | - * @param string $plugin_id The plugin ID |
|
291 | - * @return bool |
|
292 | - */ |
|
293 | - function isActive($plugin_id) { |
|
294 | - if ($this->active_guids_known) { |
|
295 | - return isset($this->active_guids[$plugin_id]); |
|
296 | - } |
|
276 | + $data = get_data($q); |
|
277 | + if ($data) { |
|
278 | + $max = $data[0]->max; |
|
279 | + } else { |
|
280 | + $max = 1; |
|
281 | + } |
|
282 | + |
|
283 | + // can't have a priority of 0. |
|
284 | + return ($max) ? $max : 1; |
|
285 | + } |
|
286 | + |
|
287 | + /** |
|
288 | + * Returns if a plugin is active for a current site. |
|
289 | + * |
|
290 | + * @param string $plugin_id The plugin ID |
|
291 | + * @return bool |
|
292 | + */ |
|
293 | + function isActive($plugin_id) { |
|
294 | + if ($this->active_guids_known) { |
|
295 | + return isset($this->active_guids[$plugin_id]); |
|
296 | + } |
|
297 | 297 | |
298 | - $site = elgg_get_site_entity(); |
|
299 | - |
|
300 | - if (!($site instanceof \ElggSite)) { |
|
301 | - return false; |
|
302 | - } |
|
303 | - |
|
304 | - $plugin = $this->get($plugin_id); |
|
305 | - |
|
306 | - if (!$plugin) { |
|
307 | - return false; |
|
308 | - } |
|
309 | - |
|
310 | - return $plugin->isActive($site->guid); |
|
311 | - } |
|
312 | - |
|
313 | - /** |
|
314 | - * Loads all active plugins in the order specified in the tool admin panel. |
|
315 | - * |
|
316 | - * @note This is called on every page load. If a plugin is active and problematic, it |
|
317 | - * will be disabled and a visible error emitted. This does not check the deps system because |
|
318 | - * that was too slow. |
|
319 | - * |
|
320 | - * @return bool |
|
321 | - * @access private |
|
322 | - */ |
|
323 | - function load() { |
|
324 | - if ($this->timer) { |
|
325 | - $this->timer->begin([__METHOD__]); |
|
326 | - } |
|
298 | + $site = elgg_get_site_entity(); |
|
299 | + |
|
300 | + if (!($site instanceof \ElggSite)) { |
|
301 | + return false; |
|
302 | + } |
|
303 | + |
|
304 | + $plugin = $this->get($plugin_id); |
|
305 | + |
|
306 | + if (!$plugin) { |
|
307 | + return false; |
|
308 | + } |
|
309 | + |
|
310 | + return $plugin->isActive($site->guid); |
|
311 | + } |
|
312 | + |
|
313 | + /** |
|
314 | + * Loads all active plugins in the order specified in the tool admin panel. |
|
315 | + * |
|
316 | + * @note This is called on every page load. If a plugin is active and problematic, it |
|
317 | + * will be disabled and a visible error emitted. This does not check the deps system because |
|
318 | + * that was too slow. |
|
319 | + * |
|
320 | + * @return bool |
|
321 | + * @access private |
|
322 | + */ |
|
323 | + function load() { |
|
324 | + if ($this->timer) { |
|
325 | + $this->timer->begin([__METHOD__]); |
|
326 | + } |
|
327 | 327 | |
328 | - $plugins_path = elgg_get_plugins_path(); |
|
329 | - $start_flags = ELGG_PLUGIN_INCLUDE_START | |
|
330 | - ELGG_PLUGIN_REGISTER_VIEWS | |
|
331 | - ELGG_PLUGIN_REGISTER_ACTIONS | |
|
332 | - ELGG_PLUGIN_REGISTER_LANGUAGES | |
|
333 | - ELGG_PLUGIN_REGISTER_WIDGETS | |
|
334 | - ELGG_PLUGIN_REGISTER_CLASSES; |
|
335 | - |
|
336 | - if (!$plugins_path) { |
|
337 | - return false; |
|
338 | - } |
|
339 | - |
|
340 | - // temporary disable all plugins if there is a file called 'disabled' in the plugin dir |
|
341 | - if (file_exists("$plugins_path/disabled")) { |
|
342 | - if (elgg_is_admin_logged_in() && elgg_in_context('admin')) { |
|
343 | - system_message(_elgg_services()->translator->translate('plugins:disabled')); |
|
344 | - } |
|
345 | - return false; |
|
346 | - } |
|
328 | + $plugins_path = elgg_get_plugins_path(); |
|
329 | + $start_flags = ELGG_PLUGIN_INCLUDE_START | |
|
330 | + ELGG_PLUGIN_REGISTER_VIEWS | |
|
331 | + ELGG_PLUGIN_REGISTER_ACTIONS | |
|
332 | + ELGG_PLUGIN_REGISTER_LANGUAGES | |
|
333 | + ELGG_PLUGIN_REGISTER_WIDGETS | |
|
334 | + ELGG_PLUGIN_REGISTER_CLASSES; |
|
335 | + |
|
336 | + if (!$plugins_path) { |
|
337 | + return false; |
|
338 | + } |
|
339 | + |
|
340 | + // temporary disable all plugins if there is a file called 'disabled' in the plugin dir |
|
341 | + if (file_exists("$plugins_path/disabled")) { |
|
342 | + if (elgg_is_admin_logged_in() && elgg_in_context('admin')) { |
|
343 | + system_message(_elgg_services()->translator->translate('plugins:disabled')); |
|
344 | + } |
|
345 | + return false; |
|
346 | + } |
|
347 | 347 | |
348 | - $config = _elgg_config(); |
|
348 | + $config = _elgg_config(); |
|
349 | 349 | |
350 | - if ($config->system_cache_loaded) { |
|
351 | - $start_flags = $start_flags & ~ELGG_PLUGIN_REGISTER_VIEWS; |
|
352 | - } |
|
350 | + if ($config->system_cache_loaded) { |
|
351 | + $start_flags = $start_flags & ~ELGG_PLUGIN_REGISTER_VIEWS; |
|
352 | + } |
|
353 | 353 | |
354 | - if (_elgg_services()->translator->wasLoadedFromCache()) { |
|
355 | - $start_flags = $start_flags & ~ELGG_PLUGIN_REGISTER_LANGUAGES; |
|
356 | - } |
|
354 | + if (_elgg_services()->translator->wasLoadedFromCache()) { |
|
355 | + $start_flags = $start_flags & ~ELGG_PLUGIN_REGISTER_LANGUAGES; |
|
356 | + } |
|
357 | 357 | |
358 | - $plugins = $this->boot_plugins; |
|
359 | - if (!$plugins) { |
|
360 | - $this->active_guids_known = true; |
|
361 | - return true; |
|
362 | - } |
|
358 | + $plugins = $this->boot_plugins; |
|
359 | + if (!$plugins) { |
|
360 | + $this->active_guids_known = true; |
|
361 | + return true; |
|
362 | + } |
|
363 | 363 | |
364 | - $return = true; |
|
365 | - foreach ($plugins as $plugin) { |
|
366 | - $id = $plugin->getID(); |
|
367 | - try { |
|
368 | - $plugin->start($start_flags); |
|
369 | - $this->active_guids[$id] = $plugin->guid; |
|
370 | - } catch (Exception $e) { |
|
371 | - $disable_plugins = _elgg_config()->auto_disable_plugins; |
|
372 | - if ($disable_plugins === null) { |
|
373 | - $disable_plugins = true; |
|
374 | - } |
|
375 | - if ($disable_plugins) { |
|
376 | - $plugin->deactivate(); |
|
364 | + $return = true; |
|
365 | + foreach ($plugins as $plugin) { |
|
366 | + $id = $plugin->getID(); |
|
367 | + try { |
|
368 | + $plugin->start($start_flags); |
|
369 | + $this->active_guids[$id] = $plugin->guid; |
|
370 | + } catch (Exception $e) { |
|
371 | + $disable_plugins = _elgg_config()->auto_disable_plugins; |
|
372 | + if ($disable_plugins === null) { |
|
373 | + $disable_plugins = true; |
|
374 | + } |
|
375 | + if ($disable_plugins) { |
|
376 | + $plugin->deactivate(); |
|
377 | 377 | |
378 | - $msg = _elgg_services()->translator->translate('PluginException:CannotStart', |
|
379 | - [$id, $plugin->guid, $e->getMessage()]); |
|
380 | - elgg_add_admin_notice("cannot_start $id", $msg); |
|
381 | - $return = false; |
|
382 | - } |
|
383 | - } |
|
384 | - } |
|
378 | + $msg = _elgg_services()->translator->translate('PluginException:CannotStart', |
|
379 | + [$id, $plugin->guid, $e->getMessage()]); |
|
380 | + elgg_add_admin_notice("cannot_start $id", $msg); |
|
381 | + $return = false; |
|
382 | + } |
|
383 | + } |
|
384 | + } |
|
385 | 385 | |
386 | - $this->active_guids_known = true; |
|
386 | + $this->active_guids_known = true; |
|
387 | 387 | |
388 | - if ($this->timer) { |
|
389 | - $this->timer->end([__METHOD__]); |
|
390 | - } |
|
391 | - return $return; |
|
392 | - } |
|
393 | - |
|
394 | - /** |
|
395 | - * Returns an ordered list of plugins |
|
396 | - * |
|
397 | - * @param string $status The status of the plugins. active, inactive, or all. |
|
398 | - * @return \ElggPlugin[] |
|
399 | - */ |
|
400 | - function find($status = 'active') { |
|
401 | - if (!_elgg_services()->db) { |
|
402 | - return []; |
|
403 | - } |
|
388 | + if ($this->timer) { |
|
389 | + $this->timer->end([__METHOD__]); |
|
390 | + } |
|
391 | + return $return; |
|
392 | + } |
|
393 | + |
|
394 | + /** |
|
395 | + * Returns an ordered list of plugins |
|
396 | + * |
|
397 | + * @param string $status The status of the plugins. active, inactive, or all. |
|
398 | + * @return \ElggPlugin[] |
|
399 | + */ |
|
400 | + function find($status = 'active') { |
|
401 | + if (!_elgg_services()->db) { |
|
402 | + return []; |
|
403 | + } |
|
404 | 404 | |
405 | - $db_prefix = _elgg_config()->dbprefix; |
|
406 | - $priority = $this->namespacePrivateSetting('internal', 'priority'); |
|
407 | - $site_guid = 1; |
|
405 | + $db_prefix = _elgg_config()->dbprefix; |
|
406 | + $priority = $this->namespacePrivateSetting('internal', 'priority'); |
|
407 | + $site_guid = 1; |
|
408 | 408 | |
409 | - // grab plugins |
|
410 | - $options = [ |
|
411 | - 'type' => 'object', |
|
412 | - 'subtype' => 'plugin', |
|
413 | - 'limit' => ELGG_ENTITIES_NO_VALUE, |
|
414 | - 'selects' => ['plugin_oe.*', 'ps.value'], |
|
415 | - 'joins' => [ |
|
416 | - "JOIN {$db_prefix}private_settings ps on ps.entity_guid = e.guid", |
|
417 | - "JOIN {$db_prefix}objects_entity plugin_oe on plugin_oe.guid = e.guid" |
|
418 | - ], |
|
419 | - 'wheres' => ["ps.name = '$priority'"], |
|
420 | - // ORDER BY CAST(ps.value) is super slow. We usort() below. |
|
421 | - 'order_by' => false, |
|
422 | - 'distinct' => false, |
|
423 | - ]; |
|
424 | - |
|
425 | - switch ($status) { |
|
426 | - case 'active': |
|
427 | - $options['relationship'] = 'active_plugin'; |
|
428 | - $options['relationship_guid'] = $site_guid; |
|
429 | - $options['inverse_relationship'] = true; |
|
430 | - break; |
|
431 | - |
|
432 | - case 'inactive': |
|
433 | - $options['wheres'][] = "NOT EXISTS ( |
|
409 | + // grab plugins |
|
410 | + $options = [ |
|
411 | + 'type' => 'object', |
|
412 | + 'subtype' => 'plugin', |
|
413 | + 'limit' => ELGG_ENTITIES_NO_VALUE, |
|
414 | + 'selects' => ['plugin_oe.*', 'ps.value'], |
|
415 | + 'joins' => [ |
|
416 | + "JOIN {$db_prefix}private_settings ps on ps.entity_guid = e.guid", |
|
417 | + "JOIN {$db_prefix}objects_entity plugin_oe on plugin_oe.guid = e.guid" |
|
418 | + ], |
|
419 | + 'wheres' => ["ps.name = '$priority'"], |
|
420 | + // ORDER BY CAST(ps.value) is super slow. We usort() below. |
|
421 | + 'order_by' => false, |
|
422 | + 'distinct' => false, |
|
423 | + ]; |
|
424 | + |
|
425 | + switch ($status) { |
|
426 | + case 'active': |
|
427 | + $options['relationship'] = 'active_plugin'; |
|
428 | + $options['relationship_guid'] = $site_guid; |
|
429 | + $options['inverse_relationship'] = true; |
|
430 | + break; |
|
431 | + |
|
432 | + case 'inactive': |
|
433 | + $options['wheres'][] = "NOT EXISTS ( |
|
434 | 434 | SELECT 1 FROM {$db_prefix}entity_relationships active_er |
435 | 435 | WHERE active_er.guid_one = e.guid |
436 | 436 | AND active_er.relationship = 'active_plugin' |
437 | 437 | AND active_er.guid_two = $site_guid)"; |
438 | - break; |
|
438 | + break; |
|
439 | 439 | |
440 | - case 'all': |
|
441 | - default: |
|
442 | - break; |
|
443 | - } |
|
440 | + case 'all': |
|
441 | + default: |
|
442 | + break; |
|
443 | + } |
|
444 | 444 | |
445 | - $old_ia = elgg_set_ignore_access(true); |
|
446 | - $plugins = elgg_get_entities_from_relationship($options); |
|
447 | - elgg_set_ignore_access($old_ia); |
|
445 | + $old_ia = elgg_set_ignore_access(true); |
|
446 | + $plugins = elgg_get_entities_from_relationship($options); |
|
447 | + elgg_set_ignore_access($old_ia); |
|
448 | 448 | |
449 | - usort($plugins, function (\ElggPlugin $a, \ElggPlugin $b) { |
|
450 | - $a_value = $a->getVolatileData('select:value'); |
|
451 | - $b_value = $b->getVolatileData('select:value'); |
|
449 | + usort($plugins, function (\ElggPlugin $a, \ElggPlugin $b) { |
|
450 | + $a_value = $a->getVolatileData('select:value'); |
|
451 | + $b_value = $b->getVolatileData('select:value'); |
|
452 | 452 | |
453 | - if ($b_value !== $a_value) { |
|
454 | - return $a_value - $b_value; |
|
455 | - } else { |
|
456 | - return $a->guid - $b->guid; |
|
457 | - } |
|
458 | - }); |
|
459 | - |
|
460 | - return $plugins; |
|
461 | - } |
|
462 | - |
|
463 | - /** |
|
464 | - * Reorder plugins to an order specified by the array. |
|
465 | - * Plugins not included in this array will be appended to the end. |
|
466 | - * |
|
467 | - * @note This doesn't use the \ElggPlugin->setPriority() method because |
|
468 | - * all plugins are being changed and we don't want it to automatically |
|
469 | - * reorder plugins. |
|
470 | - * @todo Can this be done in a single sql command? |
|
471 | - * |
|
472 | - * @param array $order An array of plugin ids in the order to set them |
|
473 | - * @return bool |
|
474 | - * @access private |
|
475 | - */ |
|
476 | - function setPriorities(array $order) { |
|
477 | - $name = $this->namespacePrivateSetting('internal', 'priority'); |
|
478 | - |
|
479 | - $plugins = $this->find('any'); |
|
480 | - if (!$plugins) { |
|
481 | - return false; |
|
482 | - } |
|
483 | - |
|
484 | - // reindex to get standard counting. no need to increment by 10. |
|
485 | - // though we do start with 1 |
|
486 | - $order = array_values($order); |
|
487 | - |
|
488 | - $missing_plugins = []; |
|
489 | - /* @var \ElggPlugin[] $missing_plugins */ |
|
490 | - |
|
491 | - $priority = 0; |
|
492 | - foreach ($plugins as $plugin) { |
|
493 | - $plugin_id = $plugin->getID(); |
|
494 | - |
|
495 | - if (!in_array($plugin_id, $order)) { |
|
496 | - $missing_plugins[] = $plugin; |
|
497 | - continue; |
|
498 | - } |
|
499 | - |
|
500 | - $priority = array_search($plugin_id, $order) + 1; |
|
501 | - |
|
502 | - if (!$plugin->setPrivateSetting($name, $priority)) { |
|
503 | - return false; |
|
504 | - } |
|
505 | - } |
|
506 | - |
|
507 | - // set the missing plugins' priorities |
|
508 | - if (empty($missing_plugins)) { |
|
509 | - return true; |
|
510 | - } |
|
453 | + if ($b_value !== $a_value) { |
|
454 | + return $a_value - $b_value; |
|
455 | + } else { |
|
456 | + return $a->guid - $b->guid; |
|
457 | + } |
|
458 | + }); |
|
459 | + |
|
460 | + return $plugins; |
|
461 | + } |
|
462 | + |
|
463 | + /** |
|
464 | + * Reorder plugins to an order specified by the array. |
|
465 | + * Plugins not included in this array will be appended to the end. |
|
466 | + * |
|
467 | + * @note This doesn't use the \ElggPlugin->setPriority() method because |
|
468 | + * all plugins are being changed and we don't want it to automatically |
|
469 | + * reorder plugins. |
|
470 | + * @todo Can this be done in a single sql command? |
|
471 | + * |
|
472 | + * @param array $order An array of plugin ids in the order to set them |
|
473 | + * @return bool |
|
474 | + * @access private |
|
475 | + */ |
|
476 | + function setPriorities(array $order) { |
|
477 | + $name = $this->namespacePrivateSetting('internal', 'priority'); |
|
478 | + |
|
479 | + $plugins = $this->find('any'); |
|
480 | + if (!$plugins) { |
|
481 | + return false; |
|
482 | + } |
|
483 | + |
|
484 | + // reindex to get standard counting. no need to increment by 10. |
|
485 | + // though we do start with 1 |
|
486 | + $order = array_values($order); |
|
487 | + |
|
488 | + $missing_plugins = []; |
|
489 | + /* @var \ElggPlugin[] $missing_plugins */ |
|
490 | + |
|
491 | + $priority = 0; |
|
492 | + foreach ($plugins as $plugin) { |
|
493 | + $plugin_id = $plugin->getID(); |
|
494 | + |
|
495 | + if (!in_array($plugin_id, $order)) { |
|
496 | + $missing_plugins[] = $plugin; |
|
497 | + continue; |
|
498 | + } |
|
499 | + |
|
500 | + $priority = array_search($plugin_id, $order) + 1; |
|
501 | + |
|
502 | + if (!$plugin->setPrivateSetting($name, $priority)) { |
|
503 | + return false; |
|
504 | + } |
|
505 | + } |
|
506 | + |
|
507 | + // set the missing plugins' priorities |
|
508 | + if (empty($missing_plugins)) { |
|
509 | + return true; |
|
510 | + } |
|
511 | 511 | |
512 | - foreach ($missing_plugins as $plugin) { |
|
513 | - $priority++; |
|
514 | - if (!$plugin->setPrivateSetting($name, $priority)) { |
|
515 | - return false; |
|
516 | - } |
|
517 | - } |
|
518 | - |
|
519 | - return true; |
|
520 | - } |
|
521 | - |
|
522 | - /** |
|
523 | - * Reindexes all plugin priorities starting at 1. |
|
524 | - * |
|
525 | - * @return bool |
|
526 | - * @access private |
|
527 | - */ |
|
528 | - function reindexPriorities() { |
|
529 | - return $this->setPriorities([]); |
|
530 | - } |
|
531 | - |
|
532 | - /** |
|
533 | - * Namespaces a string to be used as a private setting name for a plugin. |
|
534 | - * |
|
535 | - * For user_settings, two namespaces are added: a user setting namespace and the |
|
536 | - * plugin id. |
|
537 | - * |
|
538 | - * For internal (plugin priority), there is a single internal namespace added. |
|
539 | - * |
|
540 | - * @param string $type The type of setting: user_setting or internal. |
|
541 | - * @param string $name The name to namespace. |
|
542 | - * @param string $id The plugin's ID to namespace with. Required for user_setting. |
|
543 | - * @return string |
|
544 | - * @access private |
|
545 | - */ |
|
546 | - function namespacePrivateSetting($type, $name, $id = null) { |
|
547 | - switch ($type) { |
|
548 | - case 'user_setting': |
|
549 | - if (!$id) { |
|
550 | - throw new \InvalidArgumentException("You must pass the plugin id for user settings"); |
|
551 | - } |
|
552 | - $name = ELGG_PLUGIN_USER_SETTING_PREFIX . "$id:$name"; |
|
553 | - break; |
|
554 | - |
|
555 | - case 'internal': |
|
556 | - $name = ELGG_PLUGIN_INTERNAL_PREFIX . $name; |
|
557 | - break; |
|
558 | - } |
|
559 | - |
|
560 | - return $name; |
|
561 | - } |
|
562 | - |
|
563 | - |
|
564 | - /** |
|
565 | - * Returns an array of all provides from all active plugins. |
|
566 | - * |
|
567 | - * Array in the form array( |
|
568 | - * 'provide_type' => array( |
|
569 | - * 'provided_name' => array( |
|
570 | - * 'version' => '1.8', |
|
571 | - * 'provided_by' => 'provider_plugin_id' |
|
572 | - * ) |
|
573 | - * ) |
|
574 | - * ) |
|
575 | - * |
|
576 | - * @param string $type The type of provides to return |
|
577 | - * @param string $name A specific provided name to return. Requires $provide_type. |
|
578 | - * |
|
579 | - * @return array |
|
580 | - * @access private |
|
581 | - */ |
|
582 | - function getProvides($type = null, $name = null) { |
|
583 | - if ($this->provides_cache === null) { |
|
584 | - $active_plugins = $this->find('active'); |
|
512 | + foreach ($missing_plugins as $plugin) { |
|
513 | + $priority++; |
|
514 | + if (!$plugin->setPrivateSetting($name, $priority)) { |
|
515 | + return false; |
|
516 | + } |
|
517 | + } |
|
518 | + |
|
519 | + return true; |
|
520 | + } |
|
521 | + |
|
522 | + /** |
|
523 | + * Reindexes all plugin priorities starting at 1. |
|
524 | + * |
|
525 | + * @return bool |
|
526 | + * @access private |
|
527 | + */ |
|
528 | + function reindexPriorities() { |
|
529 | + return $this->setPriorities([]); |
|
530 | + } |
|
531 | + |
|
532 | + /** |
|
533 | + * Namespaces a string to be used as a private setting name for a plugin. |
|
534 | + * |
|
535 | + * For user_settings, two namespaces are added: a user setting namespace and the |
|
536 | + * plugin id. |
|
537 | + * |
|
538 | + * For internal (plugin priority), there is a single internal namespace added. |
|
539 | + * |
|
540 | + * @param string $type The type of setting: user_setting or internal. |
|
541 | + * @param string $name The name to namespace. |
|
542 | + * @param string $id The plugin's ID to namespace with. Required for user_setting. |
|
543 | + * @return string |
|
544 | + * @access private |
|
545 | + */ |
|
546 | + function namespacePrivateSetting($type, $name, $id = null) { |
|
547 | + switch ($type) { |
|
548 | + case 'user_setting': |
|
549 | + if (!$id) { |
|
550 | + throw new \InvalidArgumentException("You must pass the plugin id for user settings"); |
|
551 | + } |
|
552 | + $name = ELGG_PLUGIN_USER_SETTING_PREFIX . "$id:$name"; |
|
553 | + break; |
|
554 | + |
|
555 | + case 'internal': |
|
556 | + $name = ELGG_PLUGIN_INTERNAL_PREFIX . $name; |
|
557 | + break; |
|
558 | + } |
|
559 | + |
|
560 | + return $name; |
|
561 | + } |
|
562 | + |
|
563 | + |
|
564 | + /** |
|
565 | + * Returns an array of all provides from all active plugins. |
|
566 | + * |
|
567 | + * Array in the form array( |
|
568 | + * 'provide_type' => array( |
|
569 | + * 'provided_name' => array( |
|
570 | + * 'version' => '1.8', |
|
571 | + * 'provided_by' => 'provider_plugin_id' |
|
572 | + * ) |
|
573 | + * ) |
|
574 | + * ) |
|
575 | + * |
|
576 | + * @param string $type The type of provides to return |
|
577 | + * @param string $name A specific provided name to return. Requires $provide_type. |
|
578 | + * |
|
579 | + * @return array |
|
580 | + * @access private |
|
581 | + */ |
|
582 | + function getProvides($type = null, $name = null) { |
|
583 | + if ($this->provides_cache === null) { |
|
584 | + $active_plugins = $this->find('active'); |
|
585 | 585 | |
586 | - $provides = []; |
|
587 | - |
|
588 | - foreach ($active_plugins as $plugin) { |
|
589 | - $plugin_provides = []; |
|
590 | - $manifest = $plugin->getManifest(); |
|
591 | - if ($manifest instanceof \ElggPluginManifest) { |
|
592 | - $plugin_provides = $plugin->getManifest()->getProvides(); |
|
593 | - } |
|
594 | - if ($plugin_provides) { |
|
595 | - foreach ($plugin_provides as $provided) { |
|
596 | - $provides[$provided['type']][$provided['name']] = [ |
|
597 | - 'version' => $provided['version'], |
|
598 | - 'provided_by' => $plugin->getID() |
|
599 | - ]; |
|
600 | - } |
|
601 | - } |
|
602 | - } |
|
586 | + $provides = []; |
|
587 | + |
|
588 | + foreach ($active_plugins as $plugin) { |
|
589 | + $plugin_provides = []; |
|
590 | + $manifest = $plugin->getManifest(); |
|
591 | + if ($manifest instanceof \ElggPluginManifest) { |
|
592 | + $plugin_provides = $plugin->getManifest()->getProvides(); |
|
593 | + } |
|
594 | + if ($plugin_provides) { |
|
595 | + foreach ($plugin_provides as $provided) { |
|
596 | + $provides[$provided['type']][$provided['name']] = [ |
|
597 | + 'version' => $provided['version'], |
|
598 | + 'provided_by' => $plugin->getID() |
|
599 | + ]; |
|
600 | + } |
|
601 | + } |
|
602 | + } |
|
603 | 603 | |
604 | - $this->provides_cache = $provides; |
|
605 | - } |
|
604 | + $this->provides_cache = $provides; |
|
605 | + } |
|
606 | 606 | |
607 | - if ($type && $name) { |
|
608 | - if (isset($this->provides_cache[$type][$name])) { |
|
609 | - return $this->provides_cache[$type][$name]; |
|
610 | - } else { |
|
611 | - return false; |
|
612 | - } |
|
613 | - } elseif ($type) { |
|
614 | - if (isset($this->provides_cache[$type])) { |
|
615 | - return $this->provides_cache[$type]; |
|
616 | - } else { |
|
617 | - return false; |
|
618 | - } |
|
619 | - } |
|
620 | - |
|
621 | - return $this->provides_cache; |
|
622 | - } |
|
623 | - |
|
624 | - /** |
|
625 | - * Deletes all cached data on plugins being provided. |
|
626 | - * |
|
627 | - * @return boolean |
|
628 | - * @access private |
|
629 | - */ |
|
630 | - function invalidateProvidesCache() { |
|
631 | - $this->provides_cache = null; |
|
632 | - return true; |
|
633 | - } |
|
607 | + if ($type && $name) { |
|
608 | + if (isset($this->provides_cache[$type][$name])) { |
|
609 | + return $this->provides_cache[$type][$name]; |
|
610 | + } else { |
|
611 | + return false; |
|
612 | + } |
|
613 | + } elseif ($type) { |
|
614 | + if (isset($this->provides_cache[$type])) { |
|
615 | + return $this->provides_cache[$type]; |
|
616 | + } else { |
|
617 | + return false; |
|
618 | + } |
|
619 | + } |
|
620 | + |
|
621 | + return $this->provides_cache; |
|
622 | + } |
|
623 | + |
|
624 | + /** |
|
625 | + * Deletes all cached data on plugins being provided. |
|
626 | + * |
|
627 | + * @return boolean |
|
628 | + * @access private |
|
629 | + */ |
|
630 | + function invalidateProvidesCache() { |
|
631 | + $this->provides_cache = null; |
|
632 | + return true; |
|
633 | + } |
|
634 | 634 | |
635 | - /** |
|
636 | - * Delete the cache holding whether plugins are active or not |
|
637 | - * |
|
638 | - * @return void |
|
639 | - * @access private |
|
640 | - */ |
|
641 | - public function invalidateIsActiveCache() { |
|
642 | - $this->active_guids = []; |
|
643 | - $this->active_guids_known = false; |
|
644 | - } |
|
645 | - |
|
646 | - /** |
|
647 | - * Checks if a plugin is currently providing $type and $name, and optionally |
|
648 | - * checking a version. |
|
649 | - * |
|
650 | - * @param string $type The type of the provide |
|
651 | - * @param string $name The name of the provide |
|
652 | - * @param string $version A version to check against |
|
653 | - * @param string $comparison The comparison operator to use in version_compare() |
|
654 | - * |
|
655 | - * @return array An array in the form array( |
|
656 | - * 'status' => bool Does the provide exist?, |
|
657 | - * 'value' => string The version provided |
|
658 | - * ) |
|
659 | - * @access private |
|
660 | - */ |
|
661 | - function checkProvides($type, $name, $version = null, $comparison = 'ge') { |
|
662 | - $provided = $this->getProvides($type, $name); |
|
663 | - if (!$provided) { |
|
664 | - return [ |
|
665 | - 'status' => false, |
|
666 | - 'value' => '' |
|
667 | - ]; |
|
668 | - } |
|
669 | - |
|
670 | - if ($version) { |
|
671 | - $status = version_compare($provided['version'], $version, $comparison); |
|
672 | - } else { |
|
673 | - $status = true; |
|
674 | - } |
|
675 | - |
|
676 | - return [ |
|
677 | - 'status' => $status, |
|
678 | - 'value' => $provided['version'] |
|
679 | - ]; |
|
680 | - } |
|
681 | - |
|
682 | - /** |
|
683 | - * Returns an array of parsed strings for a dependency in the |
|
684 | - * format: array( |
|
685 | - * 'type' => requires, conflicts, or provides. |
|
686 | - * 'name' => The name of the requirement / conflict |
|
687 | - * 'value' => A string representing the expected value: <1, >=3, !=enabled |
|
688 | - * 'local_value' => The current value, ("Not installed") |
|
689 | - * 'comment' => Free form text to help resovle the problem ("Enable / Search for plugin <link>") |
|
690 | - * ) |
|
691 | - * |
|
692 | - * @param array $dep An \ElggPluginPackage dependency array |
|
693 | - * @return array |
|
694 | - * @access private |
|
695 | - */ |
|
696 | - function getDependencyStrings($dep) { |
|
697 | - $translator = _elgg_services()->translator; |
|
698 | - $dep_system = elgg_extract('type', $dep); |
|
699 | - $info = elgg_extract('dep', $dep); |
|
700 | - $type = elgg_extract('type', $info); |
|
701 | - |
|
702 | - if (!$dep_system || !$info || !$type) { |
|
703 | - return false; |
|
704 | - } |
|
705 | - |
|
706 | - // rewrite some of these to be more readable |
|
707 | - $comparison = elgg_extract('comparison', $info); |
|
708 | - switch ($comparison) { |
|
709 | - case 'lt': |
|
710 | - $comparison = '<'; |
|
711 | - break; |
|
712 | - case 'gt': |
|
713 | - $comparison = '>'; |
|
714 | - break; |
|
715 | - case 'ge': |
|
716 | - $comparison = '>='; |
|
717 | - break; |
|
718 | - case 'le': |
|
719 | - $comparison = '<='; |
|
720 | - break; |
|
721 | - default: |
|
722 | - //keep $comparison value intact |
|
723 | - break; |
|
724 | - } |
|
725 | - |
|
726 | - /* |
|
635 | + /** |
|
636 | + * Delete the cache holding whether plugins are active or not |
|
637 | + * |
|
638 | + * @return void |
|
639 | + * @access private |
|
640 | + */ |
|
641 | + public function invalidateIsActiveCache() { |
|
642 | + $this->active_guids = []; |
|
643 | + $this->active_guids_known = false; |
|
644 | + } |
|
645 | + |
|
646 | + /** |
|
647 | + * Checks if a plugin is currently providing $type and $name, and optionally |
|
648 | + * checking a version. |
|
649 | + * |
|
650 | + * @param string $type The type of the provide |
|
651 | + * @param string $name The name of the provide |
|
652 | + * @param string $version A version to check against |
|
653 | + * @param string $comparison The comparison operator to use in version_compare() |
|
654 | + * |
|
655 | + * @return array An array in the form array( |
|
656 | + * 'status' => bool Does the provide exist?, |
|
657 | + * 'value' => string The version provided |
|
658 | + * ) |
|
659 | + * @access private |
|
660 | + */ |
|
661 | + function checkProvides($type, $name, $version = null, $comparison = 'ge') { |
|
662 | + $provided = $this->getProvides($type, $name); |
|
663 | + if (!$provided) { |
|
664 | + return [ |
|
665 | + 'status' => false, |
|
666 | + 'value' => '' |
|
667 | + ]; |
|
668 | + } |
|
669 | + |
|
670 | + if ($version) { |
|
671 | + $status = version_compare($provided['version'], $version, $comparison); |
|
672 | + } else { |
|
673 | + $status = true; |
|
674 | + } |
|
675 | + |
|
676 | + return [ |
|
677 | + 'status' => $status, |
|
678 | + 'value' => $provided['version'] |
|
679 | + ]; |
|
680 | + } |
|
681 | + |
|
682 | + /** |
|
683 | + * Returns an array of parsed strings for a dependency in the |
|
684 | + * format: array( |
|
685 | + * 'type' => requires, conflicts, or provides. |
|
686 | + * 'name' => The name of the requirement / conflict |
|
687 | + * 'value' => A string representing the expected value: <1, >=3, !=enabled |
|
688 | + * 'local_value' => The current value, ("Not installed") |
|
689 | + * 'comment' => Free form text to help resovle the problem ("Enable / Search for plugin <link>") |
|
690 | + * ) |
|
691 | + * |
|
692 | + * @param array $dep An \ElggPluginPackage dependency array |
|
693 | + * @return array |
|
694 | + * @access private |
|
695 | + */ |
|
696 | + function getDependencyStrings($dep) { |
|
697 | + $translator = _elgg_services()->translator; |
|
698 | + $dep_system = elgg_extract('type', $dep); |
|
699 | + $info = elgg_extract('dep', $dep); |
|
700 | + $type = elgg_extract('type', $info); |
|
701 | + |
|
702 | + if (!$dep_system || !$info || !$type) { |
|
703 | + return false; |
|
704 | + } |
|
705 | + |
|
706 | + // rewrite some of these to be more readable |
|
707 | + $comparison = elgg_extract('comparison', $info); |
|
708 | + switch ($comparison) { |
|
709 | + case 'lt': |
|
710 | + $comparison = '<'; |
|
711 | + break; |
|
712 | + case 'gt': |
|
713 | + $comparison = '>'; |
|
714 | + break; |
|
715 | + case 'ge': |
|
716 | + $comparison = '>='; |
|
717 | + break; |
|
718 | + case 'le': |
|
719 | + $comparison = '<='; |
|
720 | + break; |
|
721 | + default: |
|
722 | + //keep $comparison value intact |
|
723 | + break; |
|
724 | + } |
|
725 | + |
|
726 | + /* |
|
727 | 727 | 'requires' 'plugin oauth_lib' <1.3 1.3 'downgrade' |
728 | 728 | 'requires' 'php setting bob' >3 3 'change it' |
729 | 729 | 'conflicts' 'php setting' >3 4 'change it' |
@@ -731,304 +731,304 @@ discard block |
||
731 | 731 | 'provides' 'plugin oauth_lib' 1.3 -- -- |
732 | 732 | 'priority' 'before blog' -- after 'move it' |
733 | 733 | */ |
734 | - $strings = []; |
|
735 | - $strings['type'] = $translator->translate('ElggPlugin:Dependencies:' . ucwords($dep_system)); |
|
736 | - |
|
737 | - switch ($type) { |
|
738 | - case 'elgg_release': |
|
739 | - // 'Elgg Version' |
|
740 | - $strings['name'] = $translator->translate('ElggPlugin:Dependencies:Elgg'); |
|
741 | - $strings['expected_value'] = "$comparison {$info['version']}"; |
|
742 | - $strings['local_value'] = $dep['value']; |
|
743 | - $strings['comment'] = ''; |
|
744 | - break; |
|
745 | - |
|
746 | - case 'php_version': |
|
747 | - // 'PHP version' |
|
748 | - $strings['name'] = $translator->translate('ElggPlugin:Dependencies:PhpVersion'); |
|
749 | - $strings['expected_value'] = "$comparison {$info['version']}"; |
|
750 | - $strings['local_value'] = $dep['value']; |
|
751 | - $strings['comment'] = ''; |
|
752 | - break; |
|
734 | + $strings = []; |
|
735 | + $strings['type'] = $translator->translate('ElggPlugin:Dependencies:' . ucwords($dep_system)); |
|
736 | + |
|
737 | + switch ($type) { |
|
738 | + case 'elgg_release': |
|
739 | + // 'Elgg Version' |
|
740 | + $strings['name'] = $translator->translate('ElggPlugin:Dependencies:Elgg'); |
|
741 | + $strings['expected_value'] = "$comparison {$info['version']}"; |
|
742 | + $strings['local_value'] = $dep['value']; |
|
743 | + $strings['comment'] = ''; |
|
744 | + break; |
|
745 | + |
|
746 | + case 'php_version': |
|
747 | + // 'PHP version' |
|
748 | + $strings['name'] = $translator->translate('ElggPlugin:Dependencies:PhpVersion'); |
|
749 | + $strings['expected_value'] = "$comparison {$info['version']}"; |
|
750 | + $strings['local_value'] = $dep['value']; |
|
751 | + $strings['comment'] = ''; |
|
752 | + break; |
|
753 | 753 | |
754 | - case 'php_extension': |
|
755 | - // PHP Extension %s [version] |
|
756 | - $strings['name'] = $translator->translate('ElggPlugin:Dependencies:PhpExtension', [$info['name']]); |
|
757 | - if ($info['version']) { |
|
758 | - $strings['expected_value'] = "$comparison {$info['version']}"; |
|
759 | - $strings['local_value'] = $dep['value']; |
|
760 | - } else { |
|
761 | - $strings['expected_value'] = ''; |
|
762 | - $strings['local_value'] = ''; |
|
763 | - } |
|
764 | - $strings['comment'] = ''; |
|
765 | - break; |
|
766 | - |
|
767 | - case 'php_ini': |
|
768 | - $strings['name'] = $translator->translate('ElggPlugin:Dependencies:PhpIni', [$info['name']]); |
|
769 | - $strings['expected_value'] = "$comparison {$info['value']}"; |
|
770 | - $strings['local_value'] = $dep['value']; |
|
771 | - $strings['comment'] = ''; |
|
772 | - break; |
|
773 | - |
|
774 | - case 'plugin': |
|
775 | - $strings['name'] = $translator->translate('ElggPlugin:Dependencies:Plugin', [$info['name']]); |
|
776 | - $expected = $info['version'] ? "$comparison {$info['version']}" : $translator->translate('any'); |
|
777 | - $strings['expected_value'] = $expected; |
|
778 | - $strings['local_value'] = $dep['value'] ? $dep['value'] : '--'; |
|
779 | - $strings['comment'] = ''; |
|
780 | - break; |
|
781 | - |
|
782 | - case 'priority': |
|
783 | - $expected_priority = ucwords($info['priority']); |
|
784 | - $real_priority = ucwords($dep['value']); |
|
785 | - $strings['name'] = $translator->translate('ElggPlugin:Dependencies:Priority'); |
|
786 | - $strings['expected_value'] = $translator->translate("ElggPlugin:Dependencies:Priority:$expected_priority", [$info['plugin']]); |
|
787 | - $strings['local_value'] = $translator->translate("ElggPlugin:Dependencies:Priority:$real_priority", [$info['plugin']]); |
|
788 | - $strings['comment'] = ''; |
|
789 | - break; |
|
790 | - } |
|
791 | - |
|
792 | - if ($dep['type'] == 'suggests') { |
|
793 | - if ($dep['status']) { |
|
794 | - $strings['comment'] = $translator->translate('ok'); |
|
795 | - } else { |
|
796 | - $strings['comment'] = $translator->translate('ElggPlugin:Dependencies:Suggests:Unsatisfied'); |
|
797 | - } |
|
798 | - } else { |
|
799 | - if ($dep['status']) { |
|
800 | - $strings['comment'] = $translator->translate('ok'); |
|
801 | - } else { |
|
802 | - $strings['comment'] = $translator->translate('error'); |
|
803 | - } |
|
804 | - } |
|
805 | - |
|
806 | - return $strings; |
|
807 | - } |
|
808 | - |
|
809 | - /** |
|
810 | - * Returns an array of all plugin user settings for a user. |
|
811 | - * |
|
812 | - * @param int $user_guid The user GUID or 0 for the currently logged in user. |
|
813 | - * @param string $plugin_id The plugin ID (Required) |
|
814 | - * @param bool $return_obj Return settings as an object? This can be used to in reusable |
|
815 | - * views where the settings are passed as $vars['entity']. |
|
816 | - * @return array |
|
817 | - * @see \ElggPlugin::getAllUserSettings() |
|
818 | - */ |
|
819 | - function getAllUserSettings($user_guid = 0, $plugin_id = null, $return_obj = false) { |
|
820 | - $plugin = $this->get($plugin_id); |
|
821 | - if (!$plugin) { |
|
822 | - return false; |
|
823 | - } |
|
824 | - |
|
825 | - $settings = $plugin->getAllUserSettings((int) $user_guid); |
|
826 | - |
|
827 | - if ($settings && $return_obj) { |
|
828 | - $return = new \stdClass; |
|
829 | - |
|
830 | - foreach ($settings as $k => $v) { |
|
831 | - $return->$k = $v; |
|
832 | - } |
|
833 | - |
|
834 | - return $return; |
|
835 | - } else { |
|
836 | - return $settings; |
|
837 | - } |
|
838 | - } |
|
839 | - |
|
840 | - /** |
|
841 | - * Set a user specific setting for a plugin. |
|
842 | - * |
|
843 | - * @param string $name The name. Note: cannot be "title". |
|
844 | - * @param mixed $value The value. |
|
845 | - * @param int $user_guid The user GUID or 0 for the currently logged in user. |
|
846 | - * @param string $plugin_id The plugin ID (Required) |
|
847 | - * |
|
848 | - * @return bool |
|
849 | - * @see \ElggPlugin::setUserSetting() |
|
850 | - */ |
|
851 | - function setUserSetting($name, $value, $user_guid = 0, $plugin_id = null) { |
|
852 | - $plugin = $this->get($plugin_id); |
|
853 | - if (!$plugin) { |
|
854 | - return false; |
|
855 | - } |
|
754 | + case 'php_extension': |
|
755 | + // PHP Extension %s [version] |
|
756 | + $strings['name'] = $translator->translate('ElggPlugin:Dependencies:PhpExtension', [$info['name']]); |
|
757 | + if ($info['version']) { |
|
758 | + $strings['expected_value'] = "$comparison {$info['version']}"; |
|
759 | + $strings['local_value'] = $dep['value']; |
|
760 | + } else { |
|
761 | + $strings['expected_value'] = ''; |
|
762 | + $strings['local_value'] = ''; |
|
763 | + } |
|
764 | + $strings['comment'] = ''; |
|
765 | + break; |
|
766 | + |
|
767 | + case 'php_ini': |
|
768 | + $strings['name'] = $translator->translate('ElggPlugin:Dependencies:PhpIni', [$info['name']]); |
|
769 | + $strings['expected_value'] = "$comparison {$info['value']}"; |
|
770 | + $strings['local_value'] = $dep['value']; |
|
771 | + $strings['comment'] = ''; |
|
772 | + break; |
|
773 | + |
|
774 | + case 'plugin': |
|
775 | + $strings['name'] = $translator->translate('ElggPlugin:Dependencies:Plugin', [$info['name']]); |
|
776 | + $expected = $info['version'] ? "$comparison {$info['version']}" : $translator->translate('any'); |
|
777 | + $strings['expected_value'] = $expected; |
|
778 | + $strings['local_value'] = $dep['value'] ? $dep['value'] : '--'; |
|
779 | + $strings['comment'] = ''; |
|
780 | + break; |
|
781 | + |
|
782 | + case 'priority': |
|
783 | + $expected_priority = ucwords($info['priority']); |
|
784 | + $real_priority = ucwords($dep['value']); |
|
785 | + $strings['name'] = $translator->translate('ElggPlugin:Dependencies:Priority'); |
|
786 | + $strings['expected_value'] = $translator->translate("ElggPlugin:Dependencies:Priority:$expected_priority", [$info['plugin']]); |
|
787 | + $strings['local_value'] = $translator->translate("ElggPlugin:Dependencies:Priority:$real_priority", [$info['plugin']]); |
|
788 | + $strings['comment'] = ''; |
|
789 | + break; |
|
790 | + } |
|
791 | + |
|
792 | + if ($dep['type'] == 'suggests') { |
|
793 | + if ($dep['status']) { |
|
794 | + $strings['comment'] = $translator->translate('ok'); |
|
795 | + } else { |
|
796 | + $strings['comment'] = $translator->translate('ElggPlugin:Dependencies:Suggests:Unsatisfied'); |
|
797 | + } |
|
798 | + } else { |
|
799 | + if ($dep['status']) { |
|
800 | + $strings['comment'] = $translator->translate('ok'); |
|
801 | + } else { |
|
802 | + $strings['comment'] = $translator->translate('error'); |
|
803 | + } |
|
804 | + } |
|
805 | + |
|
806 | + return $strings; |
|
807 | + } |
|
808 | + |
|
809 | + /** |
|
810 | + * Returns an array of all plugin user settings for a user. |
|
811 | + * |
|
812 | + * @param int $user_guid The user GUID or 0 for the currently logged in user. |
|
813 | + * @param string $plugin_id The plugin ID (Required) |
|
814 | + * @param bool $return_obj Return settings as an object? This can be used to in reusable |
|
815 | + * views where the settings are passed as $vars['entity']. |
|
816 | + * @return array |
|
817 | + * @see \ElggPlugin::getAllUserSettings() |
|
818 | + */ |
|
819 | + function getAllUserSettings($user_guid = 0, $plugin_id = null, $return_obj = false) { |
|
820 | + $plugin = $this->get($plugin_id); |
|
821 | + if (!$plugin) { |
|
822 | + return false; |
|
823 | + } |
|
824 | + |
|
825 | + $settings = $plugin->getAllUserSettings((int) $user_guid); |
|
826 | + |
|
827 | + if ($settings && $return_obj) { |
|
828 | + $return = new \stdClass; |
|
829 | + |
|
830 | + foreach ($settings as $k => $v) { |
|
831 | + $return->$k = $v; |
|
832 | + } |
|
833 | + |
|
834 | + return $return; |
|
835 | + } else { |
|
836 | + return $settings; |
|
837 | + } |
|
838 | + } |
|
839 | + |
|
840 | + /** |
|
841 | + * Set a user specific setting for a plugin. |
|
842 | + * |
|
843 | + * @param string $name The name. Note: cannot be "title". |
|
844 | + * @param mixed $value The value. |
|
845 | + * @param int $user_guid The user GUID or 0 for the currently logged in user. |
|
846 | + * @param string $plugin_id The plugin ID (Required) |
|
847 | + * |
|
848 | + * @return bool |
|
849 | + * @see \ElggPlugin::setUserSetting() |
|
850 | + */ |
|
851 | + function setUserSetting($name, $value, $user_guid = 0, $plugin_id = null) { |
|
852 | + $plugin = $this->get($plugin_id); |
|
853 | + if (!$plugin) { |
|
854 | + return false; |
|
855 | + } |
|
856 | 856 | |
857 | - return $plugin->setUserSetting($name, $value, (int) $user_guid); |
|
858 | - } |
|
859 | - |
|
860 | - /** |
|
861 | - * Unsets a user-specific plugin setting |
|
862 | - * |
|
863 | - * @param string $name Name of the setting |
|
864 | - * @param int $user_guid The user GUID or 0 for the currently logged in user. |
|
865 | - * @param string $plugin_id The plugin ID (Required) |
|
866 | - * |
|
867 | - * @return bool |
|
868 | - * @see \ElggPlugin::unsetUserSetting() |
|
869 | - */ |
|
870 | - function unsetUserSetting($name, $user_guid = 0, $plugin_id = null) { |
|
871 | - $plugin = $this->get($plugin_id); |
|
872 | - if (!$plugin) { |
|
873 | - return false; |
|
874 | - } |
|
857 | + return $plugin->setUserSetting($name, $value, (int) $user_guid); |
|
858 | + } |
|
859 | + |
|
860 | + /** |
|
861 | + * Unsets a user-specific plugin setting |
|
862 | + * |
|
863 | + * @param string $name Name of the setting |
|
864 | + * @param int $user_guid The user GUID or 0 for the currently logged in user. |
|
865 | + * @param string $plugin_id The plugin ID (Required) |
|
866 | + * |
|
867 | + * @return bool |
|
868 | + * @see \ElggPlugin::unsetUserSetting() |
|
869 | + */ |
|
870 | + function unsetUserSetting($name, $user_guid = 0, $plugin_id = null) { |
|
871 | + $plugin = $this->get($plugin_id); |
|
872 | + if (!$plugin) { |
|
873 | + return false; |
|
874 | + } |
|
875 | 875 | |
876 | - return $plugin->unsetUserSetting($name, (int) $user_guid); |
|
877 | - } |
|
878 | - |
|
879 | - /** |
|
880 | - * Get a user specific setting for a plugin. |
|
881 | - * |
|
882 | - * @param string $name The name of the setting. |
|
883 | - * @param int $user_guid The user GUID or 0 for the currently logged in user. |
|
884 | - * @param string $plugin_id The plugin ID (Required) |
|
885 | - * @param mixed $default The default value to return if none is set |
|
886 | - * |
|
887 | - * @return mixed |
|
888 | - * @see \ElggPlugin::getUserSetting() |
|
889 | - */ |
|
890 | - function getUserSetting($name, $user_guid = 0, $plugin_id = null, $default = null) { |
|
891 | - $plugin = $this->get($plugin_id); |
|
892 | - if (!$plugin) { |
|
893 | - return false; |
|
894 | - } |
|
876 | + return $plugin->unsetUserSetting($name, (int) $user_guid); |
|
877 | + } |
|
878 | + |
|
879 | + /** |
|
880 | + * Get a user specific setting for a plugin. |
|
881 | + * |
|
882 | + * @param string $name The name of the setting. |
|
883 | + * @param int $user_guid The user GUID or 0 for the currently logged in user. |
|
884 | + * @param string $plugin_id The plugin ID (Required) |
|
885 | + * @param mixed $default The default value to return if none is set |
|
886 | + * |
|
887 | + * @return mixed |
|
888 | + * @see \ElggPlugin::getUserSetting() |
|
889 | + */ |
|
890 | + function getUserSetting($name, $user_guid = 0, $plugin_id = null, $default = null) { |
|
891 | + $plugin = $this->get($plugin_id); |
|
892 | + if (!$plugin) { |
|
893 | + return false; |
|
894 | + } |
|
895 | 895 | |
896 | - return $plugin->getUserSetting($name, (int) $user_guid, $default); |
|
897 | - } |
|
898 | - |
|
899 | - /** |
|
900 | - * Set a setting for a plugin. |
|
901 | - * |
|
902 | - * @param string $name The name of the setting - note, can't be "title". |
|
903 | - * @param mixed $value The value. |
|
904 | - * @param string $plugin_id The plugin ID (Required) |
|
905 | - * |
|
906 | - * @return bool |
|
907 | - * @see \ElggPlugin::setSetting() |
|
908 | - */ |
|
909 | - function setSetting($name, $value, $plugin_id) { |
|
910 | - $plugin = $this->get($plugin_id); |
|
911 | - if (!$plugin) { |
|
912 | - return false; |
|
913 | - } |
|
896 | + return $plugin->getUserSetting($name, (int) $user_guid, $default); |
|
897 | + } |
|
898 | + |
|
899 | + /** |
|
900 | + * Set a setting for a plugin. |
|
901 | + * |
|
902 | + * @param string $name The name of the setting - note, can't be "title". |
|
903 | + * @param mixed $value The value. |
|
904 | + * @param string $plugin_id The plugin ID (Required) |
|
905 | + * |
|
906 | + * @return bool |
|
907 | + * @see \ElggPlugin::setSetting() |
|
908 | + */ |
|
909 | + function setSetting($name, $value, $plugin_id) { |
|
910 | + $plugin = $this->get($plugin_id); |
|
911 | + if (!$plugin) { |
|
912 | + return false; |
|
913 | + } |
|
914 | 914 | |
915 | - return $plugin->setSetting($name, $value); |
|
916 | - } |
|
917 | - |
|
918 | - /** |
|
919 | - * Get setting for a plugin. |
|
920 | - * |
|
921 | - * @param string $name The name of the setting. |
|
922 | - * @param string $plugin_id The plugin ID (Required) |
|
923 | - * @param mixed $default The default value to return if none is set |
|
924 | - * |
|
925 | - * @return mixed |
|
926 | - * @see \ElggPlugin::getSetting() |
|
927 | - */ |
|
928 | - function getSetting($name, $plugin_id, $default = null) { |
|
929 | - $plugin = $this->get($plugin_id); |
|
930 | - if (!$plugin) { |
|
931 | - return false; |
|
932 | - } |
|
915 | + return $plugin->setSetting($name, $value); |
|
916 | + } |
|
917 | + |
|
918 | + /** |
|
919 | + * Get setting for a plugin. |
|
920 | + * |
|
921 | + * @param string $name The name of the setting. |
|
922 | + * @param string $plugin_id The plugin ID (Required) |
|
923 | + * @param mixed $default The default value to return if none is set |
|
924 | + * |
|
925 | + * @return mixed |
|
926 | + * @see \ElggPlugin::getSetting() |
|
927 | + */ |
|
928 | + function getSetting($name, $plugin_id, $default = null) { |
|
929 | + $plugin = $this->get($plugin_id); |
|
930 | + if (!$plugin) { |
|
931 | + return false; |
|
932 | + } |
|
933 | 933 | |
934 | - return $plugin->getSetting($name, $default); |
|
935 | - } |
|
936 | - |
|
937 | - /** |
|
938 | - * Unsets a plugin setting. |
|
939 | - * |
|
940 | - * @param string $name The name of the setting. |
|
941 | - * @param string $plugin_id The plugin ID (Required) |
|
942 | - * |
|
943 | - * @return bool |
|
944 | - * @see \ElggPlugin::unsetSetting() |
|
945 | - */ |
|
946 | - function unsetSetting($name, $plugin_id) { |
|
947 | - $plugin = $this->get($plugin_id); |
|
948 | - if (!$plugin) { |
|
949 | - return false; |
|
950 | - } |
|
934 | + return $plugin->getSetting($name, $default); |
|
935 | + } |
|
936 | + |
|
937 | + /** |
|
938 | + * Unsets a plugin setting. |
|
939 | + * |
|
940 | + * @param string $name The name of the setting. |
|
941 | + * @param string $plugin_id The plugin ID (Required) |
|
942 | + * |
|
943 | + * @return bool |
|
944 | + * @see \ElggPlugin::unsetSetting() |
|
945 | + */ |
|
946 | + function unsetSetting($name, $plugin_id) { |
|
947 | + $plugin = $this->get($plugin_id); |
|
948 | + if (!$plugin) { |
|
949 | + return false; |
|
950 | + } |
|
951 | 951 | |
952 | - return $plugin->unsetSetting($name); |
|
953 | - } |
|
954 | - |
|
955 | - /** |
|
956 | - * Unsets all plugin settings for a plugin. |
|
957 | - * |
|
958 | - * @param string $plugin_id The plugin ID (Required) |
|
959 | - * |
|
960 | - * @return bool |
|
961 | - * @see \ElggPlugin::unsetAllSettings() |
|
962 | - */ |
|
963 | - function unsetAllSettings($plugin_id) { |
|
964 | - $plugin = $this->get($plugin_id); |
|
965 | - if (!$plugin) { |
|
966 | - return false; |
|
967 | - } |
|
968 | - |
|
969 | - return $plugin->unsetAllSettings(); |
|
970 | - } |
|
971 | - |
|
972 | - /** |
|
973 | - * Returns entities based upon plugin user settings. |
|
974 | - * Takes all the options for {@link elgg_get_entities_from_private_settings()} |
|
975 | - * in addition to the ones below. |
|
976 | - * |
|
977 | - * @param array $options Array in the format: |
|
978 | - * |
|
979 | - * plugin_id => STR The plugin id. Required. |
|
980 | - * |
|
981 | - * plugin_user_setting_names => null|ARR private setting names |
|
982 | - * |
|
983 | - * plugin_user_setting_values => null|ARR metadata values |
|
984 | - * |
|
985 | - * plugin_user_setting_name_value_pairs => null|ARR ( |
|
986 | - * name => 'name', |
|
987 | - * value => 'value', |
|
988 | - * 'operand' => '=', |
|
989 | - * ) |
|
990 | - * Currently if multiple values are sent via |
|
991 | - * an array (value => array('value1', 'value2') |
|
992 | - * the pair's operand will be forced to "IN". |
|
993 | - * |
|
994 | - * plugin_user_setting_name_value_pairs_operator => null|STR The operator to use for combining |
|
995 | - * (name = value) OPERATOR (name = value); default AND |
|
996 | - * |
|
997 | - * @return mixed int If count, int. If not count, array. false on errors. |
|
998 | - */ |
|
999 | - function getEntitiesFromUserSettings(array $options = []) { |
|
1000 | - $singulars = ['plugin_user_setting_name', 'plugin_user_setting_value', |
|
1001 | - 'plugin_user_setting_name_value_pair']; |
|
1002 | - |
|
1003 | - $options = _elgg_normalize_plural_options_array($options, $singulars); |
|
1004 | - |
|
1005 | - // rewrite plugin_user_setting_name_* to the right PS ones. |
|
1006 | - $map = [ |
|
1007 | - 'plugin_user_setting_names' => 'private_setting_names', |
|
1008 | - 'plugin_user_setting_values' => 'private_setting_values', |
|
1009 | - 'plugin_user_setting_name_value_pairs' => 'private_setting_name_value_pairs', |
|
1010 | - 'plugin_user_setting_name_value_pairs_operator' => 'private_setting_name_value_pairs_operator', |
|
1011 | - ]; |
|
1012 | - |
|
1013 | - foreach ($map as $plugin => $private) { |
|
1014 | - if (!isset($options[$plugin])) { |
|
1015 | - continue; |
|
1016 | - } |
|
1017 | - |
|
1018 | - if (isset($options[$private])) { |
|
1019 | - if (!is_array($options[$private])) { |
|
1020 | - $options[$private] = [$options[$private]]; |
|
1021 | - } |
|
1022 | - |
|
1023 | - $options[$private] = array_merge($options[$private], $options[$plugin]); |
|
1024 | - } else { |
|
1025 | - $options[$private] = $options[$plugin]; |
|
1026 | - } |
|
1027 | - } |
|
1028 | - |
|
1029 | - $prefix = $this->namespacePrivateSetting('user_setting', '', $options['plugin_id']); |
|
1030 | - $options['private_setting_name_prefix'] = $prefix; |
|
1031 | - |
|
1032 | - return elgg_get_entities_from_private_settings($options); |
|
1033 | - } |
|
952 | + return $plugin->unsetSetting($name); |
|
953 | + } |
|
954 | + |
|
955 | + /** |
|
956 | + * Unsets all plugin settings for a plugin. |
|
957 | + * |
|
958 | + * @param string $plugin_id The plugin ID (Required) |
|
959 | + * |
|
960 | + * @return bool |
|
961 | + * @see \ElggPlugin::unsetAllSettings() |
|
962 | + */ |
|
963 | + function unsetAllSettings($plugin_id) { |
|
964 | + $plugin = $this->get($plugin_id); |
|
965 | + if (!$plugin) { |
|
966 | + return false; |
|
967 | + } |
|
968 | + |
|
969 | + return $plugin->unsetAllSettings(); |
|
970 | + } |
|
971 | + |
|
972 | + /** |
|
973 | + * Returns entities based upon plugin user settings. |
|
974 | + * Takes all the options for {@link elgg_get_entities_from_private_settings()} |
|
975 | + * in addition to the ones below. |
|
976 | + * |
|
977 | + * @param array $options Array in the format: |
|
978 | + * |
|
979 | + * plugin_id => STR The plugin id. Required. |
|
980 | + * |
|
981 | + * plugin_user_setting_names => null|ARR private setting names |
|
982 | + * |
|
983 | + * plugin_user_setting_values => null|ARR metadata values |
|
984 | + * |
|
985 | + * plugin_user_setting_name_value_pairs => null|ARR ( |
|
986 | + * name => 'name', |
|
987 | + * value => 'value', |
|
988 | + * 'operand' => '=', |
|
989 | + * ) |
|
990 | + * Currently if multiple values are sent via |
|
991 | + * an array (value => array('value1', 'value2') |
|
992 | + * the pair's operand will be forced to "IN". |
|
993 | + * |
|
994 | + * plugin_user_setting_name_value_pairs_operator => null|STR The operator to use for combining |
|
995 | + * (name = value) OPERATOR (name = value); default AND |
|
996 | + * |
|
997 | + * @return mixed int If count, int. If not count, array. false on errors. |
|
998 | + */ |
|
999 | + function getEntitiesFromUserSettings(array $options = []) { |
|
1000 | + $singulars = ['plugin_user_setting_name', 'plugin_user_setting_value', |
|
1001 | + 'plugin_user_setting_name_value_pair']; |
|
1002 | + |
|
1003 | + $options = _elgg_normalize_plural_options_array($options, $singulars); |
|
1004 | + |
|
1005 | + // rewrite plugin_user_setting_name_* to the right PS ones. |
|
1006 | + $map = [ |
|
1007 | + 'plugin_user_setting_names' => 'private_setting_names', |
|
1008 | + 'plugin_user_setting_values' => 'private_setting_values', |
|
1009 | + 'plugin_user_setting_name_value_pairs' => 'private_setting_name_value_pairs', |
|
1010 | + 'plugin_user_setting_name_value_pairs_operator' => 'private_setting_name_value_pairs_operator', |
|
1011 | + ]; |
|
1012 | + |
|
1013 | + foreach ($map as $plugin => $private) { |
|
1014 | + if (!isset($options[$plugin])) { |
|
1015 | + continue; |
|
1016 | + } |
|
1017 | + |
|
1018 | + if (isset($options[$private])) { |
|
1019 | + if (!is_array($options[$private])) { |
|
1020 | + $options[$private] = [$options[$private]]; |
|
1021 | + } |
|
1022 | + |
|
1023 | + $options[$private] = array_merge($options[$private], $options[$plugin]); |
|
1024 | + } else { |
|
1025 | + $options[$private] = $options[$plugin]; |
|
1026 | + } |
|
1027 | + } |
|
1028 | + |
|
1029 | + $prefix = $this->namespacePrivateSetting('user_setting', '', $options['plugin_id']); |
|
1030 | + $options['private_setting_name_prefix'] = $prefix; |
|
1031 | + |
|
1032 | + return elgg_get_entities_from_private_settings($options); |
|
1033 | + } |
|
1034 | 1034 | } |
@@ -38,177 +38,177 @@ discard block |
||
38 | 38 | */ |
39 | 39 | class EntityTable { |
40 | 40 | |
41 | - use \Elgg\TimeUsing; |
|
41 | + use \Elgg\TimeUsing; |
|
42 | 42 | |
43 | - /** |
|
44 | - * @var Conf |
|
45 | - */ |
|
46 | - protected $config; |
|
47 | - |
|
48 | - /** |
|
49 | - * @var Database |
|
50 | - */ |
|
51 | - protected $db; |
|
52 | - |
|
53 | - /** |
|
54 | - * @var string |
|
55 | - */ |
|
56 | - protected $table; |
|
57 | - |
|
58 | - /** |
|
59 | - * @var SubtypeTable |
|
60 | - */ |
|
61 | - protected $subtype_table; |
|
62 | - |
|
63 | - /** |
|
64 | - * @var EntityCache |
|
65 | - */ |
|
66 | - protected $entity_cache; |
|
67 | - |
|
68 | - /** |
|
69 | - * @var EntityPreloader |
|
70 | - */ |
|
71 | - protected $entity_preloader; |
|
72 | - |
|
73 | - /** |
|
74 | - * @var MetadataCache |
|
75 | - */ |
|
76 | - protected $metadata_cache; |
|
77 | - |
|
78 | - /** |
|
79 | - * @var EventsService |
|
80 | - */ |
|
81 | - protected $events; |
|
82 | - |
|
83 | - /** |
|
84 | - * @var ElggSession |
|
85 | - */ |
|
86 | - protected $session; |
|
87 | - |
|
88 | - /** |
|
89 | - * @var Translator |
|
90 | - */ |
|
91 | - protected $translator; |
|
92 | - |
|
93 | - /** |
|
94 | - * @var Logger |
|
95 | - */ |
|
96 | - protected $logger; |
|
97 | - |
|
98 | - /** |
|
99 | - * Constructor |
|
100 | - * |
|
101 | - * @param Conf $config Config |
|
102 | - * @param Database $db Database |
|
103 | - * @param EntityCache $entity_cache Entity cache |
|
104 | - * @param MetadataCache $metadata_cache Metadata cache |
|
105 | - * @param SubtypeTable $subtype_table Subtype table |
|
106 | - * @param EventsService $events Events service |
|
107 | - * @param ElggSession $session Session |
|
108 | - * @param Translator $translator Translator |
|
109 | - * @param Logger $logger Logger |
|
110 | - */ |
|
111 | - public function __construct( |
|
112 | - Conf $config, |
|
113 | - Database $db, |
|
114 | - EntityCache $entity_cache, |
|
115 | - MetadataCache $metadata_cache, |
|
116 | - SubtypeTable $subtype_table, |
|
117 | - EventsService $events, |
|
118 | - ElggSession $session, |
|
119 | - Translator $translator, |
|
120 | - Logger $logger |
|
121 | - ) { |
|
122 | - $this->config = $config; |
|
123 | - $this->db = $db; |
|
124 | - $this->table = $this->db->prefix . 'entities'; |
|
125 | - $this->entity_cache = $entity_cache; |
|
126 | - $this->metadata_cache = $metadata_cache; |
|
127 | - $this->subtype_table = $subtype_table; |
|
128 | - $this->events = $events; |
|
129 | - $this->session = $session; |
|
130 | - $this->translator = $translator; |
|
131 | - $this->logger = $logger; |
|
132 | - } |
|
133 | - |
|
134 | - /** |
|
135 | - * Returns a database row from the entities table. |
|
136 | - * |
|
137 | - * @see entity_row_to_elggstar() |
|
138 | - * |
|
139 | - * @tip Use get_entity() to return the fully loaded entity. |
|
140 | - * |
|
141 | - * @warning This will only return results if a) it exists, b) you have access to it. |
|
142 | - * see {@link _elgg_get_access_where_sql()}. |
|
143 | - * |
|
144 | - * @param int $guid The GUID of the object to extract |
|
145 | - * @param int $user_guid GUID of the user accessing the row |
|
146 | - * Defaults to logged in user if null |
|
147 | - * Builds an access query for a logged out user if 0 |
|
148 | - * @return stdClass|false |
|
149 | - * @access private |
|
150 | - */ |
|
151 | - public function getRow($guid, $user_guid = null) { |
|
152 | - |
|
153 | - if (!$guid) { |
|
154 | - return false; |
|
155 | - } |
|
156 | - |
|
157 | - $access = _elgg_get_access_where_sql([ |
|
158 | - 'table_alias' => '', |
|
159 | - 'user_guid' => $user_guid, |
|
160 | - ]); |
|
161 | - |
|
162 | - $sql = "SELECT * FROM {$this->db->prefix}entities |
|
43 | + /** |
|
44 | + * @var Conf |
|
45 | + */ |
|
46 | + protected $config; |
|
47 | + |
|
48 | + /** |
|
49 | + * @var Database |
|
50 | + */ |
|
51 | + protected $db; |
|
52 | + |
|
53 | + /** |
|
54 | + * @var string |
|
55 | + */ |
|
56 | + protected $table; |
|
57 | + |
|
58 | + /** |
|
59 | + * @var SubtypeTable |
|
60 | + */ |
|
61 | + protected $subtype_table; |
|
62 | + |
|
63 | + /** |
|
64 | + * @var EntityCache |
|
65 | + */ |
|
66 | + protected $entity_cache; |
|
67 | + |
|
68 | + /** |
|
69 | + * @var EntityPreloader |
|
70 | + */ |
|
71 | + protected $entity_preloader; |
|
72 | + |
|
73 | + /** |
|
74 | + * @var MetadataCache |
|
75 | + */ |
|
76 | + protected $metadata_cache; |
|
77 | + |
|
78 | + /** |
|
79 | + * @var EventsService |
|
80 | + */ |
|
81 | + protected $events; |
|
82 | + |
|
83 | + /** |
|
84 | + * @var ElggSession |
|
85 | + */ |
|
86 | + protected $session; |
|
87 | + |
|
88 | + /** |
|
89 | + * @var Translator |
|
90 | + */ |
|
91 | + protected $translator; |
|
92 | + |
|
93 | + /** |
|
94 | + * @var Logger |
|
95 | + */ |
|
96 | + protected $logger; |
|
97 | + |
|
98 | + /** |
|
99 | + * Constructor |
|
100 | + * |
|
101 | + * @param Conf $config Config |
|
102 | + * @param Database $db Database |
|
103 | + * @param EntityCache $entity_cache Entity cache |
|
104 | + * @param MetadataCache $metadata_cache Metadata cache |
|
105 | + * @param SubtypeTable $subtype_table Subtype table |
|
106 | + * @param EventsService $events Events service |
|
107 | + * @param ElggSession $session Session |
|
108 | + * @param Translator $translator Translator |
|
109 | + * @param Logger $logger Logger |
|
110 | + */ |
|
111 | + public function __construct( |
|
112 | + Conf $config, |
|
113 | + Database $db, |
|
114 | + EntityCache $entity_cache, |
|
115 | + MetadataCache $metadata_cache, |
|
116 | + SubtypeTable $subtype_table, |
|
117 | + EventsService $events, |
|
118 | + ElggSession $session, |
|
119 | + Translator $translator, |
|
120 | + Logger $logger |
|
121 | + ) { |
|
122 | + $this->config = $config; |
|
123 | + $this->db = $db; |
|
124 | + $this->table = $this->db->prefix . 'entities'; |
|
125 | + $this->entity_cache = $entity_cache; |
|
126 | + $this->metadata_cache = $metadata_cache; |
|
127 | + $this->subtype_table = $subtype_table; |
|
128 | + $this->events = $events; |
|
129 | + $this->session = $session; |
|
130 | + $this->translator = $translator; |
|
131 | + $this->logger = $logger; |
|
132 | + } |
|
133 | + |
|
134 | + /** |
|
135 | + * Returns a database row from the entities table. |
|
136 | + * |
|
137 | + * @see entity_row_to_elggstar() |
|
138 | + * |
|
139 | + * @tip Use get_entity() to return the fully loaded entity. |
|
140 | + * |
|
141 | + * @warning This will only return results if a) it exists, b) you have access to it. |
|
142 | + * see {@link _elgg_get_access_where_sql()}. |
|
143 | + * |
|
144 | + * @param int $guid The GUID of the object to extract |
|
145 | + * @param int $user_guid GUID of the user accessing the row |
|
146 | + * Defaults to logged in user if null |
|
147 | + * Builds an access query for a logged out user if 0 |
|
148 | + * @return stdClass|false |
|
149 | + * @access private |
|
150 | + */ |
|
151 | + public function getRow($guid, $user_guid = null) { |
|
152 | + |
|
153 | + if (!$guid) { |
|
154 | + return false; |
|
155 | + } |
|
156 | + |
|
157 | + $access = _elgg_get_access_where_sql([ |
|
158 | + 'table_alias' => '', |
|
159 | + 'user_guid' => $user_guid, |
|
160 | + ]); |
|
161 | + |
|
162 | + $sql = "SELECT * FROM {$this->db->prefix}entities |
|
163 | 163 | WHERE guid = :guid AND $access"; |
164 | 164 | |
165 | - $params = [ |
|
166 | - ':guid' => (int) $guid, |
|
167 | - ]; |
|
168 | - |
|
169 | - return $this->db->getDataRow($sql, null, $params); |
|
170 | - } |
|
171 | - |
|
172 | - /** |
|
173 | - * Adds a new row to the entity table |
|
174 | - * |
|
175 | - * @param stdClass $row Entity base information |
|
176 | - * @param array $attributes All primary and secondary table attributes |
|
177 | - * Used by database mock services to allow mocking |
|
178 | - * entities that were instantiated using new keyword |
|
179 | - * and calling ElggEntity::save() |
|
180 | - * @return int|false |
|
181 | - */ |
|
182 | - public function insertRow(stdClass $row, array $attributes = []) { |
|
183 | - |
|
184 | - $sql = "INSERT INTO {$this->db->prefix}entities |
|
165 | + $params = [ |
|
166 | + ':guid' => (int) $guid, |
|
167 | + ]; |
|
168 | + |
|
169 | + return $this->db->getDataRow($sql, null, $params); |
|
170 | + } |
|
171 | + |
|
172 | + /** |
|
173 | + * Adds a new row to the entity table |
|
174 | + * |
|
175 | + * @param stdClass $row Entity base information |
|
176 | + * @param array $attributes All primary and secondary table attributes |
|
177 | + * Used by database mock services to allow mocking |
|
178 | + * entities that were instantiated using new keyword |
|
179 | + * and calling ElggEntity::save() |
|
180 | + * @return int|false |
|
181 | + */ |
|
182 | + public function insertRow(stdClass $row, array $attributes = []) { |
|
183 | + |
|
184 | + $sql = "INSERT INTO {$this->db->prefix}entities |
|
185 | 185 | (type, subtype, owner_guid, container_guid, |
186 | 186 | access_id, time_created, time_updated, last_action) |
187 | 187 | VALUES |
188 | 188 | (:type, :subtype_id, :owner_guid, :container_guid, |
189 | 189 | :access_id, :time_created, :time_updated, :last_action)"; |
190 | 190 | |
191 | - return $this->db->insertData($sql, [ |
|
192 | - ':type' => $row->type, |
|
193 | - ':subtype_id' => $row->subtype_id, |
|
194 | - ':owner_guid' => $row->owner_guid, |
|
195 | - ':container_guid' => $row->container_guid, |
|
196 | - ':access_id' => $row->access_id, |
|
197 | - ':time_created' => $row->time_created, |
|
198 | - ':time_updated' => $row->time_updated, |
|
199 | - ':last_action' => $row->last_action, |
|
200 | - ]); |
|
201 | - } |
|
202 | - |
|
203 | - /** |
|
204 | - * Update entity table row |
|
205 | - * |
|
206 | - * @param int $guid Entity guid |
|
207 | - * @param stdClass $row Updated data |
|
208 | - * @return int|false |
|
209 | - */ |
|
210 | - public function updateRow($guid, stdClass $row) { |
|
211 | - $sql = " |
|
191 | + return $this->db->insertData($sql, [ |
|
192 | + ':type' => $row->type, |
|
193 | + ':subtype_id' => $row->subtype_id, |
|
194 | + ':owner_guid' => $row->owner_guid, |
|
195 | + ':container_guid' => $row->container_guid, |
|
196 | + ':access_id' => $row->access_id, |
|
197 | + ':time_created' => $row->time_created, |
|
198 | + ':time_updated' => $row->time_updated, |
|
199 | + ':last_action' => $row->last_action, |
|
200 | + ]); |
|
201 | + } |
|
202 | + |
|
203 | + /** |
|
204 | + * Update entity table row |
|
205 | + * |
|
206 | + * @param int $guid Entity guid |
|
207 | + * @param stdClass $row Updated data |
|
208 | + * @return int|false |
|
209 | + */ |
|
210 | + public function updateRow($guid, stdClass $row) { |
|
211 | + $sql = " |
|
212 | 212 | UPDATE {$this->db->prefix}entities |
213 | 213 | SET owner_guid = :owner_guid, |
214 | 214 | access_id = :access_id, |
@@ -218,1280 +218,1280 @@ discard block |
||
218 | 218 | WHERE guid = :guid |
219 | 219 | "; |
220 | 220 | |
221 | - $params = [ |
|
222 | - ':owner_guid' => $row->owner_guid, |
|
223 | - ':access_id' => $row->access_id, |
|
224 | - ':container_guid' => $row->container_guid, |
|
225 | - ':time_created' => $row->time_created, |
|
226 | - ':time_updated' => $row->time_updated, |
|
227 | - ':guid' => $guid, |
|
228 | - ]; |
|
229 | - |
|
230 | - return $this->db->updateData($sql, false, $params); |
|
231 | - } |
|
232 | - |
|
233 | - /** |
|
234 | - * Create an Elgg* object from a given entity row. |
|
235 | - * |
|
236 | - * Handles loading all tables into the correct class. |
|
237 | - * |
|
238 | - * @see get_entity_as_row() |
|
239 | - * @see add_subtype() |
|
240 | - * @see get_entity() |
|
241 | - * |
|
242 | - * @access private |
|
243 | - * |
|
244 | - * @param stdClass $row The row of the entry in the entities table. |
|
245 | - * @return ElggEntity|false |
|
246 | - * @throws ClassException |
|
247 | - * @throws InstallationException |
|
248 | - */ |
|
249 | - public function rowToElggStar($row) { |
|
250 | - if (!$row instanceof stdClass) { |
|
251 | - return $row; |
|
252 | - } |
|
253 | - |
|
254 | - if (!isset($row->guid) || !isset($row->subtype)) { |
|
255 | - return $row; |
|
256 | - } |
|
221 | + $params = [ |
|
222 | + ':owner_guid' => $row->owner_guid, |
|
223 | + ':access_id' => $row->access_id, |
|
224 | + ':container_guid' => $row->container_guid, |
|
225 | + ':time_created' => $row->time_created, |
|
226 | + ':time_updated' => $row->time_updated, |
|
227 | + ':guid' => $guid, |
|
228 | + ]; |
|
229 | + |
|
230 | + return $this->db->updateData($sql, false, $params); |
|
231 | + } |
|
232 | + |
|
233 | + /** |
|
234 | + * Create an Elgg* object from a given entity row. |
|
235 | + * |
|
236 | + * Handles loading all tables into the correct class. |
|
237 | + * |
|
238 | + * @see get_entity_as_row() |
|
239 | + * @see add_subtype() |
|
240 | + * @see get_entity() |
|
241 | + * |
|
242 | + * @access private |
|
243 | + * |
|
244 | + * @param stdClass $row The row of the entry in the entities table. |
|
245 | + * @return ElggEntity|false |
|
246 | + * @throws ClassException |
|
247 | + * @throws InstallationException |
|
248 | + */ |
|
249 | + public function rowToElggStar($row) { |
|
250 | + if (!$row instanceof stdClass) { |
|
251 | + return $row; |
|
252 | + } |
|
253 | + |
|
254 | + if (!isset($row->guid) || !isset($row->subtype)) { |
|
255 | + return $row; |
|
256 | + } |
|
257 | 257 | |
258 | - $class_name = $this->subtype_table->getClassFromId($row->subtype); |
|
259 | - if ($class_name && !class_exists($class_name)) { |
|
260 | - $this->logger->error("Class '$class_name' was not found, missing plugin?"); |
|
261 | - $class_name = ''; |
|
262 | - } |
|
263 | - |
|
264 | - if (!$class_name) { |
|
265 | - $map = [ |
|
266 | - 'object' => ElggObject::class, |
|
267 | - 'user' => ElggUser::class, |
|
268 | - 'group' => ElggGroup::class, |
|
269 | - 'site' => ElggSite::class, |
|
270 | - ]; |
|
271 | - |
|
272 | - if (isset($map[$row->type])) { |
|
273 | - $class_name = $map[$row->type]; |
|
274 | - } else { |
|
275 | - throw new InstallationException("Entity type {$row->type} is not supported."); |
|
276 | - } |
|
277 | - } |
|
278 | - |
|
279 | - $entity = new $class_name($row); |
|
280 | - if (!$entity instanceof ElggEntity) { |
|
281 | - throw new ClassException("$class_name must extend " . ElggEntity::class); |
|
282 | - } |
|
283 | - |
|
284 | - return $entity; |
|
285 | - } |
|
286 | - |
|
287 | - /** |
|
288 | - * Get an entity from the in-memory or memcache caches |
|
289 | - * |
|
290 | - * @param int $guid GUID |
|
291 | - * |
|
292 | - * @return \ElggEntity |
|
293 | - */ |
|
294 | - protected function getFromCache($guid) { |
|
295 | - $entity = $this->entity_cache->get($guid); |
|
296 | - if ($entity) { |
|
297 | - return $entity; |
|
298 | - } |
|
299 | - |
|
300 | - $memcache = _elgg_get_memcache('new_entity_cache'); |
|
301 | - $entity = $memcache->load($guid); |
|
302 | - if (!$entity instanceof ElggEntity) { |
|
303 | - return false; |
|
304 | - } |
|
305 | - |
|
306 | - // Validate accessibility if from memcache |
|
307 | - if (!elgg_get_ignore_access() && !has_access_to_entity($entity)) { |
|
308 | - return false; |
|
309 | - } |
|
310 | - |
|
311 | - $this->entity_cache->set($entity); |
|
312 | - return $entity; |
|
313 | - } |
|
314 | - |
|
315 | - /** |
|
316 | - * Loads and returns an entity object from a guid. |
|
317 | - * |
|
318 | - * @param int $guid The GUID of the entity |
|
319 | - * @param string $type The type of the entity. If given, even an existing entity with the given GUID |
|
320 | - * will not be returned unless its type matches. |
|
321 | - * |
|
322 | - * @return ElggEntity|stdClass|false The correct Elgg or custom object based upon entity type and subtype |
|
323 | - * @throws ClassException |
|
324 | - * @throws InstallationException |
|
325 | - */ |
|
326 | - public function get($guid, $type = '') { |
|
327 | - // We could also use: if (!(int) $guid) { return false }, |
|
328 | - // but that evaluates to a false positive for $guid = true. |
|
329 | - // This is a bit slower, but more thorough. |
|
330 | - if (!is_numeric($guid) || $guid === 0 || $guid === '0') { |
|
331 | - return false; |
|
332 | - } |
|
333 | - |
|
334 | - $guid = (int) $guid; |
|
335 | - |
|
336 | - $entity = $this->getFromCache($guid); |
|
337 | - if ($entity && (!$type || elgg_instanceof($entity, $type))) { |
|
338 | - return $entity; |
|
339 | - } |
|
340 | - |
|
341 | - $row = $this->getRow($guid); |
|
342 | - if (!$row) { |
|
343 | - return false; |
|
344 | - } |
|
345 | - |
|
346 | - if ($type && $row->type != $type) { |
|
347 | - return false; |
|
348 | - } |
|
349 | - |
|
350 | - $entity = $this->rowToElggStar($row); |
|
351 | - |
|
352 | - if ($entity instanceof ElggEntity) { |
|
353 | - $entity->storeInPersistedCache(_elgg_get_memcache('new_entity_cache')); |
|
354 | - } |
|
355 | - |
|
356 | - return $entity; |
|
357 | - } |
|
358 | - |
|
359 | - /** |
|
360 | - * Does an entity exist? |
|
361 | - * |
|
362 | - * This function checks for the existence of an entity independent of access |
|
363 | - * permissions. It is useful for situations when a user cannot access an entity |
|
364 | - * and it must be determined whether entity has been deleted or the access level |
|
365 | - * has changed. |
|
366 | - * |
|
367 | - * @param int $guid The GUID of the entity |
|
368 | - * @return bool |
|
369 | - */ |
|
370 | - public function exists($guid) { |
|
371 | - |
|
372 | - // need to ignore access and show hidden entities to check existence |
|
373 | - $ia = $this->session->setIgnoreAccess(true); |
|
374 | - $show_hidden = access_show_hidden_entities(true); |
|
375 | - |
|
376 | - $result = $this->getRow($guid); |
|
377 | - |
|
378 | - $this->session->setIgnoreAccess($ia); |
|
379 | - access_show_hidden_entities($show_hidden); |
|
380 | - |
|
381 | - return !empty($result); |
|
382 | - } |
|
383 | - |
|
384 | - /** |
|
385 | - * Enable an entity. |
|
386 | - * |
|
387 | - * @param int $guid GUID of entity to enable |
|
388 | - * @param bool $recursive Recursively enable all entities disabled with the entity? |
|
389 | - * @return bool |
|
390 | - */ |
|
391 | - public function enable($guid, $recursive = true) { |
|
392 | - |
|
393 | - // Override access only visible entities |
|
394 | - $old_access_status = access_get_show_hidden_status(); |
|
395 | - access_show_hidden_entities(true); |
|
396 | - |
|
397 | - $result = false; |
|
398 | - $entity = get_entity($guid); |
|
399 | - if ($entity) { |
|
400 | - $result = $entity->enable($recursive); |
|
401 | - } |
|
402 | - |
|
403 | - access_show_hidden_entities($old_access_status); |
|
404 | - return $result; |
|
405 | - } |
|
406 | - |
|
407 | - /** |
|
408 | - * Returns an array of entities with optional filtering. |
|
409 | - * |
|
410 | - * Entities are the basic unit of storage in Elgg. This function |
|
411 | - * provides the simplest way to get an array of entities. There |
|
412 | - * are many options available that can be passed to filter |
|
413 | - * what sorts of entities are returned. |
|
414 | - * |
|
415 | - * @tip To output formatted strings of entities, use {@link elgg_list_entities()} and |
|
416 | - * its cousins. |
|
417 | - * |
|
418 | - * @tip Plural arguments can be written as singular if only specifying a |
|
419 | - * single element. ('type' => 'object' vs 'types' => array('object')). |
|
420 | - * |
|
421 | - * @see elgg_get_entities_from_metadata() |
|
422 | - * @see elgg_get_entities_from_relationship() |
|
423 | - * @see elgg_get_entities_from_access_id() |
|
424 | - * @see elgg_get_entities_from_annotations() |
|
425 | - * @see elgg_list_entities() |
|
426 | - * |
|
427 | - * @param array $options Array in format: |
|
428 | - * |
|
429 | - * types => null|STR entity type (type IN ('type1', 'type2') |
|
430 | - * Joined with subtypes by AND. See below) |
|
431 | - * |
|
432 | - * subtypes => null|STR entity subtype (SQL: subtype IN ('subtype1', 'subtype2)) |
|
433 | - * Use ELGG_ENTITIES_NO_VALUE to match the default subtype. |
|
434 | - * Use ELGG_ENTITIES_ANY_VALUE to match any subtype. |
|
435 | - * |
|
436 | - * type_subtype_pairs => null|ARR (array('type' => 'subtype')) |
|
437 | - * array( |
|
438 | - * 'object' => array('blog', 'file'), // All objects with subtype of 'blog' or 'file' |
|
439 | - * 'user' => ELGG_ENTITY_ANY_VALUE, // All users irrespective of subtype |
|
440 | - * ); |
|
441 | - * |
|
442 | - * guids => null|ARR Array of entity guids |
|
443 | - * |
|
444 | - * owner_guids => null|ARR Array of owner guids |
|
445 | - * |
|
446 | - * container_guids => null|ARR Array of container_guids |
|
447 | - * |
|
448 | - * order_by => null (time_created desc)|STR SQL order by clause |
|
449 | - * |
|
450 | - * reverse_order_by => BOOL Reverse the default order by clause |
|
451 | - * |
|
452 | - * limit => null (10)|INT SQL limit clause (0 means no limit) |
|
453 | - * |
|
454 | - * offset => null (0)|INT SQL offset clause |
|
455 | - * |
|
456 | - * created_time_lower => null|INT Created time lower boundary in epoch time |
|
457 | - * |
|
458 | - * created_time_upper => null|INT Created time upper boundary in epoch time |
|
459 | - * |
|
460 | - * modified_time_lower => null|INT Modified time lower boundary in epoch time |
|
461 | - * |
|
462 | - * modified_time_upper => null|INT Modified time upper boundary in epoch time |
|
463 | - * |
|
464 | - * count => true|false return a count instead of entities |
|
465 | - * |
|
466 | - * wheres => array() Additional where clauses to AND together |
|
467 | - * |
|
468 | - * joins => array() Additional joins |
|
469 | - * |
|
470 | - * preload_owners => bool (false) If set to true, this function will preload |
|
471 | - * all the owners of the returned entities resulting in better |
|
472 | - * performance if those owners need to be displayed |
|
473 | - * |
|
474 | - * preload_containers => bool (false) If set to true, this function will preload |
|
475 | - * all the containers of the returned entities resulting in better |
|
476 | - * performance if those containers need to be displayed |
|
477 | - * |
|
478 | - * |
|
479 | - * callback => string A callback function to pass each row through |
|
480 | - * |
|
481 | - * distinct => bool (true) If set to false, Elgg will drop the DISTINCT clause from |
|
482 | - * the MySQL query, which will improve performance in some situations. |
|
483 | - * Avoid setting this option without a full understanding of the underlying |
|
484 | - * SQL query Elgg creates. |
|
485 | - * |
|
486 | - * batch => bool (false) If set to true, an Elgg\BatchResult object will be returned instead of an array. |
|
487 | - * Since 2.3 |
|
488 | - * |
|
489 | - * batch_inc_offset => bool (true) If "batch" is used, this tells the batch to increment the offset |
|
490 | - * on each fetch. This must be set to false if you delete the batched results. |
|
491 | - * |
|
492 | - * batch_size => int (25) If "batch" is used, this is the number of entities/rows to pull in before |
|
493 | - * requesting more. |
|
494 | - * |
|
495 | - * @return \ElggEntity[]|int|mixed If count, int. Otherwise an array or an Elgg\BatchResult. false on errors. |
|
496 | - * |
|
497 | - * @see elgg_get_entities_from_metadata() |
|
498 | - * @see elgg_get_entities_from_relationship() |
|
499 | - * @see elgg_get_entities_from_access_id() |
|
500 | - * @see elgg_get_entities_from_annotations() |
|
501 | - * @see elgg_list_entities() |
|
502 | - */ |
|
503 | - public function getEntities(array $options = []) { |
|
504 | - _elgg_check_unsupported_site_guid($options); |
|
505 | - |
|
506 | - $defaults = [ |
|
507 | - 'types' => ELGG_ENTITIES_ANY_VALUE, |
|
508 | - 'subtypes' => ELGG_ENTITIES_ANY_VALUE, |
|
509 | - 'type_subtype_pairs' => ELGG_ENTITIES_ANY_VALUE, |
|
510 | - |
|
511 | - 'guids' => ELGG_ENTITIES_ANY_VALUE, |
|
512 | - 'owner_guids' => ELGG_ENTITIES_ANY_VALUE, |
|
513 | - 'container_guids' => ELGG_ENTITIES_ANY_VALUE, |
|
514 | - |
|
515 | - 'modified_time_lower' => ELGG_ENTITIES_ANY_VALUE, |
|
516 | - 'modified_time_upper' => ELGG_ENTITIES_ANY_VALUE, |
|
517 | - 'created_time_lower' => ELGG_ENTITIES_ANY_VALUE, |
|
518 | - 'created_time_upper' => ELGG_ENTITIES_ANY_VALUE, |
|
519 | - |
|
520 | - 'reverse_order_by' => false, |
|
521 | - 'order_by' => 'e.time_created desc', |
|
522 | - 'group_by' => ELGG_ENTITIES_ANY_VALUE, |
|
523 | - 'limit' => $this->config->default_limit, |
|
524 | - 'offset' => 0, |
|
525 | - 'count' => false, |
|
526 | - 'selects' => [], |
|
527 | - 'wheres' => [], |
|
528 | - 'joins' => [], |
|
529 | - |
|
530 | - 'preload_owners' => false, |
|
531 | - 'preload_containers' => false, |
|
532 | - 'callback' => 'entity_row_to_elggstar', |
|
533 | - 'distinct' => true, |
|
534 | - |
|
535 | - 'batch' => false, |
|
536 | - 'batch_inc_offset' => true, |
|
537 | - 'batch_size' => 25, |
|
538 | - |
|
539 | - // private API |
|
540 | - '__ElggBatch' => null, |
|
541 | - ]; |
|
542 | - |
|
543 | - $options = array_merge($defaults, $options); |
|
544 | - |
|
545 | - if ($options['batch'] && !$options['count']) { |
|
546 | - $batch_size = $options['batch_size']; |
|
547 | - $batch_inc_offset = $options['batch_inc_offset']; |
|
548 | - |
|
549 | - // clean batch keys from $options. |
|
550 | - unset($options['batch'], $options['batch_size'], $options['batch_inc_offset']); |
|
551 | - |
|
552 | - return new \ElggBatch([$this, 'getEntities'], $options, null, $batch_size, $batch_inc_offset); |
|
553 | - } |
|
258 | + $class_name = $this->subtype_table->getClassFromId($row->subtype); |
|
259 | + if ($class_name && !class_exists($class_name)) { |
|
260 | + $this->logger->error("Class '$class_name' was not found, missing plugin?"); |
|
261 | + $class_name = ''; |
|
262 | + } |
|
263 | + |
|
264 | + if (!$class_name) { |
|
265 | + $map = [ |
|
266 | + 'object' => ElggObject::class, |
|
267 | + 'user' => ElggUser::class, |
|
268 | + 'group' => ElggGroup::class, |
|
269 | + 'site' => ElggSite::class, |
|
270 | + ]; |
|
271 | + |
|
272 | + if (isset($map[$row->type])) { |
|
273 | + $class_name = $map[$row->type]; |
|
274 | + } else { |
|
275 | + throw new InstallationException("Entity type {$row->type} is not supported."); |
|
276 | + } |
|
277 | + } |
|
278 | + |
|
279 | + $entity = new $class_name($row); |
|
280 | + if (!$entity instanceof ElggEntity) { |
|
281 | + throw new ClassException("$class_name must extend " . ElggEntity::class); |
|
282 | + } |
|
283 | + |
|
284 | + return $entity; |
|
285 | + } |
|
286 | + |
|
287 | + /** |
|
288 | + * Get an entity from the in-memory or memcache caches |
|
289 | + * |
|
290 | + * @param int $guid GUID |
|
291 | + * |
|
292 | + * @return \ElggEntity |
|
293 | + */ |
|
294 | + protected function getFromCache($guid) { |
|
295 | + $entity = $this->entity_cache->get($guid); |
|
296 | + if ($entity) { |
|
297 | + return $entity; |
|
298 | + } |
|
299 | + |
|
300 | + $memcache = _elgg_get_memcache('new_entity_cache'); |
|
301 | + $entity = $memcache->load($guid); |
|
302 | + if (!$entity instanceof ElggEntity) { |
|
303 | + return false; |
|
304 | + } |
|
305 | + |
|
306 | + // Validate accessibility if from memcache |
|
307 | + if (!elgg_get_ignore_access() && !has_access_to_entity($entity)) { |
|
308 | + return false; |
|
309 | + } |
|
310 | + |
|
311 | + $this->entity_cache->set($entity); |
|
312 | + return $entity; |
|
313 | + } |
|
314 | + |
|
315 | + /** |
|
316 | + * Loads and returns an entity object from a guid. |
|
317 | + * |
|
318 | + * @param int $guid The GUID of the entity |
|
319 | + * @param string $type The type of the entity. If given, even an existing entity with the given GUID |
|
320 | + * will not be returned unless its type matches. |
|
321 | + * |
|
322 | + * @return ElggEntity|stdClass|false The correct Elgg or custom object based upon entity type and subtype |
|
323 | + * @throws ClassException |
|
324 | + * @throws InstallationException |
|
325 | + */ |
|
326 | + public function get($guid, $type = '') { |
|
327 | + // We could also use: if (!(int) $guid) { return false }, |
|
328 | + // but that evaluates to a false positive for $guid = true. |
|
329 | + // This is a bit slower, but more thorough. |
|
330 | + if (!is_numeric($guid) || $guid === 0 || $guid === '0') { |
|
331 | + return false; |
|
332 | + } |
|
333 | + |
|
334 | + $guid = (int) $guid; |
|
335 | + |
|
336 | + $entity = $this->getFromCache($guid); |
|
337 | + if ($entity && (!$type || elgg_instanceof($entity, $type))) { |
|
338 | + return $entity; |
|
339 | + } |
|
340 | + |
|
341 | + $row = $this->getRow($guid); |
|
342 | + if (!$row) { |
|
343 | + return false; |
|
344 | + } |
|
345 | + |
|
346 | + if ($type && $row->type != $type) { |
|
347 | + return false; |
|
348 | + } |
|
349 | + |
|
350 | + $entity = $this->rowToElggStar($row); |
|
351 | + |
|
352 | + if ($entity instanceof ElggEntity) { |
|
353 | + $entity->storeInPersistedCache(_elgg_get_memcache('new_entity_cache')); |
|
354 | + } |
|
355 | + |
|
356 | + return $entity; |
|
357 | + } |
|
358 | + |
|
359 | + /** |
|
360 | + * Does an entity exist? |
|
361 | + * |
|
362 | + * This function checks for the existence of an entity independent of access |
|
363 | + * permissions. It is useful for situations when a user cannot access an entity |
|
364 | + * and it must be determined whether entity has been deleted or the access level |
|
365 | + * has changed. |
|
366 | + * |
|
367 | + * @param int $guid The GUID of the entity |
|
368 | + * @return bool |
|
369 | + */ |
|
370 | + public function exists($guid) { |
|
371 | + |
|
372 | + // need to ignore access and show hidden entities to check existence |
|
373 | + $ia = $this->session->setIgnoreAccess(true); |
|
374 | + $show_hidden = access_show_hidden_entities(true); |
|
375 | + |
|
376 | + $result = $this->getRow($guid); |
|
377 | + |
|
378 | + $this->session->setIgnoreAccess($ia); |
|
379 | + access_show_hidden_entities($show_hidden); |
|
380 | + |
|
381 | + return !empty($result); |
|
382 | + } |
|
383 | + |
|
384 | + /** |
|
385 | + * Enable an entity. |
|
386 | + * |
|
387 | + * @param int $guid GUID of entity to enable |
|
388 | + * @param bool $recursive Recursively enable all entities disabled with the entity? |
|
389 | + * @return bool |
|
390 | + */ |
|
391 | + public function enable($guid, $recursive = true) { |
|
392 | + |
|
393 | + // Override access only visible entities |
|
394 | + $old_access_status = access_get_show_hidden_status(); |
|
395 | + access_show_hidden_entities(true); |
|
396 | + |
|
397 | + $result = false; |
|
398 | + $entity = get_entity($guid); |
|
399 | + if ($entity) { |
|
400 | + $result = $entity->enable($recursive); |
|
401 | + } |
|
402 | + |
|
403 | + access_show_hidden_entities($old_access_status); |
|
404 | + return $result; |
|
405 | + } |
|
406 | + |
|
407 | + /** |
|
408 | + * Returns an array of entities with optional filtering. |
|
409 | + * |
|
410 | + * Entities are the basic unit of storage in Elgg. This function |
|
411 | + * provides the simplest way to get an array of entities. There |
|
412 | + * are many options available that can be passed to filter |
|
413 | + * what sorts of entities are returned. |
|
414 | + * |
|
415 | + * @tip To output formatted strings of entities, use {@link elgg_list_entities()} and |
|
416 | + * its cousins. |
|
417 | + * |
|
418 | + * @tip Plural arguments can be written as singular if only specifying a |
|
419 | + * single element. ('type' => 'object' vs 'types' => array('object')). |
|
420 | + * |
|
421 | + * @see elgg_get_entities_from_metadata() |
|
422 | + * @see elgg_get_entities_from_relationship() |
|
423 | + * @see elgg_get_entities_from_access_id() |
|
424 | + * @see elgg_get_entities_from_annotations() |
|
425 | + * @see elgg_list_entities() |
|
426 | + * |
|
427 | + * @param array $options Array in format: |
|
428 | + * |
|
429 | + * types => null|STR entity type (type IN ('type1', 'type2') |
|
430 | + * Joined with subtypes by AND. See below) |
|
431 | + * |
|
432 | + * subtypes => null|STR entity subtype (SQL: subtype IN ('subtype1', 'subtype2)) |
|
433 | + * Use ELGG_ENTITIES_NO_VALUE to match the default subtype. |
|
434 | + * Use ELGG_ENTITIES_ANY_VALUE to match any subtype. |
|
435 | + * |
|
436 | + * type_subtype_pairs => null|ARR (array('type' => 'subtype')) |
|
437 | + * array( |
|
438 | + * 'object' => array('blog', 'file'), // All objects with subtype of 'blog' or 'file' |
|
439 | + * 'user' => ELGG_ENTITY_ANY_VALUE, // All users irrespective of subtype |
|
440 | + * ); |
|
441 | + * |
|
442 | + * guids => null|ARR Array of entity guids |
|
443 | + * |
|
444 | + * owner_guids => null|ARR Array of owner guids |
|
445 | + * |
|
446 | + * container_guids => null|ARR Array of container_guids |
|
447 | + * |
|
448 | + * order_by => null (time_created desc)|STR SQL order by clause |
|
449 | + * |
|
450 | + * reverse_order_by => BOOL Reverse the default order by clause |
|
451 | + * |
|
452 | + * limit => null (10)|INT SQL limit clause (0 means no limit) |
|
453 | + * |
|
454 | + * offset => null (0)|INT SQL offset clause |
|
455 | + * |
|
456 | + * created_time_lower => null|INT Created time lower boundary in epoch time |
|
457 | + * |
|
458 | + * created_time_upper => null|INT Created time upper boundary in epoch time |
|
459 | + * |
|
460 | + * modified_time_lower => null|INT Modified time lower boundary in epoch time |
|
461 | + * |
|
462 | + * modified_time_upper => null|INT Modified time upper boundary in epoch time |
|
463 | + * |
|
464 | + * count => true|false return a count instead of entities |
|
465 | + * |
|
466 | + * wheres => array() Additional where clauses to AND together |
|
467 | + * |
|
468 | + * joins => array() Additional joins |
|
469 | + * |
|
470 | + * preload_owners => bool (false) If set to true, this function will preload |
|
471 | + * all the owners of the returned entities resulting in better |
|
472 | + * performance if those owners need to be displayed |
|
473 | + * |
|
474 | + * preload_containers => bool (false) If set to true, this function will preload |
|
475 | + * all the containers of the returned entities resulting in better |
|
476 | + * performance if those containers need to be displayed |
|
477 | + * |
|
478 | + * |
|
479 | + * callback => string A callback function to pass each row through |
|
480 | + * |
|
481 | + * distinct => bool (true) If set to false, Elgg will drop the DISTINCT clause from |
|
482 | + * the MySQL query, which will improve performance in some situations. |
|
483 | + * Avoid setting this option without a full understanding of the underlying |
|
484 | + * SQL query Elgg creates. |
|
485 | + * |
|
486 | + * batch => bool (false) If set to true, an Elgg\BatchResult object will be returned instead of an array. |
|
487 | + * Since 2.3 |
|
488 | + * |
|
489 | + * batch_inc_offset => bool (true) If "batch" is used, this tells the batch to increment the offset |
|
490 | + * on each fetch. This must be set to false if you delete the batched results. |
|
491 | + * |
|
492 | + * batch_size => int (25) If "batch" is used, this is the number of entities/rows to pull in before |
|
493 | + * requesting more. |
|
494 | + * |
|
495 | + * @return \ElggEntity[]|int|mixed If count, int. Otherwise an array or an Elgg\BatchResult. false on errors. |
|
496 | + * |
|
497 | + * @see elgg_get_entities_from_metadata() |
|
498 | + * @see elgg_get_entities_from_relationship() |
|
499 | + * @see elgg_get_entities_from_access_id() |
|
500 | + * @see elgg_get_entities_from_annotations() |
|
501 | + * @see elgg_list_entities() |
|
502 | + */ |
|
503 | + public function getEntities(array $options = []) { |
|
504 | + _elgg_check_unsupported_site_guid($options); |
|
505 | + |
|
506 | + $defaults = [ |
|
507 | + 'types' => ELGG_ENTITIES_ANY_VALUE, |
|
508 | + 'subtypes' => ELGG_ENTITIES_ANY_VALUE, |
|
509 | + 'type_subtype_pairs' => ELGG_ENTITIES_ANY_VALUE, |
|
510 | + |
|
511 | + 'guids' => ELGG_ENTITIES_ANY_VALUE, |
|
512 | + 'owner_guids' => ELGG_ENTITIES_ANY_VALUE, |
|
513 | + 'container_guids' => ELGG_ENTITIES_ANY_VALUE, |
|
514 | + |
|
515 | + 'modified_time_lower' => ELGG_ENTITIES_ANY_VALUE, |
|
516 | + 'modified_time_upper' => ELGG_ENTITIES_ANY_VALUE, |
|
517 | + 'created_time_lower' => ELGG_ENTITIES_ANY_VALUE, |
|
518 | + 'created_time_upper' => ELGG_ENTITIES_ANY_VALUE, |
|
519 | + |
|
520 | + 'reverse_order_by' => false, |
|
521 | + 'order_by' => 'e.time_created desc', |
|
522 | + 'group_by' => ELGG_ENTITIES_ANY_VALUE, |
|
523 | + 'limit' => $this->config->default_limit, |
|
524 | + 'offset' => 0, |
|
525 | + 'count' => false, |
|
526 | + 'selects' => [], |
|
527 | + 'wheres' => [], |
|
528 | + 'joins' => [], |
|
529 | + |
|
530 | + 'preload_owners' => false, |
|
531 | + 'preload_containers' => false, |
|
532 | + 'callback' => 'entity_row_to_elggstar', |
|
533 | + 'distinct' => true, |
|
534 | + |
|
535 | + 'batch' => false, |
|
536 | + 'batch_inc_offset' => true, |
|
537 | + 'batch_size' => 25, |
|
538 | + |
|
539 | + // private API |
|
540 | + '__ElggBatch' => null, |
|
541 | + ]; |
|
542 | + |
|
543 | + $options = array_merge($defaults, $options); |
|
544 | + |
|
545 | + if ($options['batch'] && !$options['count']) { |
|
546 | + $batch_size = $options['batch_size']; |
|
547 | + $batch_inc_offset = $options['batch_inc_offset']; |
|
548 | + |
|
549 | + // clean batch keys from $options. |
|
550 | + unset($options['batch'], $options['batch_size'], $options['batch_inc_offset']); |
|
551 | + |
|
552 | + return new \ElggBatch([$this, 'getEntities'], $options, null, $batch_size, $batch_inc_offset); |
|
553 | + } |
|
554 | 554 | |
555 | - // can't use helper function with type_subtype_pair because |
|
556 | - // it's already an array...just need to merge it |
|
557 | - if (isset($options['type_subtype_pair'])) { |
|
558 | - if (isset($options['type_subtype_pairs'])) { |
|
559 | - $options['type_subtype_pairs'] = array_merge($options['type_subtype_pairs'], |
|
560 | - $options['type_subtype_pair']); |
|
561 | - } else { |
|
562 | - $options['type_subtype_pairs'] = $options['type_subtype_pair']; |
|
563 | - } |
|
564 | - } |
|
565 | - |
|
566 | - $singulars = ['type', 'subtype', 'guid', 'owner_guid', 'container_guid']; |
|
567 | - $options = _elgg_normalize_plural_options_array($options, $singulars); |
|
568 | - |
|
569 | - $options = $this->autoJoinTables($options); |
|
570 | - |
|
571 | - // evaluate where clauses |
|
572 | - if (!is_array($options['wheres'])) { |
|
573 | - $options['wheres'] = [$options['wheres']]; |
|
574 | - } |
|
575 | - |
|
576 | - $wheres = $options['wheres']; |
|
577 | - |
|
578 | - $wheres[] = $this->getEntityTypeSubtypeWhereSql('e', $options['types'], |
|
579 | - $options['subtypes'], $options['type_subtype_pairs']); |
|
580 | - |
|
581 | - $wheres[] = $this->getGuidBasedWhereSql('e.guid', $options['guids']); |
|
582 | - $wheres[] = $this->getGuidBasedWhereSql('e.owner_guid', $options['owner_guids']); |
|
583 | - $wheres[] = $this->getGuidBasedWhereSql('e.container_guid', $options['container_guids']); |
|
584 | - |
|
585 | - $wheres[] = $this->getEntityTimeWhereSql('e', $options['created_time_upper'], |
|
586 | - $options['created_time_lower'], $options['modified_time_upper'], $options['modified_time_lower']); |
|
587 | - |
|
588 | - // see if any functions failed |
|
589 | - // remove empty strings on successful functions |
|
590 | - foreach ($wheres as $i => $where) { |
|
591 | - if ($where === false) { |
|
592 | - return false; |
|
593 | - } elseif (empty($where)) { |
|
594 | - unset($wheres[$i]); |
|
595 | - } |
|
596 | - } |
|
597 | - |
|
598 | - // remove identical where clauses |
|
599 | - $wheres = array_unique($wheres); |
|
600 | - |
|
601 | - // evaluate join clauses |
|
602 | - if (!is_array($options['joins'])) { |
|
603 | - $options['joins'] = [$options['joins']]; |
|
604 | - } |
|
605 | - |
|
606 | - // remove identical join clauses |
|
607 | - $joins = array_unique($options['joins']); |
|
608 | - |
|
609 | - foreach ($joins as $i => $join) { |
|
610 | - if ($join === false) { |
|
611 | - return false; |
|
612 | - } elseif (empty($join)) { |
|
613 | - unset($joins[$i]); |
|
614 | - } |
|
615 | - } |
|
616 | - |
|
617 | - // evalutate selects |
|
618 | - if ($options['selects']) { |
|
619 | - $selects = ''; |
|
620 | - foreach ($options['selects'] as $select) { |
|
621 | - $selects .= ", $select"; |
|
622 | - } |
|
623 | - } else { |
|
624 | - $selects = ''; |
|
625 | - } |
|
626 | - |
|
627 | - if (!$options['count']) { |
|
628 | - $distinct = $options['distinct'] ? "DISTINCT" : ""; |
|
629 | - $query = "SELECT $distinct e.*{$selects} FROM {$this->db->prefix}entities e "; |
|
630 | - } else { |
|
631 | - // note: when DISTINCT unneeded, it's slightly faster to compute COUNT(*) than GUIDs |
|
632 | - $count_expr = $options['distinct'] ? "DISTINCT e.guid" : "*"; |
|
633 | - $query = "SELECT COUNT($count_expr) as total FROM {$this->db->prefix}entities e "; |
|
634 | - } |
|
635 | - |
|
636 | - // add joins |
|
637 | - foreach ($joins as $j) { |
|
638 | - $query .= " $j "; |
|
639 | - } |
|
640 | - |
|
641 | - // add wheres |
|
642 | - $query .= ' WHERE '; |
|
643 | - |
|
644 | - foreach ($wheres as $w) { |
|
645 | - $query .= " $w AND "; |
|
646 | - } |
|
647 | - |
|
648 | - // Add access controls |
|
649 | - $query .= _elgg_get_access_where_sql(); |
|
650 | - |
|
651 | - // reverse order by |
|
652 | - if ($options['reverse_order_by']) { |
|
653 | - $options['order_by'] = _elgg_sql_reverse_order_by_clause($options['order_by']); |
|
654 | - } |
|
655 | - |
|
656 | - if ($options['count']) { |
|
657 | - $total = $this->db->getDataRow($query); |
|
658 | - return (int) $total->total; |
|
659 | - } |
|
660 | - |
|
661 | - if ($options['group_by']) { |
|
662 | - $query .= " GROUP BY {$options['group_by']}"; |
|
663 | - } |
|
664 | - |
|
665 | - if ($options['order_by']) { |
|
666 | - $query .= " ORDER BY {$options['order_by']}"; |
|
667 | - } |
|
668 | - |
|
669 | - if ($options['limit']) { |
|
670 | - $limit = sanitise_int($options['limit'], false); |
|
671 | - $offset = sanitise_int($options['offset'], false); |
|
672 | - $query .= " LIMIT $offset, $limit"; |
|
673 | - } |
|
674 | - |
|
675 | - if ($options['callback'] === 'entity_row_to_elggstar') { |
|
676 | - $results = $this->fetchFromSql($query, $options['__ElggBatch']); |
|
677 | - } else { |
|
678 | - $results = $this->db->getData($query, $options['callback']); |
|
679 | - } |
|
680 | - |
|
681 | - if (!$results) { |
|
682 | - // no results, no preloading |
|
683 | - return $results; |
|
684 | - } |
|
685 | - |
|
686 | - // populate entity and metadata caches, and prepare $entities for preloader |
|
687 | - $guids = []; |
|
688 | - foreach ($results as $item) { |
|
689 | - // A custom callback could result in items that aren't \ElggEntity's, so check for them |
|
690 | - if ($item instanceof ElggEntity) { |
|
691 | - $this->entity_cache->set($item); |
|
692 | - // plugins usually have only settings |
|
693 | - if (!$item instanceof ElggPlugin) { |
|
694 | - $guids[] = $item->guid; |
|
695 | - } |
|
696 | - } |
|
697 | - } |
|
698 | - // @todo Without this, recursive delete fails. See #4568 |
|
699 | - reset($results); |
|
700 | - |
|
701 | - if ($guids) { |
|
702 | - // there were entities in the result set, preload metadata for them |
|
703 | - $this->metadata_cache->populateFromEntities($guids); |
|
704 | - } |
|
705 | - |
|
706 | - if (count($results) > 1) { |
|
707 | - $props_to_preload = []; |
|
708 | - if ($options['preload_owners']) { |
|
709 | - $props_to_preload[] = 'owner_guid'; |
|
710 | - } |
|
711 | - if ($options['preload_containers']) { |
|
712 | - $props_to_preload[] = 'container_guid'; |
|
713 | - } |
|
714 | - if ($props_to_preload) { |
|
715 | - // note, ElggEntityPreloaderIntegrationTest assumes it can swap out |
|
716 | - // the preloader after boot. If you inject this component at construction |
|
717 | - // time that unit test will break. :/ |
|
718 | - _elgg_services()->entityPreloader->preload($results, $props_to_preload); |
|
719 | - } |
|
720 | - } |
|
721 | - |
|
722 | - return $results; |
|
723 | - } |
|
724 | - |
|
725 | - /** |
|
726 | - * Decorate getEntities() options in order to auto-join secondary tables where it's |
|
727 | - * safe to do so. |
|
728 | - * |
|
729 | - * @param array $options Options array in getEntities() after normalization |
|
730 | - * @return array |
|
731 | - */ |
|
732 | - protected function autoJoinTables(array $options) { |
|
733 | - // we must be careful that the query doesn't specify any options that may join |
|
734 | - // tables or change the selected columns |
|
735 | - if (!is_array($options['types']) |
|
736 | - || count($options['types']) !== 1 |
|
737 | - || !empty($options['selects']) |
|
738 | - || !empty($options['wheres']) |
|
739 | - || !empty($options['joins']) |
|
740 | - || $options['callback'] !== 'entity_row_to_elggstar' |
|
741 | - || $options['count']) { |
|
742 | - // Too dangerous to auto-join |
|
743 | - return $options; |
|
744 | - } |
|
745 | - |
|
746 | - $join_types = [ |
|
747 | - // Each class must have a static getExternalAttributes() : array |
|
748 | - 'object' => 'ElggObject', |
|
749 | - 'user' => 'ElggUser', |
|
750 | - 'group' => 'ElggGroup', |
|
751 | - 'site' => 'ElggSite', |
|
752 | - ]; |
|
753 | - |
|
754 | - // We use reset() because $options['types'] may not have a numeric key |
|
755 | - $type = reset($options['types']); |
|
756 | - |
|
757 | - // Get the columns we'll need to select. We can't use st.* because the order_by |
|
758 | - // clause may reference "guid", which MySQL will complain about being ambiguous |
|
759 | - try { |
|
760 | - $attributes = \ElggEntity::getExtraAttributeDefaults($type); |
|
761 | - } catch (\Exception $e) { |
|
762 | - $this->logger->error("Unrecognized type: $type"); |
|
763 | - return $options; |
|
764 | - } |
|
765 | - |
|
766 | - foreach (array_keys($attributes) as $col) { |
|
767 | - $options['selects'][] = "st.$col"; |
|
768 | - } |
|
769 | - |
|
770 | - // join the secondary table |
|
771 | - $options['joins'][] = "JOIN {$this->db->prefix}{$type}s_entity st ON (e.guid = st.guid)"; |
|
772 | - |
|
773 | - return $options; |
|
774 | - } |
|
775 | - |
|
776 | - /** |
|
777 | - * Return entities from an SQL query generated by elgg_get_entities. |
|
778 | - * |
|
779 | - * @access private |
|
780 | - * |
|
781 | - * @param string $sql |
|
782 | - * @param ElggBatch $batch |
|
783 | - * @return ElggEntity[] |
|
784 | - * @throws LogicException |
|
785 | - */ |
|
786 | - public function fetchFromSql($sql, \ElggBatch $batch = null) { |
|
787 | - $plugin_subtype = $this->subtype_table->getId('object', 'plugin'); |
|
788 | - |
|
789 | - // Keys are types, values are columns that, if present, suggest that the secondary |
|
790 | - // table is already JOINed. Note it's OK if guess incorrectly because entity load() |
|
791 | - // will fetch any missing attributes. |
|
792 | - $types_to_optimize = [ |
|
793 | - 'object' => 'title', |
|
794 | - 'user' => 'password_hash', |
|
795 | - 'group' => 'name', |
|
796 | - 'site' => 'url', |
|
797 | - ]; |
|
798 | - |
|
799 | - $rows = $this->db->getData($sql); |
|
800 | - |
|
801 | - // guids to look up in each type |
|
802 | - $lookup_types = []; |
|
803 | - // maps GUIDs to the $rows key |
|
804 | - $guid_to_key = []; |
|
805 | - |
|
806 | - if (isset($rows[0]->type, $rows[0]->subtype) |
|
807 | - && $rows[0]->type === 'object' |
|
808 | - && $rows[0]->subtype == $plugin_subtype) { |
|
809 | - // Likely the entire resultset is plugins, which have already been optimized |
|
810 | - // to JOIN the secondary table. In this case we allow retrieving from cache, |
|
811 | - // but abandon the extra queries. |
|
812 | - $types_to_optimize = []; |
|
813 | - } |
|
814 | - |
|
815 | - // First pass: use cache where possible, gather GUIDs that we're optimizing |
|
816 | - foreach ($rows as $i => $row) { |
|
817 | - if (empty($row->guid) || empty($row->type)) { |
|
818 | - throw new LogicException('Entity row missing guid or type'); |
|
819 | - } |
|
820 | - |
|
821 | - // We try ephemeral cache because it's blazingly fast and we ideally want to access |
|
822 | - // the same PHP instance. We don't try memcache because it isn't worth the overhead. |
|
823 | - $entity = $this->entity_cache->get($row->guid); |
|
824 | - if ($entity) { |
|
825 | - // from static var, must be refreshed in case row has extra columns |
|
826 | - $entity->refresh($row); |
|
827 | - $rows[$i] = $entity; |
|
828 | - continue; |
|
829 | - } |
|
830 | - |
|
831 | - if (isset($types_to_optimize[$row->type])) { |
|
832 | - // check if row already looks JOINed. |
|
833 | - if (isset($row->{$types_to_optimize[$row->type]})) { |
|
834 | - // Row probably already contains JOINed secondary table. Don't make another query just |
|
835 | - // to pull data that's already there |
|
836 | - continue; |
|
837 | - } |
|
838 | - $lookup_types[$row->type][] = $row->guid; |
|
839 | - $guid_to_key[$row->guid] = $i; |
|
840 | - } |
|
841 | - } |
|
842 | - // Do secondary queries and merge rows |
|
843 | - if ($lookup_types) { |
|
844 | - foreach ($lookup_types as $type => $guids) { |
|
845 | - $set = "(" . implode(',', $guids) . ")"; |
|
846 | - $sql = "SELECT * FROM {$this->db->prefix}{$type}s_entity WHERE guid IN $set"; |
|
847 | - $secondary_rows = $this->db->getData($sql); |
|
848 | - if ($secondary_rows) { |
|
849 | - foreach ($secondary_rows as $secondary_row) { |
|
850 | - $key = $guid_to_key[$secondary_row->guid]; |
|
851 | - // cast to arrays to merge then cast back |
|
852 | - $rows[$key] = (object) array_merge((array) $rows[$key], (array) $secondary_row); |
|
853 | - } |
|
854 | - } |
|
855 | - } |
|
856 | - } |
|
857 | - // Second pass to finish conversion |
|
858 | - foreach ($rows as $i => $row) { |
|
859 | - if ($row instanceof ElggEntity) { |
|
860 | - continue; |
|
861 | - } else { |
|
862 | - try { |
|
863 | - $rows[$i] = $this->rowToElggStar($row); |
|
864 | - } catch (IncompleteEntityException $e) { |
|
865 | - // don't let incomplete entities throw fatal errors |
|
866 | - unset($rows[$i]); |
|
867 | - |
|
868 | - // report incompletes to the batch process that spawned this query |
|
869 | - if ($batch) { |
|
870 | - $batch->reportIncompleteEntity($row); |
|
871 | - } |
|
872 | - } |
|
873 | - } |
|
874 | - } |
|
875 | - return $rows; |
|
876 | - } |
|
877 | - |
|
878 | - /** |
|
879 | - * Returns SQL where clause for type and subtype on main entity table |
|
880 | - * |
|
881 | - * @param string $table Entity table prefix as defined in SELECT...FROM entities $table |
|
882 | - * @param null|array $types Array of types or null if none. |
|
883 | - * @param null|array $subtypes Array of subtypes or null if none |
|
884 | - * @param null|array $pairs Array of pairs of types and subtypes |
|
885 | - * |
|
886 | - * @return false|string |
|
887 | - * @access private |
|
888 | - */ |
|
889 | - public function getEntityTypeSubtypeWhereSql($table, $types, $subtypes, $pairs) { |
|
890 | - // subtype depends upon type. |
|
891 | - if ($subtypes && !$types) { |
|
892 | - $this->logger->warn("Cannot set subtypes without type."); |
|
893 | - return false; |
|
894 | - } |
|
895 | - |
|
896 | - // short circuit if nothing is requested |
|
897 | - if (!$types && !$subtypes && !$pairs) { |
|
898 | - return ''; |
|
899 | - } |
|
900 | - |
|
901 | - // pairs override |
|
902 | - $wheres = []; |
|
903 | - if (!is_array($pairs)) { |
|
904 | - if (!is_array($types)) { |
|
905 | - $types = [$types]; |
|
906 | - } |
|
907 | - |
|
908 | - if ($subtypes && !is_array($subtypes)) { |
|
909 | - $subtypes = [$subtypes]; |
|
910 | - } |
|
911 | - |
|
912 | - // decrementer for valid types. Return false if no valid types |
|
913 | - $valid_types_count = count($types); |
|
914 | - $valid_subtypes_count = 0; |
|
915 | - // remove invalid types to get an accurate count of |
|
916 | - // valid types for the invalid subtype detection to use |
|
917 | - // below. |
|
918 | - // also grab the count of ALL subtypes on valid types to decrement later on |
|
919 | - // and check against. |
|
920 | - // |
|
921 | - // yes this is duplicating a foreach on $types. |
|
922 | - foreach ($types as $type) { |
|
923 | - if (!in_array($type, \Elgg\Config::getEntityTypes())) { |
|
924 | - $valid_types_count--; |
|
925 | - unset($types[array_search($type, $types)]); |
|
926 | - } else { |
|
927 | - // do the checking (and decrementing) in the subtype section. |
|
928 | - $valid_subtypes_count += count($subtypes); |
|
929 | - } |
|
930 | - } |
|
931 | - |
|
932 | - // return false if nothing is valid. |
|
933 | - if (!$valid_types_count) { |
|
934 | - return false; |
|
935 | - } |
|
936 | - |
|
937 | - // subtypes are based upon types, so we need to look at each |
|
938 | - // type individually to get the right subtype id. |
|
939 | - foreach ($types as $type) { |
|
940 | - $subtype_ids = []; |
|
941 | - if ($subtypes) { |
|
942 | - foreach ($subtypes as $subtype) { |
|
943 | - // check that the subtype is valid |
|
944 | - if (!$subtype && ELGG_ENTITIES_NO_VALUE === $subtype) { |
|
945 | - // subtype value is 0 |
|
946 | - $subtype_ids[] = ELGG_ENTITIES_NO_VALUE; |
|
947 | - } elseif (!$subtype) { |
|
948 | - // subtype is ignored. |
|
949 | - // this handles ELGG_ENTITIES_ANY_VALUE, '', and anything falsy that isn't 0 |
|
950 | - continue; |
|
951 | - } else { |
|
952 | - $subtype_id = get_subtype_id($type, $subtype); |
|
953 | - |
|
954 | - if ($subtype_id) { |
|
955 | - $subtype_ids[] = $subtype_id; |
|
956 | - } else { |
|
957 | - $valid_subtypes_count--; |
|
958 | - $this->logger->notice("Type-subtype '$type:$subtype' does not exist!"); |
|
959 | - continue; |
|
960 | - } |
|
961 | - } |
|
962 | - } |
|
963 | - |
|
964 | - // return false if we're all invalid subtypes in the only valid type |
|
965 | - if ($valid_subtypes_count <= 0) { |
|
966 | - return false; |
|
967 | - } |
|
968 | - } |
|
969 | - |
|
970 | - if (is_array($subtype_ids) && count($subtype_ids)) { |
|
971 | - $subtype_ids_str = implode(',', $subtype_ids); |
|
972 | - $wheres[] = "({$table}.type = '$type' AND {$table}.subtype IN ($subtype_ids_str))"; |
|
973 | - } else { |
|
974 | - $wheres[] = "({$table}.type = '$type')"; |
|
975 | - } |
|
976 | - } |
|
977 | - } else { |
|
978 | - // using type/subtype pairs |
|
979 | - $valid_pairs_count = count($pairs); |
|
980 | - $valid_pairs_subtypes_count = 0; |
|
981 | - |
|
982 | - // same deal as above--we need to know how many valid types |
|
983 | - // and subtypes we have before hitting the subtype section. |
|
984 | - // also normalize the subtypes into arrays here. |
|
985 | - foreach ($pairs as $paired_type => $paired_subtypes) { |
|
986 | - if (!in_array($paired_type, \Elgg\Config::getEntityTypes())) { |
|
987 | - $valid_pairs_count--; |
|
988 | - unset($pairs[array_search($paired_type, $pairs)]); |
|
989 | - } else { |
|
990 | - if ($paired_subtypes && !is_array($paired_subtypes)) { |
|
991 | - $pairs[$paired_type] = [$paired_subtypes]; |
|
992 | - } |
|
993 | - $valid_pairs_subtypes_count += count($paired_subtypes); |
|
994 | - } |
|
995 | - } |
|
996 | - |
|
997 | - if ($valid_pairs_count <= 0) { |
|
998 | - return false; |
|
999 | - } |
|
1000 | - foreach ($pairs as $paired_type => $paired_subtypes) { |
|
1001 | - // this will always be an array because of line 2027, right? |
|
1002 | - // no...some overly clever person can say pair => array('object' => null) |
|
1003 | - if (is_array($paired_subtypes)) { |
|
1004 | - $paired_subtype_ids = []; |
|
1005 | - foreach ($paired_subtypes as $paired_subtype) { |
|
1006 | - if (ELGG_ENTITIES_NO_VALUE === $paired_subtype || ($paired_subtype_id = get_subtype_id($paired_type, $paired_subtype))) { |
|
1007 | - $paired_subtype_ids[] = (ELGG_ENTITIES_NO_VALUE === $paired_subtype) ? |
|
1008 | - ELGG_ENTITIES_NO_VALUE : $paired_subtype_id; |
|
1009 | - } else { |
|
1010 | - $valid_pairs_subtypes_count--; |
|
1011 | - $this->logger->notice("Type-subtype '$paired_type:$paired_subtype' does not exist!"); |
|
1012 | - // return false if we're all invalid subtypes in the only valid type |
|
1013 | - continue; |
|
1014 | - } |
|
1015 | - } |
|
1016 | - |
|
1017 | - // return false if there are no valid subtypes. |
|
1018 | - if ($valid_pairs_subtypes_count <= 0) { |
|
1019 | - return false; |
|
1020 | - } |
|
1021 | - |
|
1022 | - |
|
1023 | - if ($paired_subtype_ids_str = implode(',', $paired_subtype_ids)) { |
|
1024 | - $wheres[] = "({$table}.type = '$paired_type'" |
|
1025 | - . " AND {$table}.subtype IN ($paired_subtype_ids_str))"; |
|
1026 | - } |
|
1027 | - } else { |
|
1028 | - $wheres[] = "({$table}.type = '$paired_type')"; |
|
1029 | - } |
|
1030 | - } |
|
1031 | - } |
|
1032 | - |
|
1033 | - // pairs override the above. return false if they don't exist. |
|
1034 | - if (is_array($wheres) && count($wheres)) { |
|
1035 | - $where = implode(' OR ', $wheres); |
|
1036 | - return "($where)"; |
|
1037 | - } |
|
1038 | - |
|
1039 | - return ''; |
|
1040 | - } |
|
1041 | - |
|
1042 | - /** |
|
1043 | - * Returns SQL where clause for owner and containers. |
|
1044 | - * |
|
1045 | - * @param string $column Column name the guids should be checked against. Usually |
|
1046 | - * best to provide in table.column format. |
|
1047 | - * @param null|array $guids Array of GUIDs. |
|
1048 | - * |
|
1049 | - * @return false|string |
|
1050 | - * @access private |
|
1051 | - */ |
|
1052 | - public function getGuidBasedWhereSql($column, $guids) { |
|
1053 | - // short circuit if nothing requested |
|
1054 | - // 0 is a valid guid |
|
1055 | - if (!$guids && $guids !== 0) { |
|
1056 | - return ''; |
|
1057 | - } |
|
1058 | - |
|
1059 | - // normalize and sanitise owners |
|
1060 | - if (!is_array($guids)) { |
|
1061 | - $guids = [$guids]; |
|
1062 | - } |
|
1063 | - |
|
1064 | - $guids_sanitized = []; |
|
1065 | - foreach ($guids as $guid) { |
|
1066 | - if ($guid !== ELGG_ENTITIES_NO_VALUE) { |
|
1067 | - $guid = sanitise_int($guid); |
|
1068 | - |
|
1069 | - if (!$guid) { |
|
1070 | - return false; |
|
1071 | - } |
|
1072 | - } |
|
1073 | - $guids_sanitized[] = $guid; |
|
1074 | - } |
|
1075 | - |
|
1076 | - $where = ''; |
|
1077 | - $guid_str = implode(',', $guids_sanitized); |
|
1078 | - |
|
1079 | - // implode(',', 0) returns 0. |
|
1080 | - if ($guid_str !== false && $guid_str !== '') { |
|
1081 | - $where = "($column IN ($guid_str))"; |
|
1082 | - } |
|
1083 | - |
|
1084 | - return $where; |
|
1085 | - } |
|
1086 | - |
|
1087 | - /** |
|
1088 | - * Returns SQL where clause for entity time limits. |
|
1089 | - * |
|
1090 | - * @param string $table Entity table prefix as defined in |
|
1091 | - * SELECT...FROM entities $table |
|
1092 | - * @param null|int $time_created_upper Time created upper limit |
|
1093 | - * @param null|int $time_created_lower Time created lower limit |
|
1094 | - * @param null|int $time_updated_upper Time updated upper limit |
|
1095 | - * @param null|int $time_updated_lower Time updated lower limit |
|
1096 | - * |
|
1097 | - * @return false|string false on fail, string on success. |
|
1098 | - * @access private |
|
1099 | - */ |
|
1100 | - public function getEntityTimeWhereSql($table, $time_created_upper = null, |
|
1101 | - $time_created_lower = null, $time_updated_upper = null, $time_updated_lower = null) { |
|
1102 | - |
|
1103 | - $wheres = []; |
|
1104 | - |
|
1105 | - // exploit PHP's loose typing (quack) to check that they are INTs and not str cast to 0 |
|
1106 | - if ($time_created_upper && $time_created_upper == sanitise_int($time_created_upper)) { |
|
1107 | - $wheres[] = "{$table}.time_created <= $time_created_upper"; |
|
1108 | - } |
|
1109 | - |
|
1110 | - if ($time_created_lower && $time_created_lower == sanitise_int($time_created_lower)) { |
|
1111 | - $wheres[] = "{$table}.time_created >= $time_created_lower"; |
|
1112 | - } |
|
1113 | - |
|
1114 | - if ($time_updated_upper && $time_updated_upper == sanitise_int($time_updated_upper)) { |
|
1115 | - $wheres[] = "{$table}.time_updated <= $time_updated_upper"; |
|
1116 | - } |
|
1117 | - |
|
1118 | - if ($time_updated_lower && $time_updated_lower == sanitise_int($time_updated_lower)) { |
|
1119 | - $wheres[] = "{$table}.time_updated >= $time_updated_lower"; |
|
1120 | - } |
|
1121 | - |
|
1122 | - if (is_array($wheres) && count($wheres) > 0) { |
|
1123 | - $where_str = implode(' AND ', $wheres); |
|
1124 | - return "($where_str)"; |
|
1125 | - } |
|
1126 | - |
|
1127 | - return ''; |
|
1128 | - } |
|
1129 | - |
|
1130 | - /** |
|
1131 | - * Gets entities based upon attributes in secondary tables. |
|
1132 | - * Also accepts all options available to elgg_get_entities(), |
|
1133 | - * elgg_get_entities_from_metadata(), and elgg_get_entities_from_relationship(). |
|
1134 | - * |
|
1135 | - * @warning requires that the entity type be specified and there can only be one |
|
1136 | - * type. |
|
1137 | - * |
|
1138 | - * @see elgg_get_entities |
|
1139 | - * @see elgg_get_entities_from_metadata |
|
1140 | - * @see elgg_get_entities_from_relationship |
|
1141 | - * |
|
1142 | - * @param array $options Array in format: |
|
1143 | - * |
|
1144 | - * attribute_name_value_pairs => ARR ( |
|
1145 | - * 'name' => 'name', |
|
1146 | - * 'value' => 'value', |
|
1147 | - * 'operand' => '=', (optional) |
|
1148 | - * 'case_sensitive' => false (optional) |
|
1149 | - * ) |
|
1150 | - * If multiple values are sent via |
|
1151 | - * an array ('value' => array('value1', 'value2') |
|
1152 | - * the pair's operand will be forced to "IN". |
|
1153 | - * |
|
1154 | - * attribute_name_value_pairs_operator => null|STR The operator to use for combining |
|
1155 | - * (name = value) OPERATOR (name = value); default is AND |
|
1156 | - * |
|
1157 | - * @return ElggEntity[]|mixed If count, int. If not count, array. false on errors. |
|
1158 | - * @throws InvalidArgumentException |
|
1159 | - * @todo Does not support ordering by attributes or using an attribute pair shortcut like this ('title' => 'foo') |
|
1160 | - */ |
|
1161 | - public function getEntitiesFromAttributes(array $options = []) { |
|
1162 | - $defaults = [ |
|
1163 | - 'attribute_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE, |
|
1164 | - 'attribute_name_value_pairs_operator' => 'AND', |
|
1165 | - ]; |
|
1166 | - |
|
1167 | - $options = array_merge($defaults, $options); |
|
1168 | - |
|
1169 | - $singulars = ['type', 'attribute_name_value_pair']; |
|
1170 | - $options = _elgg_normalize_plural_options_array($options, $singulars); |
|
1171 | - |
|
1172 | - $clauses = _elgg_get_entity_attribute_where_sql($options); |
|
1173 | - |
|
1174 | - if ($clauses) { |
|
1175 | - // merge wheres to pass to elgg_get_entities() |
|
1176 | - if (isset($options['wheres']) && !is_array($options['wheres'])) { |
|
1177 | - $options['wheres'] = [$options['wheres']]; |
|
1178 | - } elseif (!isset($options['wheres'])) { |
|
1179 | - $options['wheres'] = []; |
|
1180 | - } |
|
1181 | - |
|
1182 | - $options['wheres'] = array_merge($options['wheres'], $clauses['wheres']); |
|
1183 | - |
|
1184 | - // merge joins to pass to elgg_get_entities() |
|
1185 | - if (isset($options['joins']) && !is_array($options['joins'])) { |
|
1186 | - $options['joins'] = [$options['joins']]; |
|
1187 | - } elseif (!isset($options['joins'])) { |
|
1188 | - $options['joins'] = []; |
|
1189 | - } |
|
1190 | - |
|
1191 | - $options['joins'] = array_merge($options['joins'], $clauses['joins']); |
|
1192 | - } |
|
1193 | - |
|
1194 | - return elgg_get_entities_from_relationship($options); |
|
1195 | - } |
|
1196 | - |
|
1197 | - /** |
|
1198 | - * Get the join and where clauses for working with entity attributes |
|
1199 | - * |
|
1200 | - * @return false|array False on fail, array('joins', 'wheres') |
|
1201 | - * @access private |
|
1202 | - * @throws InvalidArgumentException |
|
1203 | - */ |
|
1204 | - public function getEntityAttributeWhereSql(array $options = []) { |
|
1205 | - |
|
1206 | - if (!isset($options['types'])) { |
|
1207 | - throw new InvalidArgumentException("The entity type must be defined for elgg_get_entities_from_attributes()"); |
|
1208 | - } |
|
1209 | - |
|
1210 | - if (is_array($options['types']) && count($options['types']) !== 1) { |
|
1211 | - throw new InvalidArgumentException("Only one type can be passed to elgg_get_entities_from_attributes()"); |
|
1212 | - } |
|
1213 | - |
|
1214 | - // type can be passed as string or array |
|
1215 | - $type = $options['types']; |
|
1216 | - if (is_array($type)) { |
|
1217 | - $type = $type[0]; |
|
1218 | - } |
|
1219 | - |
|
1220 | - // @todo the types should be defined somewhere (as constant on \ElggEntity?) |
|
1221 | - if (!in_array($type, ['group', 'object', 'site', 'user'])) { |
|
1222 | - throw new InvalidArgumentException("Invalid type '$type' passed to elgg_get_entities_from_attributes()"); |
|
1223 | - } |
|
1224 | - |
|
1225 | - |
|
1226 | - $type_table = "{$this->db->prefix}{$type}s_entity"; |
|
1227 | - |
|
1228 | - $return = [ |
|
1229 | - 'joins' => [], |
|
1230 | - 'wheres' => [], |
|
1231 | - ]; |
|
1232 | - |
|
1233 | - // short circuit if nothing requested |
|
1234 | - if ($options['attribute_name_value_pairs'] == ELGG_ENTITIES_ANY_VALUE) { |
|
1235 | - return $return; |
|
1236 | - } |
|
1237 | - |
|
1238 | - if (!is_array($options['attribute_name_value_pairs'])) { |
|
1239 | - throw new InvalidArgumentException("attribute_name_value_pairs must be an array for elgg_get_entities_from_attributes()"); |
|
1240 | - } |
|
1241 | - |
|
1242 | - $wheres = []; |
|
1243 | - |
|
1244 | - // check if this is an array of pairs or just a single pair. |
|
1245 | - $pairs = $options['attribute_name_value_pairs']; |
|
1246 | - if (isset($pairs['name']) || isset($pairs['value'])) { |
|
1247 | - $pairs = [$pairs]; |
|
1248 | - } |
|
1249 | - |
|
1250 | - $pair_wheres = []; |
|
1251 | - foreach ($pairs as $index => $pair) { |
|
1252 | - // must have at least a name and value |
|
1253 | - if (!isset($pair['name']) || !isset($pair['value'])) { |
|
1254 | - continue; |
|
1255 | - } |
|
1256 | - |
|
1257 | - if (isset($pair['operand'])) { |
|
1258 | - $operand = sanitize_string($pair['operand']); |
|
1259 | - } else { |
|
1260 | - $operand = '='; |
|
1261 | - } |
|
1262 | - |
|
1263 | - if (is_numeric($pair['value'])) { |
|
1264 | - $value = sanitize_string($pair['value']); |
|
1265 | - } else if (is_array($pair['value'])) { |
|
1266 | - $values_array = []; |
|
1267 | - foreach ($pair['value'] as $pair_value) { |
|
1268 | - if (is_numeric($pair_value)) { |
|
1269 | - $values_array[] = sanitize_string($pair_value); |
|
1270 | - } else { |
|
1271 | - $values_array[] = "'" . sanitize_string($pair_value) . "'"; |
|
1272 | - } |
|
1273 | - } |
|
1274 | - |
|
1275 | - $operand = 'IN'; |
|
1276 | - if ($values_array) { |
|
1277 | - $value = '(' . implode(', ', $values_array) . ')'; |
|
1278 | - } |
|
1279 | - } else { |
|
1280 | - $value = "'" . sanitize_string($pair['value']) . "'"; |
|
1281 | - } |
|
1282 | - |
|
1283 | - $name = sanitize_string($pair['name']); |
|
1284 | - |
|
1285 | - // case sensitivity can be specified per pair |
|
1286 | - $pair_binary = ''; |
|
1287 | - if (isset($pair['case_sensitive'])) { |
|
1288 | - $pair_binary = ($pair['case_sensitive']) ? 'BINARY ' : ''; |
|
1289 | - } |
|
1290 | - |
|
1291 | - $pair_wheres[] = "({$pair_binary}type_table.$name $operand $value)"; |
|
1292 | - } |
|
1293 | - |
|
1294 | - if ($where = implode(" {$options['attribute_name_value_pairs_operator']} ", $pair_wheres)) { |
|
1295 | - $return['wheres'][] = "($where)"; |
|
1296 | - |
|
1297 | - $return['joins'][] = "JOIN $type_table type_table ON e.guid = type_table.guid"; |
|
1298 | - } |
|
1299 | - |
|
1300 | - return $return; |
|
1301 | - } |
|
1302 | - |
|
1303 | - /** |
|
1304 | - * Returns a list of months in which entities were updated or created. |
|
1305 | - * |
|
1306 | - * @tip Use this to generate a list of archives by month for when entities were added or updated. |
|
1307 | - * |
|
1308 | - * @todo document how to pass in array for $subtype |
|
1309 | - * |
|
1310 | - * @warning Months are returned in the form YYYYMM. |
|
1311 | - * |
|
1312 | - * @param string $type The type of entity |
|
1313 | - * @param string $subtype The subtype of entity |
|
1314 | - * @param int $container_guid The container GUID that the entities belong to |
|
1315 | - * @param string $order_by Order_by SQL order by clause |
|
1316 | - * |
|
1317 | - * @return array|false Either an array months as YYYYMM, or false on failure |
|
1318 | - */ |
|
1319 | - public function getDates($type = '', $subtype = '', $container_guid = 0, $order_by = 'time_created') { |
|
1320 | - |
|
1321 | - $where = []; |
|
1322 | - |
|
1323 | - if ($type != "") { |
|
1324 | - $type = sanitise_string($type); |
|
1325 | - $where[] = "type='$type'"; |
|
1326 | - } |
|
1327 | - |
|
1328 | - if (is_array($subtype)) { |
|
1329 | - $tempwhere = ""; |
|
1330 | - if (sizeof($subtype)) { |
|
1331 | - foreach ($subtype as $typekey => $subtypearray) { |
|
1332 | - foreach ($subtypearray as $subtypeval) { |
|
1333 | - $typekey = sanitise_string($typekey); |
|
1334 | - if (!empty($subtypeval)) { |
|
1335 | - if (!$subtypeval = (int) get_subtype_id($typekey, $subtypeval)) { |
|
1336 | - return false; |
|
1337 | - } |
|
1338 | - } else { |
|
1339 | - $subtypeval = 0; |
|
1340 | - } |
|
1341 | - if (!empty($tempwhere)) { |
|
1342 | - $tempwhere .= " or "; |
|
1343 | - } |
|
1344 | - $tempwhere .= "(type = '{$typekey}' and subtype = {$subtypeval})"; |
|
1345 | - } |
|
1346 | - } |
|
1347 | - } |
|
1348 | - if (!empty($tempwhere)) { |
|
1349 | - $where[] = "({$tempwhere})"; |
|
1350 | - } |
|
1351 | - } else { |
|
1352 | - if ($subtype) { |
|
1353 | - if (!$subtype_id = get_subtype_id($type, $subtype)) { |
|
1354 | - return false; |
|
1355 | - } else { |
|
1356 | - $where[] = "subtype=$subtype_id"; |
|
1357 | - } |
|
1358 | - } |
|
1359 | - } |
|
1360 | - |
|
1361 | - if ($container_guid !== 0) { |
|
1362 | - if (is_array($container_guid)) { |
|
1363 | - foreach ($container_guid as $key => $val) { |
|
1364 | - $container_guid[$key] = (int) $val; |
|
1365 | - } |
|
1366 | - $where[] = "container_guid in (" . implode(",", $container_guid) . ")"; |
|
1367 | - } else { |
|
1368 | - $container_guid = (int) $container_guid; |
|
1369 | - $where[] = "container_guid = {$container_guid}"; |
|
1370 | - } |
|
1371 | - } |
|
1372 | - |
|
1373 | - $where[] = _elgg_get_access_where_sql(['table_alias' => '']); |
|
1374 | - |
|
1375 | - $sql = "SELECT DISTINCT EXTRACT(YEAR_MONTH FROM FROM_UNIXTIME(time_created)) AS yearmonth |
|
555 | + // can't use helper function with type_subtype_pair because |
|
556 | + // it's already an array...just need to merge it |
|
557 | + if (isset($options['type_subtype_pair'])) { |
|
558 | + if (isset($options['type_subtype_pairs'])) { |
|
559 | + $options['type_subtype_pairs'] = array_merge($options['type_subtype_pairs'], |
|
560 | + $options['type_subtype_pair']); |
|
561 | + } else { |
|
562 | + $options['type_subtype_pairs'] = $options['type_subtype_pair']; |
|
563 | + } |
|
564 | + } |
|
565 | + |
|
566 | + $singulars = ['type', 'subtype', 'guid', 'owner_guid', 'container_guid']; |
|
567 | + $options = _elgg_normalize_plural_options_array($options, $singulars); |
|
568 | + |
|
569 | + $options = $this->autoJoinTables($options); |
|
570 | + |
|
571 | + // evaluate where clauses |
|
572 | + if (!is_array($options['wheres'])) { |
|
573 | + $options['wheres'] = [$options['wheres']]; |
|
574 | + } |
|
575 | + |
|
576 | + $wheres = $options['wheres']; |
|
577 | + |
|
578 | + $wheres[] = $this->getEntityTypeSubtypeWhereSql('e', $options['types'], |
|
579 | + $options['subtypes'], $options['type_subtype_pairs']); |
|
580 | + |
|
581 | + $wheres[] = $this->getGuidBasedWhereSql('e.guid', $options['guids']); |
|
582 | + $wheres[] = $this->getGuidBasedWhereSql('e.owner_guid', $options['owner_guids']); |
|
583 | + $wheres[] = $this->getGuidBasedWhereSql('e.container_guid', $options['container_guids']); |
|
584 | + |
|
585 | + $wheres[] = $this->getEntityTimeWhereSql('e', $options['created_time_upper'], |
|
586 | + $options['created_time_lower'], $options['modified_time_upper'], $options['modified_time_lower']); |
|
587 | + |
|
588 | + // see if any functions failed |
|
589 | + // remove empty strings on successful functions |
|
590 | + foreach ($wheres as $i => $where) { |
|
591 | + if ($where === false) { |
|
592 | + return false; |
|
593 | + } elseif (empty($where)) { |
|
594 | + unset($wheres[$i]); |
|
595 | + } |
|
596 | + } |
|
597 | + |
|
598 | + // remove identical where clauses |
|
599 | + $wheres = array_unique($wheres); |
|
600 | + |
|
601 | + // evaluate join clauses |
|
602 | + if (!is_array($options['joins'])) { |
|
603 | + $options['joins'] = [$options['joins']]; |
|
604 | + } |
|
605 | + |
|
606 | + // remove identical join clauses |
|
607 | + $joins = array_unique($options['joins']); |
|
608 | + |
|
609 | + foreach ($joins as $i => $join) { |
|
610 | + if ($join === false) { |
|
611 | + return false; |
|
612 | + } elseif (empty($join)) { |
|
613 | + unset($joins[$i]); |
|
614 | + } |
|
615 | + } |
|
616 | + |
|
617 | + // evalutate selects |
|
618 | + if ($options['selects']) { |
|
619 | + $selects = ''; |
|
620 | + foreach ($options['selects'] as $select) { |
|
621 | + $selects .= ", $select"; |
|
622 | + } |
|
623 | + } else { |
|
624 | + $selects = ''; |
|
625 | + } |
|
626 | + |
|
627 | + if (!$options['count']) { |
|
628 | + $distinct = $options['distinct'] ? "DISTINCT" : ""; |
|
629 | + $query = "SELECT $distinct e.*{$selects} FROM {$this->db->prefix}entities e "; |
|
630 | + } else { |
|
631 | + // note: when DISTINCT unneeded, it's slightly faster to compute COUNT(*) than GUIDs |
|
632 | + $count_expr = $options['distinct'] ? "DISTINCT e.guid" : "*"; |
|
633 | + $query = "SELECT COUNT($count_expr) as total FROM {$this->db->prefix}entities e "; |
|
634 | + } |
|
635 | + |
|
636 | + // add joins |
|
637 | + foreach ($joins as $j) { |
|
638 | + $query .= " $j "; |
|
639 | + } |
|
640 | + |
|
641 | + // add wheres |
|
642 | + $query .= ' WHERE '; |
|
643 | + |
|
644 | + foreach ($wheres as $w) { |
|
645 | + $query .= " $w AND "; |
|
646 | + } |
|
647 | + |
|
648 | + // Add access controls |
|
649 | + $query .= _elgg_get_access_where_sql(); |
|
650 | + |
|
651 | + // reverse order by |
|
652 | + if ($options['reverse_order_by']) { |
|
653 | + $options['order_by'] = _elgg_sql_reverse_order_by_clause($options['order_by']); |
|
654 | + } |
|
655 | + |
|
656 | + if ($options['count']) { |
|
657 | + $total = $this->db->getDataRow($query); |
|
658 | + return (int) $total->total; |
|
659 | + } |
|
660 | + |
|
661 | + if ($options['group_by']) { |
|
662 | + $query .= " GROUP BY {$options['group_by']}"; |
|
663 | + } |
|
664 | + |
|
665 | + if ($options['order_by']) { |
|
666 | + $query .= " ORDER BY {$options['order_by']}"; |
|
667 | + } |
|
668 | + |
|
669 | + if ($options['limit']) { |
|
670 | + $limit = sanitise_int($options['limit'], false); |
|
671 | + $offset = sanitise_int($options['offset'], false); |
|
672 | + $query .= " LIMIT $offset, $limit"; |
|
673 | + } |
|
674 | + |
|
675 | + if ($options['callback'] === 'entity_row_to_elggstar') { |
|
676 | + $results = $this->fetchFromSql($query, $options['__ElggBatch']); |
|
677 | + } else { |
|
678 | + $results = $this->db->getData($query, $options['callback']); |
|
679 | + } |
|
680 | + |
|
681 | + if (!$results) { |
|
682 | + // no results, no preloading |
|
683 | + return $results; |
|
684 | + } |
|
685 | + |
|
686 | + // populate entity and metadata caches, and prepare $entities for preloader |
|
687 | + $guids = []; |
|
688 | + foreach ($results as $item) { |
|
689 | + // A custom callback could result in items that aren't \ElggEntity's, so check for them |
|
690 | + if ($item instanceof ElggEntity) { |
|
691 | + $this->entity_cache->set($item); |
|
692 | + // plugins usually have only settings |
|
693 | + if (!$item instanceof ElggPlugin) { |
|
694 | + $guids[] = $item->guid; |
|
695 | + } |
|
696 | + } |
|
697 | + } |
|
698 | + // @todo Without this, recursive delete fails. See #4568 |
|
699 | + reset($results); |
|
700 | + |
|
701 | + if ($guids) { |
|
702 | + // there were entities in the result set, preload metadata for them |
|
703 | + $this->metadata_cache->populateFromEntities($guids); |
|
704 | + } |
|
705 | + |
|
706 | + if (count($results) > 1) { |
|
707 | + $props_to_preload = []; |
|
708 | + if ($options['preload_owners']) { |
|
709 | + $props_to_preload[] = 'owner_guid'; |
|
710 | + } |
|
711 | + if ($options['preload_containers']) { |
|
712 | + $props_to_preload[] = 'container_guid'; |
|
713 | + } |
|
714 | + if ($props_to_preload) { |
|
715 | + // note, ElggEntityPreloaderIntegrationTest assumes it can swap out |
|
716 | + // the preloader after boot. If you inject this component at construction |
|
717 | + // time that unit test will break. :/ |
|
718 | + _elgg_services()->entityPreloader->preload($results, $props_to_preload); |
|
719 | + } |
|
720 | + } |
|
721 | + |
|
722 | + return $results; |
|
723 | + } |
|
724 | + |
|
725 | + /** |
|
726 | + * Decorate getEntities() options in order to auto-join secondary tables where it's |
|
727 | + * safe to do so. |
|
728 | + * |
|
729 | + * @param array $options Options array in getEntities() after normalization |
|
730 | + * @return array |
|
731 | + */ |
|
732 | + protected function autoJoinTables(array $options) { |
|
733 | + // we must be careful that the query doesn't specify any options that may join |
|
734 | + // tables or change the selected columns |
|
735 | + if (!is_array($options['types']) |
|
736 | + || count($options['types']) !== 1 |
|
737 | + || !empty($options['selects']) |
|
738 | + || !empty($options['wheres']) |
|
739 | + || !empty($options['joins']) |
|
740 | + || $options['callback'] !== 'entity_row_to_elggstar' |
|
741 | + || $options['count']) { |
|
742 | + // Too dangerous to auto-join |
|
743 | + return $options; |
|
744 | + } |
|
745 | + |
|
746 | + $join_types = [ |
|
747 | + // Each class must have a static getExternalAttributes() : array |
|
748 | + 'object' => 'ElggObject', |
|
749 | + 'user' => 'ElggUser', |
|
750 | + 'group' => 'ElggGroup', |
|
751 | + 'site' => 'ElggSite', |
|
752 | + ]; |
|
753 | + |
|
754 | + // We use reset() because $options['types'] may not have a numeric key |
|
755 | + $type = reset($options['types']); |
|
756 | + |
|
757 | + // Get the columns we'll need to select. We can't use st.* because the order_by |
|
758 | + // clause may reference "guid", which MySQL will complain about being ambiguous |
|
759 | + try { |
|
760 | + $attributes = \ElggEntity::getExtraAttributeDefaults($type); |
|
761 | + } catch (\Exception $e) { |
|
762 | + $this->logger->error("Unrecognized type: $type"); |
|
763 | + return $options; |
|
764 | + } |
|
765 | + |
|
766 | + foreach (array_keys($attributes) as $col) { |
|
767 | + $options['selects'][] = "st.$col"; |
|
768 | + } |
|
769 | + |
|
770 | + // join the secondary table |
|
771 | + $options['joins'][] = "JOIN {$this->db->prefix}{$type}s_entity st ON (e.guid = st.guid)"; |
|
772 | + |
|
773 | + return $options; |
|
774 | + } |
|
775 | + |
|
776 | + /** |
|
777 | + * Return entities from an SQL query generated by elgg_get_entities. |
|
778 | + * |
|
779 | + * @access private |
|
780 | + * |
|
781 | + * @param string $sql |
|
782 | + * @param ElggBatch $batch |
|
783 | + * @return ElggEntity[] |
|
784 | + * @throws LogicException |
|
785 | + */ |
|
786 | + public function fetchFromSql($sql, \ElggBatch $batch = null) { |
|
787 | + $plugin_subtype = $this->subtype_table->getId('object', 'plugin'); |
|
788 | + |
|
789 | + // Keys are types, values are columns that, if present, suggest that the secondary |
|
790 | + // table is already JOINed. Note it's OK if guess incorrectly because entity load() |
|
791 | + // will fetch any missing attributes. |
|
792 | + $types_to_optimize = [ |
|
793 | + 'object' => 'title', |
|
794 | + 'user' => 'password_hash', |
|
795 | + 'group' => 'name', |
|
796 | + 'site' => 'url', |
|
797 | + ]; |
|
798 | + |
|
799 | + $rows = $this->db->getData($sql); |
|
800 | + |
|
801 | + // guids to look up in each type |
|
802 | + $lookup_types = []; |
|
803 | + // maps GUIDs to the $rows key |
|
804 | + $guid_to_key = []; |
|
805 | + |
|
806 | + if (isset($rows[0]->type, $rows[0]->subtype) |
|
807 | + && $rows[0]->type === 'object' |
|
808 | + && $rows[0]->subtype == $plugin_subtype) { |
|
809 | + // Likely the entire resultset is plugins, which have already been optimized |
|
810 | + // to JOIN the secondary table. In this case we allow retrieving from cache, |
|
811 | + // but abandon the extra queries. |
|
812 | + $types_to_optimize = []; |
|
813 | + } |
|
814 | + |
|
815 | + // First pass: use cache where possible, gather GUIDs that we're optimizing |
|
816 | + foreach ($rows as $i => $row) { |
|
817 | + if (empty($row->guid) || empty($row->type)) { |
|
818 | + throw new LogicException('Entity row missing guid or type'); |
|
819 | + } |
|
820 | + |
|
821 | + // We try ephemeral cache because it's blazingly fast and we ideally want to access |
|
822 | + // the same PHP instance. We don't try memcache because it isn't worth the overhead. |
|
823 | + $entity = $this->entity_cache->get($row->guid); |
|
824 | + if ($entity) { |
|
825 | + // from static var, must be refreshed in case row has extra columns |
|
826 | + $entity->refresh($row); |
|
827 | + $rows[$i] = $entity; |
|
828 | + continue; |
|
829 | + } |
|
830 | + |
|
831 | + if (isset($types_to_optimize[$row->type])) { |
|
832 | + // check if row already looks JOINed. |
|
833 | + if (isset($row->{$types_to_optimize[$row->type]})) { |
|
834 | + // Row probably already contains JOINed secondary table. Don't make another query just |
|
835 | + // to pull data that's already there |
|
836 | + continue; |
|
837 | + } |
|
838 | + $lookup_types[$row->type][] = $row->guid; |
|
839 | + $guid_to_key[$row->guid] = $i; |
|
840 | + } |
|
841 | + } |
|
842 | + // Do secondary queries and merge rows |
|
843 | + if ($lookup_types) { |
|
844 | + foreach ($lookup_types as $type => $guids) { |
|
845 | + $set = "(" . implode(',', $guids) . ")"; |
|
846 | + $sql = "SELECT * FROM {$this->db->prefix}{$type}s_entity WHERE guid IN $set"; |
|
847 | + $secondary_rows = $this->db->getData($sql); |
|
848 | + if ($secondary_rows) { |
|
849 | + foreach ($secondary_rows as $secondary_row) { |
|
850 | + $key = $guid_to_key[$secondary_row->guid]; |
|
851 | + // cast to arrays to merge then cast back |
|
852 | + $rows[$key] = (object) array_merge((array) $rows[$key], (array) $secondary_row); |
|
853 | + } |
|
854 | + } |
|
855 | + } |
|
856 | + } |
|
857 | + // Second pass to finish conversion |
|
858 | + foreach ($rows as $i => $row) { |
|
859 | + if ($row instanceof ElggEntity) { |
|
860 | + continue; |
|
861 | + } else { |
|
862 | + try { |
|
863 | + $rows[$i] = $this->rowToElggStar($row); |
|
864 | + } catch (IncompleteEntityException $e) { |
|
865 | + // don't let incomplete entities throw fatal errors |
|
866 | + unset($rows[$i]); |
|
867 | + |
|
868 | + // report incompletes to the batch process that spawned this query |
|
869 | + if ($batch) { |
|
870 | + $batch->reportIncompleteEntity($row); |
|
871 | + } |
|
872 | + } |
|
873 | + } |
|
874 | + } |
|
875 | + return $rows; |
|
876 | + } |
|
877 | + |
|
878 | + /** |
|
879 | + * Returns SQL where clause for type and subtype on main entity table |
|
880 | + * |
|
881 | + * @param string $table Entity table prefix as defined in SELECT...FROM entities $table |
|
882 | + * @param null|array $types Array of types or null if none. |
|
883 | + * @param null|array $subtypes Array of subtypes or null if none |
|
884 | + * @param null|array $pairs Array of pairs of types and subtypes |
|
885 | + * |
|
886 | + * @return false|string |
|
887 | + * @access private |
|
888 | + */ |
|
889 | + public function getEntityTypeSubtypeWhereSql($table, $types, $subtypes, $pairs) { |
|
890 | + // subtype depends upon type. |
|
891 | + if ($subtypes && !$types) { |
|
892 | + $this->logger->warn("Cannot set subtypes without type."); |
|
893 | + return false; |
|
894 | + } |
|
895 | + |
|
896 | + // short circuit if nothing is requested |
|
897 | + if (!$types && !$subtypes && !$pairs) { |
|
898 | + return ''; |
|
899 | + } |
|
900 | + |
|
901 | + // pairs override |
|
902 | + $wheres = []; |
|
903 | + if (!is_array($pairs)) { |
|
904 | + if (!is_array($types)) { |
|
905 | + $types = [$types]; |
|
906 | + } |
|
907 | + |
|
908 | + if ($subtypes && !is_array($subtypes)) { |
|
909 | + $subtypes = [$subtypes]; |
|
910 | + } |
|
911 | + |
|
912 | + // decrementer for valid types. Return false if no valid types |
|
913 | + $valid_types_count = count($types); |
|
914 | + $valid_subtypes_count = 0; |
|
915 | + // remove invalid types to get an accurate count of |
|
916 | + // valid types for the invalid subtype detection to use |
|
917 | + // below. |
|
918 | + // also grab the count of ALL subtypes on valid types to decrement later on |
|
919 | + // and check against. |
|
920 | + // |
|
921 | + // yes this is duplicating a foreach on $types. |
|
922 | + foreach ($types as $type) { |
|
923 | + if (!in_array($type, \Elgg\Config::getEntityTypes())) { |
|
924 | + $valid_types_count--; |
|
925 | + unset($types[array_search($type, $types)]); |
|
926 | + } else { |
|
927 | + // do the checking (and decrementing) in the subtype section. |
|
928 | + $valid_subtypes_count += count($subtypes); |
|
929 | + } |
|
930 | + } |
|
931 | + |
|
932 | + // return false if nothing is valid. |
|
933 | + if (!$valid_types_count) { |
|
934 | + return false; |
|
935 | + } |
|
936 | + |
|
937 | + // subtypes are based upon types, so we need to look at each |
|
938 | + // type individually to get the right subtype id. |
|
939 | + foreach ($types as $type) { |
|
940 | + $subtype_ids = []; |
|
941 | + if ($subtypes) { |
|
942 | + foreach ($subtypes as $subtype) { |
|
943 | + // check that the subtype is valid |
|
944 | + if (!$subtype && ELGG_ENTITIES_NO_VALUE === $subtype) { |
|
945 | + // subtype value is 0 |
|
946 | + $subtype_ids[] = ELGG_ENTITIES_NO_VALUE; |
|
947 | + } elseif (!$subtype) { |
|
948 | + // subtype is ignored. |
|
949 | + // this handles ELGG_ENTITIES_ANY_VALUE, '', and anything falsy that isn't 0 |
|
950 | + continue; |
|
951 | + } else { |
|
952 | + $subtype_id = get_subtype_id($type, $subtype); |
|
953 | + |
|
954 | + if ($subtype_id) { |
|
955 | + $subtype_ids[] = $subtype_id; |
|
956 | + } else { |
|
957 | + $valid_subtypes_count--; |
|
958 | + $this->logger->notice("Type-subtype '$type:$subtype' does not exist!"); |
|
959 | + continue; |
|
960 | + } |
|
961 | + } |
|
962 | + } |
|
963 | + |
|
964 | + // return false if we're all invalid subtypes in the only valid type |
|
965 | + if ($valid_subtypes_count <= 0) { |
|
966 | + return false; |
|
967 | + } |
|
968 | + } |
|
969 | + |
|
970 | + if (is_array($subtype_ids) && count($subtype_ids)) { |
|
971 | + $subtype_ids_str = implode(',', $subtype_ids); |
|
972 | + $wheres[] = "({$table}.type = '$type' AND {$table}.subtype IN ($subtype_ids_str))"; |
|
973 | + } else { |
|
974 | + $wheres[] = "({$table}.type = '$type')"; |
|
975 | + } |
|
976 | + } |
|
977 | + } else { |
|
978 | + // using type/subtype pairs |
|
979 | + $valid_pairs_count = count($pairs); |
|
980 | + $valid_pairs_subtypes_count = 0; |
|
981 | + |
|
982 | + // same deal as above--we need to know how many valid types |
|
983 | + // and subtypes we have before hitting the subtype section. |
|
984 | + // also normalize the subtypes into arrays here. |
|
985 | + foreach ($pairs as $paired_type => $paired_subtypes) { |
|
986 | + if (!in_array($paired_type, \Elgg\Config::getEntityTypes())) { |
|
987 | + $valid_pairs_count--; |
|
988 | + unset($pairs[array_search($paired_type, $pairs)]); |
|
989 | + } else { |
|
990 | + if ($paired_subtypes && !is_array($paired_subtypes)) { |
|
991 | + $pairs[$paired_type] = [$paired_subtypes]; |
|
992 | + } |
|
993 | + $valid_pairs_subtypes_count += count($paired_subtypes); |
|
994 | + } |
|
995 | + } |
|
996 | + |
|
997 | + if ($valid_pairs_count <= 0) { |
|
998 | + return false; |
|
999 | + } |
|
1000 | + foreach ($pairs as $paired_type => $paired_subtypes) { |
|
1001 | + // this will always be an array because of line 2027, right? |
|
1002 | + // no...some overly clever person can say pair => array('object' => null) |
|
1003 | + if (is_array($paired_subtypes)) { |
|
1004 | + $paired_subtype_ids = []; |
|
1005 | + foreach ($paired_subtypes as $paired_subtype) { |
|
1006 | + if (ELGG_ENTITIES_NO_VALUE === $paired_subtype || ($paired_subtype_id = get_subtype_id($paired_type, $paired_subtype))) { |
|
1007 | + $paired_subtype_ids[] = (ELGG_ENTITIES_NO_VALUE === $paired_subtype) ? |
|
1008 | + ELGG_ENTITIES_NO_VALUE : $paired_subtype_id; |
|
1009 | + } else { |
|
1010 | + $valid_pairs_subtypes_count--; |
|
1011 | + $this->logger->notice("Type-subtype '$paired_type:$paired_subtype' does not exist!"); |
|
1012 | + // return false if we're all invalid subtypes in the only valid type |
|
1013 | + continue; |
|
1014 | + } |
|
1015 | + } |
|
1016 | + |
|
1017 | + // return false if there are no valid subtypes. |
|
1018 | + if ($valid_pairs_subtypes_count <= 0) { |
|
1019 | + return false; |
|
1020 | + } |
|
1021 | + |
|
1022 | + |
|
1023 | + if ($paired_subtype_ids_str = implode(',', $paired_subtype_ids)) { |
|
1024 | + $wheres[] = "({$table}.type = '$paired_type'" |
|
1025 | + . " AND {$table}.subtype IN ($paired_subtype_ids_str))"; |
|
1026 | + } |
|
1027 | + } else { |
|
1028 | + $wheres[] = "({$table}.type = '$paired_type')"; |
|
1029 | + } |
|
1030 | + } |
|
1031 | + } |
|
1032 | + |
|
1033 | + // pairs override the above. return false if they don't exist. |
|
1034 | + if (is_array($wheres) && count($wheres)) { |
|
1035 | + $where = implode(' OR ', $wheres); |
|
1036 | + return "($where)"; |
|
1037 | + } |
|
1038 | + |
|
1039 | + return ''; |
|
1040 | + } |
|
1041 | + |
|
1042 | + /** |
|
1043 | + * Returns SQL where clause for owner and containers. |
|
1044 | + * |
|
1045 | + * @param string $column Column name the guids should be checked against. Usually |
|
1046 | + * best to provide in table.column format. |
|
1047 | + * @param null|array $guids Array of GUIDs. |
|
1048 | + * |
|
1049 | + * @return false|string |
|
1050 | + * @access private |
|
1051 | + */ |
|
1052 | + public function getGuidBasedWhereSql($column, $guids) { |
|
1053 | + // short circuit if nothing requested |
|
1054 | + // 0 is a valid guid |
|
1055 | + if (!$guids && $guids !== 0) { |
|
1056 | + return ''; |
|
1057 | + } |
|
1058 | + |
|
1059 | + // normalize and sanitise owners |
|
1060 | + if (!is_array($guids)) { |
|
1061 | + $guids = [$guids]; |
|
1062 | + } |
|
1063 | + |
|
1064 | + $guids_sanitized = []; |
|
1065 | + foreach ($guids as $guid) { |
|
1066 | + if ($guid !== ELGG_ENTITIES_NO_VALUE) { |
|
1067 | + $guid = sanitise_int($guid); |
|
1068 | + |
|
1069 | + if (!$guid) { |
|
1070 | + return false; |
|
1071 | + } |
|
1072 | + } |
|
1073 | + $guids_sanitized[] = $guid; |
|
1074 | + } |
|
1075 | + |
|
1076 | + $where = ''; |
|
1077 | + $guid_str = implode(',', $guids_sanitized); |
|
1078 | + |
|
1079 | + // implode(',', 0) returns 0. |
|
1080 | + if ($guid_str !== false && $guid_str !== '') { |
|
1081 | + $where = "($column IN ($guid_str))"; |
|
1082 | + } |
|
1083 | + |
|
1084 | + return $where; |
|
1085 | + } |
|
1086 | + |
|
1087 | + /** |
|
1088 | + * Returns SQL where clause for entity time limits. |
|
1089 | + * |
|
1090 | + * @param string $table Entity table prefix as defined in |
|
1091 | + * SELECT...FROM entities $table |
|
1092 | + * @param null|int $time_created_upper Time created upper limit |
|
1093 | + * @param null|int $time_created_lower Time created lower limit |
|
1094 | + * @param null|int $time_updated_upper Time updated upper limit |
|
1095 | + * @param null|int $time_updated_lower Time updated lower limit |
|
1096 | + * |
|
1097 | + * @return false|string false on fail, string on success. |
|
1098 | + * @access private |
|
1099 | + */ |
|
1100 | + public function getEntityTimeWhereSql($table, $time_created_upper = null, |
|
1101 | + $time_created_lower = null, $time_updated_upper = null, $time_updated_lower = null) { |
|
1102 | + |
|
1103 | + $wheres = []; |
|
1104 | + |
|
1105 | + // exploit PHP's loose typing (quack) to check that they are INTs and not str cast to 0 |
|
1106 | + if ($time_created_upper && $time_created_upper == sanitise_int($time_created_upper)) { |
|
1107 | + $wheres[] = "{$table}.time_created <= $time_created_upper"; |
|
1108 | + } |
|
1109 | + |
|
1110 | + if ($time_created_lower && $time_created_lower == sanitise_int($time_created_lower)) { |
|
1111 | + $wheres[] = "{$table}.time_created >= $time_created_lower"; |
|
1112 | + } |
|
1113 | + |
|
1114 | + if ($time_updated_upper && $time_updated_upper == sanitise_int($time_updated_upper)) { |
|
1115 | + $wheres[] = "{$table}.time_updated <= $time_updated_upper"; |
|
1116 | + } |
|
1117 | + |
|
1118 | + if ($time_updated_lower && $time_updated_lower == sanitise_int($time_updated_lower)) { |
|
1119 | + $wheres[] = "{$table}.time_updated >= $time_updated_lower"; |
|
1120 | + } |
|
1121 | + |
|
1122 | + if (is_array($wheres) && count($wheres) > 0) { |
|
1123 | + $where_str = implode(' AND ', $wheres); |
|
1124 | + return "($where_str)"; |
|
1125 | + } |
|
1126 | + |
|
1127 | + return ''; |
|
1128 | + } |
|
1129 | + |
|
1130 | + /** |
|
1131 | + * Gets entities based upon attributes in secondary tables. |
|
1132 | + * Also accepts all options available to elgg_get_entities(), |
|
1133 | + * elgg_get_entities_from_metadata(), and elgg_get_entities_from_relationship(). |
|
1134 | + * |
|
1135 | + * @warning requires that the entity type be specified and there can only be one |
|
1136 | + * type. |
|
1137 | + * |
|
1138 | + * @see elgg_get_entities |
|
1139 | + * @see elgg_get_entities_from_metadata |
|
1140 | + * @see elgg_get_entities_from_relationship |
|
1141 | + * |
|
1142 | + * @param array $options Array in format: |
|
1143 | + * |
|
1144 | + * attribute_name_value_pairs => ARR ( |
|
1145 | + * 'name' => 'name', |
|
1146 | + * 'value' => 'value', |
|
1147 | + * 'operand' => '=', (optional) |
|
1148 | + * 'case_sensitive' => false (optional) |
|
1149 | + * ) |
|
1150 | + * If multiple values are sent via |
|
1151 | + * an array ('value' => array('value1', 'value2') |
|
1152 | + * the pair's operand will be forced to "IN". |
|
1153 | + * |
|
1154 | + * attribute_name_value_pairs_operator => null|STR The operator to use for combining |
|
1155 | + * (name = value) OPERATOR (name = value); default is AND |
|
1156 | + * |
|
1157 | + * @return ElggEntity[]|mixed If count, int. If not count, array. false on errors. |
|
1158 | + * @throws InvalidArgumentException |
|
1159 | + * @todo Does not support ordering by attributes or using an attribute pair shortcut like this ('title' => 'foo') |
|
1160 | + */ |
|
1161 | + public function getEntitiesFromAttributes(array $options = []) { |
|
1162 | + $defaults = [ |
|
1163 | + 'attribute_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE, |
|
1164 | + 'attribute_name_value_pairs_operator' => 'AND', |
|
1165 | + ]; |
|
1166 | + |
|
1167 | + $options = array_merge($defaults, $options); |
|
1168 | + |
|
1169 | + $singulars = ['type', 'attribute_name_value_pair']; |
|
1170 | + $options = _elgg_normalize_plural_options_array($options, $singulars); |
|
1171 | + |
|
1172 | + $clauses = _elgg_get_entity_attribute_where_sql($options); |
|
1173 | + |
|
1174 | + if ($clauses) { |
|
1175 | + // merge wheres to pass to elgg_get_entities() |
|
1176 | + if (isset($options['wheres']) && !is_array($options['wheres'])) { |
|
1177 | + $options['wheres'] = [$options['wheres']]; |
|
1178 | + } elseif (!isset($options['wheres'])) { |
|
1179 | + $options['wheres'] = []; |
|
1180 | + } |
|
1181 | + |
|
1182 | + $options['wheres'] = array_merge($options['wheres'], $clauses['wheres']); |
|
1183 | + |
|
1184 | + // merge joins to pass to elgg_get_entities() |
|
1185 | + if (isset($options['joins']) && !is_array($options['joins'])) { |
|
1186 | + $options['joins'] = [$options['joins']]; |
|
1187 | + } elseif (!isset($options['joins'])) { |
|
1188 | + $options['joins'] = []; |
|
1189 | + } |
|
1190 | + |
|
1191 | + $options['joins'] = array_merge($options['joins'], $clauses['joins']); |
|
1192 | + } |
|
1193 | + |
|
1194 | + return elgg_get_entities_from_relationship($options); |
|
1195 | + } |
|
1196 | + |
|
1197 | + /** |
|
1198 | + * Get the join and where clauses for working with entity attributes |
|
1199 | + * |
|
1200 | + * @return false|array False on fail, array('joins', 'wheres') |
|
1201 | + * @access private |
|
1202 | + * @throws InvalidArgumentException |
|
1203 | + */ |
|
1204 | + public function getEntityAttributeWhereSql(array $options = []) { |
|
1205 | + |
|
1206 | + if (!isset($options['types'])) { |
|
1207 | + throw new InvalidArgumentException("The entity type must be defined for elgg_get_entities_from_attributes()"); |
|
1208 | + } |
|
1209 | + |
|
1210 | + if (is_array($options['types']) && count($options['types']) !== 1) { |
|
1211 | + throw new InvalidArgumentException("Only one type can be passed to elgg_get_entities_from_attributes()"); |
|
1212 | + } |
|
1213 | + |
|
1214 | + // type can be passed as string or array |
|
1215 | + $type = $options['types']; |
|
1216 | + if (is_array($type)) { |
|
1217 | + $type = $type[0]; |
|
1218 | + } |
|
1219 | + |
|
1220 | + // @todo the types should be defined somewhere (as constant on \ElggEntity?) |
|
1221 | + if (!in_array($type, ['group', 'object', 'site', 'user'])) { |
|
1222 | + throw new InvalidArgumentException("Invalid type '$type' passed to elgg_get_entities_from_attributes()"); |
|
1223 | + } |
|
1224 | + |
|
1225 | + |
|
1226 | + $type_table = "{$this->db->prefix}{$type}s_entity"; |
|
1227 | + |
|
1228 | + $return = [ |
|
1229 | + 'joins' => [], |
|
1230 | + 'wheres' => [], |
|
1231 | + ]; |
|
1232 | + |
|
1233 | + // short circuit if nothing requested |
|
1234 | + if ($options['attribute_name_value_pairs'] == ELGG_ENTITIES_ANY_VALUE) { |
|
1235 | + return $return; |
|
1236 | + } |
|
1237 | + |
|
1238 | + if (!is_array($options['attribute_name_value_pairs'])) { |
|
1239 | + throw new InvalidArgumentException("attribute_name_value_pairs must be an array for elgg_get_entities_from_attributes()"); |
|
1240 | + } |
|
1241 | + |
|
1242 | + $wheres = []; |
|
1243 | + |
|
1244 | + // check if this is an array of pairs or just a single pair. |
|
1245 | + $pairs = $options['attribute_name_value_pairs']; |
|
1246 | + if (isset($pairs['name']) || isset($pairs['value'])) { |
|
1247 | + $pairs = [$pairs]; |
|
1248 | + } |
|
1249 | + |
|
1250 | + $pair_wheres = []; |
|
1251 | + foreach ($pairs as $index => $pair) { |
|
1252 | + // must have at least a name and value |
|
1253 | + if (!isset($pair['name']) || !isset($pair['value'])) { |
|
1254 | + continue; |
|
1255 | + } |
|
1256 | + |
|
1257 | + if (isset($pair['operand'])) { |
|
1258 | + $operand = sanitize_string($pair['operand']); |
|
1259 | + } else { |
|
1260 | + $operand = '='; |
|
1261 | + } |
|
1262 | + |
|
1263 | + if (is_numeric($pair['value'])) { |
|
1264 | + $value = sanitize_string($pair['value']); |
|
1265 | + } else if (is_array($pair['value'])) { |
|
1266 | + $values_array = []; |
|
1267 | + foreach ($pair['value'] as $pair_value) { |
|
1268 | + if (is_numeric($pair_value)) { |
|
1269 | + $values_array[] = sanitize_string($pair_value); |
|
1270 | + } else { |
|
1271 | + $values_array[] = "'" . sanitize_string($pair_value) . "'"; |
|
1272 | + } |
|
1273 | + } |
|
1274 | + |
|
1275 | + $operand = 'IN'; |
|
1276 | + if ($values_array) { |
|
1277 | + $value = '(' . implode(', ', $values_array) . ')'; |
|
1278 | + } |
|
1279 | + } else { |
|
1280 | + $value = "'" . sanitize_string($pair['value']) . "'"; |
|
1281 | + } |
|
1282 | + |
|
1283 | + $name = sanitize_string($pair['name']); |
|
1284 | + |
|
1285 | + // case sensitivity can be specified per pair |
|
1286 | + $pair_binary = ''; |
|
1287 | + if (isset($pair['case_sensitive'])) { |
|
1288 | + $pair_binary = ($pair['case_sensitive']) ? 'BINARY ' : ''; |
|
1289 | + } |
|
1290 | + |
|
1291 | + $pair_wheres[] = "({$pair_binary}type_table.$name $operand $value)"; |
|
1292 | + } |
|
1293 | + |
|
1294 | + if ($where = implode(" {$options['attribute_name_value_pairs_operator']} ", $pair_wheres)) { |
|
1295 | + $return['wheres'][] = "($where)"; |
|
1296 | + |
|
1297 | + $return['joins'][] = "JOIN $type_table type_table ON e.guid = type_table.guid"; |
|
1298 | + } |
|
1299 | + |
|
1300 | + return $return; |
|
1301 | + } |
|
1302 | + |
|
1303 | + /** |
|
1304 | + * Returns a list of months in which entities were updated or created. |
|
1305 | + * |
|
1306 | + * @tip Use this to generate a list of archives by month for when entities were added or updated. |
|
1307 | + * |
|
1308 | + * @todo document how to pass in array for $subtype |
|
1309 | + * |
|
1310 | + * @warning Months are returned in the form YYYYMM. |
|
1311 | + * |
|
1312 | + * @param string $type The type of entity |
|
1313 | + * @param string $subtype The subtype of entity |
|
1314 | + * @param int $container_guid The container GUID that the entities belong to |
|
1315 | + * @param string $order_by Order_by SQL order by clause |
|
1316 | + * |
|
1317 | + * @return array|false Either an array months as YYYYMM, or false on failure |
|
1318 | + */ |
|
1319 | + public function getDates($type = '', $subtype = '', $container_guid = 0, $order_by = 'time_created') { |
|
1320 | + |
|
1321 | + $where = []; |
|
1322 | + |
|
1323 | + if ($type != "") { |
|
1324 | + $type = sanitise_string($type); |
|
1325 | + $where[] = "type='$type'"; |
|
1326 | + } |
|
1327 | + |
|
1328 | + if (is_array($subtype)) { |
|
1329 | + $tempwhere = ""; |
|
1330 | + if (sizeof($subtype)) { |
|
1331 | + foreach ($subtype as $typekey => $subtypearray) { |
|
1332 | + foreach ($subtypearray as $subtypeval) { |
|
1333 | + $typekey = sanitise_string($typekey); |
|
1334 | + if (!empty($subtypeval)) { |
|
1335 | + if (!$subtypeval = (int) get_subtype_id($typekey, $subtypeval)) { |
|
1336 | + return false; |
|
1337 | + } |
|
1338 | + } else { |
|
1339 | + $subtypeval = 0; |
|
1340 | + } |
|
1341 | + if (!empty($tempwhere)) { |
|
1342 | + $tempwhere .= " or "; |
|
1343 | + } |
|
1344 | + $tempwhere .= "(type = '{$typekey}' and subtype = {$subtypeval})"; |
|
1345 | + } |
|
1346 | + } |
|
1347 | + } |
|
1348 | + if (!empty($tempwhere)) { |
|
1349 | + $where[] = "({$tempwhere})"; |
|
1350 | + } |
|
1351 | + } else { |
|
1352 | + if ($subtype) { |
|
1353 | + if (!$subtype_id = get_subtype_id($type, $subtype)) { |
|
1354 | + return false; |
|
1355 | + } else { |
|
1356 | + $where[] = "subtype=$subtype_id"; |
|
1357 | + } |
|
1358 | + } |
|
1359 | + } |
|
1360 | + |
|
1361 | + if ($container_guid !== 0) { |
|
1362 | + if (is_array($container_guid)) { |
|
1363 | + foreach ($container_guid as $key => $val) { |
|
1364 | + $container_guid[$key] = (int) $val; |
|
1365 | + } |
|
1366 | + $where[] = "container_guid in (" . implode(",", $container_guid) . ")"; |
|
1367 | + } else { |
|
1368 | + $container_guid = (int) $container_guid; |
|
1369 | + $where[] = "container_guid = {$container_guid}"; |
|
1370 | + } |
|
1371 | + } |
|
1372 | + |
|
1373 | + $where[] = _elgg_get_access_where_sql(['table_alias' => '']); |
|
1374 | + |
|
1375 | + $sql = "SELECT DISTINCT EXTRACT(YEAR_MONTH FROM FROM_UNIXTIME(time_created)) AS yearmonth |
|
1376 | 1376 | FROM {$this->db->prefix}entities where "; |
1377 | 1377 | |
1378 | - foreach ($where as $w) { |
|
1379 | - $sql .= " $w and "; |
|
1380 | - } |
|
1381 | - |
|
1382 | - $sql .= "1=1 ORDER BY $order_by"; |
|
1383 | - if ($result = $this->db->getData($sql)) { |
|
1384 | - $endresult = []; |
|
1385 | - foreach ($result as $res) { |
|
1386 | - $endresult[] = $res->yearmonth; |
|
1387 | - } |
|
1388 | - return $endresult; |
|
1389 | - } |
|
1390 | - return false; |
|
1391 | - } |
|
1392 | - |
|
1393 | - /** |
|
1394 | - * Update the last_action column in the entities table for $guid. |
|
1395 | - * |
|
1396 | - * @warning This is different to time_updated. Time_updated is automatically set, |
|
1397 | - * while last_action is only set when explicitly called. |
|
1398 | - * |
|
1399 | - * @param ElggEntity $entity Entity annotation|relationship action carried out on |
|
1400 | - * @param int $posted Timestamp of last action |
|
1401 | - * @return int |
|
1402 | - * @access private |
|
1403 | - */ |
|
1404 | - public function updateLastAction(ElggEntity $entity, $posted = null) { |
|
1405 | - |
|
1406 | - if (!$posted) { |
|
1407 | - $posted = $this->getCurrentTime()->getTimestamp(); |
|
1408 | - } |
|
1378 | + foreach ($where as $w) { |
|
1379 | + $sql .= " $w and "; |
|
1380 | + } |
|
1381 | + |
|
1382 | + $sql .= "1=1 ORDER BY $order_by"; |
|
1383 | + if ($result = $this->db->getData($sql)) { |
|
1384 | + $endresult = []; |
|
1385 | + foreach ($result as $res) { |
|
1386 | + $endresult[] = $res->yearmonth; |
|
1387 | + } |
|
1388 | + return $endresult; |
|
1389 | + } |
|
1390 | + return false; |
|
1391 | + } |
|
1392 | + |
|
1393 | + /** |
|
1394 | + * Update the last_action column in the entities table for $guid. |
|
1395 | + * |
|
1396 | + * @warning This is different to time_updated. Time_updated is automatically set, |
|
1397 | + * while last_action is only set when explicitly called. |
|
1398 | + * |
|
1399 | + * @param ElggEntity $entity Entity annotation|relationship action carried out on |
|
1400 | + * @param int $posted Timestamp of last action |
|
1401 | + * @return int |
|
1402 | + * @access private |
|
1403 | + */ |
|
1404 | + public function updateLastAction(ElggEntity $entity, $posted = null) { |
|
1405 | + |
|
1406 | + if (!$posted) { |
|
1407 | + $posted = $this->getCurrentTime()->getTimestamp(); |
|
1408 | + } |
|
1409 | 1409 | |
1410 | - $query = " |
|
1410 | + $query = " |
|
1411 | 1411 | UPDATE {$this->db->prefix}entities |
1412 | 1412 | SET last_action = :last_action |
1413 | 1413 | WHERE guid = :guid |
1414 | 1414 | "; |
1415 | 1415 | |
1416 | - $params = [ |
|
1417 | - ':last_action' => (int) $posted, |
|
1418 | - ':guid' => (int) $entity->guid, |
|
1419 | - ]; |
|
1416 | + $params = [ |
|
1417 | + ':last_action' => (int) $posted, |
|
1418 | + ':guid' => (int) $entity->guid, |
|
1419 | + ]; |
|
1420 | 1420 | |
1421 | - $this->db->updateData($query, true, $params); |
|
1422 | - |
|
1423 | - return (int) $posted; |
|
1424 | - } |
|
1425 | - |
|
1426 | - /** |
|
1427 | - * Get a user by GUID even if the entity is hidden or disabled |
|
1428 | - * |
|
1429 | - * @param int $guid User GUID. Default is logged in user |
|
1430 | - * |
|
1431 | - * @return ElggUser|false |
|
1432 | - * @throws UserFetchFailureException |
|
1433 | - * @access private |
|
1434 | - */ |
|
1435 | - public function getUserForPermissionsCheck($guid = 0) { |
|
1436 | - if (!$guid) { |
|
1437 | - return $this->session->getLoggedInUser(); |
|
1438 | - } |
|
1439 | - |
|
1440 | - // need to ignore access and show hidden entities for potential hidden/disabled users |
|
1441 | - $ia = $this->session->setIgnoreAccess(true); |
|
1442 | - $show_hidden = access_show_hidden_entities(true); |
|
1421 | + $this->db->updateData($query, true, $params); |
|
1422 | + |
|
1423 | + return (int) $posted; |
|
1424 | + } |
|
1425 | + |
|
1426 | + /** |
|
1427 | + * Get a user by GUID even if the entity is hidden or disabled |
|
1428 | + * |
|
1429 | + * @param int $guid User GUID. Default is logged in user |
|
1430 | + * |
|
1431 | + * @return ElggUser|false |
|
1432 | + * @throws UserFetchFailureException |
|
1433 | + * @access private |
|
1434 | + */ |
|
1435 | + public function getUserForPermissionsCheck($guid = 0) { |
|
1436 | + if (!$guid) { |
|
1437 | + return $this->session->getLoggedInUser(); |
|
1438 | + } |
|
1439 | + |
|
1440 | + // need to ignore access and show hidden entities for potential hidden/disabled users |
|
1441 | + $ia = $this->session->setIgnoreAccess(true); |
|
1442 | + $show_hidden = access_show_hidden_entities(true); |
|
1443 | 1443 | |
1444 | - $user = $this->get($guid, 'user'); |
|
1445 | - |
|
1446 | - $this->session->setIgnoreAccess($ia); |
|
1447 | - access_show_hidden_entities($show_hidden); |
|
1448 | - |
|
1449 | - if (!$user) { |
|
1450 | - // requested to check access for a specific user_guid, but there is no user entity, so the caller |
|
1451 | - // should cancel the check and return false |
|
1452 | - $message = $this->translator->translate('UserFetchFailureException', [$guid]); |
|
1453 | - // $this->logger->warn($message); |
|
1454 | - |
|
1455 | - throw new UserFetchFailureException($message); |
|
1456 | - } |
|
1457 | - |
|
1458 | - return $user; |
|
1459 | - } |
|
1460 | - |
|
1461 | - /** |
|
1462 | - * Disables all entities owned and contained by a user (or another entity) |
|
1463 | - * |
|
1464 | - * @param int $owner_guid The owner GUID |
|
1465 | - * @return bool |
|
1466 | - */ |
|
1467 | - public function disableEntities($owner_guid) { |
|
1468 | - $entity = get_entity($owner_guid); |
|
1469 | - if (!$entity || !$entity->canEdit()) { |
|
1470 | - return false; |
|
1471 | - } |
|
1472 | - |
|
1473 | - if (!$this->events->trigger('disable', $entity->type, $entity)) { |
|
1474 | - return false; |
|
1475 | - } |
|
1476 | - |
|
1477 | - $query = " |
|
1444 | + $user = $this->get($guid, 'user'); |
|
1445 | + |
|
1446 | + $this->session->setIgnoreAccess($ia); |
|
1447 | + access_show_hidden_entities($show_hidden); |
|
1448 | + |
|
1449 | + if (!$user) { |
|
1450 | + // requested to check access for a specific user_guid, but there is no user entity, so the caller |
|
1451 | + // should cancel the check and return false |
|
1452 | + $message = $this->translator->translate('UserFetchFailureException', [$guid]); |
|
1453 | + // $this->logger->warn($message); |
|
1454 | + |
|
1455 | + throw new UserFetchFailureException($message); |
|
1456 | + } |
|
1457 | + |
|
1458 | + return $user; |
|
1459 | + } |
|
1460 | + |
|
1461 | + /** |
|
1462 | + * Disables all entities owned and contained by a user (or another entity) |
|
1463 | + * |
|
1464 | + * @param int $owner_guid The owner GUID |
|
1465 | + * @return bool |
|
1466 | + */ |
|
1467 | + public function disableEntities($owner_guid) { |
|
1468 | + $entity = get_entity($owner_guid); |
|
1469 | + if (!$entity || !$entity->canEdit()) { |
|
1470 | + return false; |
|
1471 | + } |
|
1472 | + |
|
1473 | + if (!$this->events->trigger('disable', $entity->type, $entity)) { |
|
1474 | + return false; |
|
1475 | + } |
|
1476 | + |
|
1477 | + $query = " |
|
1478 | 1478 | UPDATE {$this->table}entities |
1479 | 1479 | SET enabled='no' |
1480 | 1480 | WHERE owner_guid = :owner_guid |
1481 | 1481 | OR container_guid = :owner_guid"; |
1482 | 1482 | |
1483 | - $params = [ |
|
1484 | - ':owner_guid' => (int) $owner_guid, |
|
1485 | - ]; |
|
1483 | + $params = [ |
|
1484 | + ':owner_guid' => (int) $owner_guid, |
|
1485 | + ]; |
|
1486 | 1486 | |
1487 | - _elgg_invalidate_cache_for_entity($entity->guid); |
|
1488 | - _elgg_invalidate_memcache_for_entity($entity->guid); |
|
1487 | + _elgg_invalidate_cache_for_entity($entity->guid); |
|
1488 | + _elgg_invalidate_memcache_for_entity($entity->guid); |
|
1489 | 1489 | |
1490 | - if ($this->db->updateData($query, true, $params)) { |
|
1491 | - return true; |
|
1492 | - } |
|
1490 | + if ($this->db->updateData($query, true, $params)) { |
|
1491 | + return true; |
|
1492 | + } |
|
1493 | 1493 | |
1494 | - return false; |
|
1495 | - } |
|
1494 | + return false; |
|
1495 | + } |
|
1496 | 1496 | |
1497 | 1497 | } |
@@ -102,7 +102,7 @@ discard block |
||
102 | 102 | } |
103 | 103 | |
104 | 104 | // Test user if possible - should default to false unless a plugin hook says otherwise |
105 | - $default = call_user_func(function () use ($entity, $user) { |
|
105 | + $default = call_user_func(function() use ($entity, $user) { |
|
106 | 106 | if (!$user) { |
107 | 107 | return false; |
108 | 108 | } |
@@ -411,7 +411,7 @@ discard block |
||
411 | 411 | // accepting these for BC |
412 | 412 | $annotation_name = ''; |
413 | 413 | } elseif (!is_string($annotation_name)) { |
414 | - throw new InvalidArgumentException(__METHOD__ . ' expects \$annotation_name to be a string'); |
|
414 | + throw new InvalidArgumentException(__METHOD__.' expects \$annotation_name to be a string'); |
|
415 | 415 | } |
416 | 416 | |
417 | 417 | if ($this->canBypassPermissionsCheck($user_guid)) { |
@@ -22,449 +22,449 @@ |
||
22 | 22 | */ |
23 | 23 | class UserCapabilities { |
24 | 24 | |
25 | - /** |
|
26 | - * @var PluginHooksService $hooks |
|
27 | - */ |
|
28 | - private $hooks; |
|
29 | - |
|
30 | - /** |
|
31 | - * @var EntityTable |
|
32 | - */ |
|
33 | - private $entities; |
|
34 | - |
|
35 | - /** |
|
36 | - * @var ElggSession |
|
37 | - */ |
|
38 | - private $session; |
|
39 | - |
|
40 | - /** |
|
41 | - * Constructor |
|
42 | - * |
|
43 | - * @param PluginHooksService $hooks Plugin hooks service |
|
44 | - * @param EntityTable $entities Entity table |
|
45 | - * @param ElggSession $session Session |
|
46 | - */ |
|
47 | - public function __construct(PluginHooksService $hooks, EntityTable $entities, ElggSession $session) { |
|
48 | - $this->hooks = $hooks; |
|
49 | - $this->entities = $entities; |
|
50 | - $this->session = $session; |
|
51 | - } |
|
52 | - |
|
53 | - /** |
|
54 | - * Decides if the access system should be ignored for a user. |
|
55 | - * |
|
56 | - * Returns true (meaning ignore access) if either of these 2 conditions are true: |
|
57 | - * 1) an admin user guid is passed to this function. |
|
58 | - * 2) {@link elgg_get_ignore_access()} returns true. |
|
59 | - * |
|
60 | - * @see elgg_set_ignore_access() |
|
61 | - * |
|
62 | - * @param int $user_guid The user to check against. |
|
63 | - * |
|
64 | - * @return bool |
|
65 | - */ |
|
66 | - public function canBypassPermissionsCheck($user_guid = 0) { |
|
67 | - if ($this->session->getIgnoreAccess()) { |
|
68 | - // Checking ignored access first to avoid infinite loops, |
|
69 | - // when trying to fetch a user by guid |
|
70 | - return true; |
|
71 | - } |
|
72 | - |
|
73 | - try { |
|
74 | - $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
75 | - } catch (UserFetchFailureException $e) { |
|
76 | - return false; |
|
77 | - } |
|
78 | - |
|
79 | - return $user && $user->isAdmin(); |
|
80 | - } |
|
81 | - |
|
82 | - /** |
|
83 | - * Can a user edit this entity? |
|
84 | - * |
|
85 | - * @tip Can be overridden by registering for the permissions_check plugin hook. |
|
86 | - * |
|
87 | - * @param ElggEntity $entity Object entity |
|
88 | - * @param int $user_guid The user GUID, optionally (default: logged in user) |
|
89 | - * |
|
90 | - * @return bool Whether this entity is editable by the given user. |
|
91 | - * @see elgg_set_ignore_access() |
|
92 | - */ |
|
93 | - public function canEdit(ElggEntity $entity, $user_guid = 0) { |
|
94 | - if ($this->canBypassPermissionsCheck($user_guid)) { |
|
95 | - return true; |
|
96 | - } |
|
97 | - |
|
98 | - try { |
|
99 | - $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
100 | - } catch (UserFetchFailureException $e) { |
|
101 | - return false; |
|
102 | - } |
|
103 | - |
|
104 | - // Test user if possible - should default to false unless a plugin hook says otherwise |
|
105 | - $default = call_user_func(function () use ($entity, $user) { |
|
106 | - if (!$user) { |
|
107 | - return false; |
|
108 | - } |
|
109 | - |
|
110 | - // favor the persisted attributes if not saved |
|
111 | - $attrs = array_merge( |
|
112 | - [ |
|
113 | - 'owner_guid' => $entity->owner_guid, |
|
114 | - 'container_guid' => $entity->container_guid, |
|
115 | - ], $entity->getOriginalAttributes() |
|
116 | - ); |
|
117 | - |
|
118 | - if ($attrs['owner_guid'] == $user->guid) { |
|
119 | - return true; |
|
120 | - } |
|
121 | - |
|
122 | - if ($attrs['container_guid'] == $user->guid) { |
|
123 | - return true; |
|
124 | - } |
|
125 | - |
|
126 | - if ($entity->guid == $user->guid) { |
|
127 | - return true; |
|
128 | - } |
|
129 | - |
|
130 | - $container = $this->entities->get($attrs['container_guid']); |
|
131 | - |
|
132 | - return ($container && $container->canEdit($user->guid)); |
|
133 | - }); |
|
134 | - |
|
135 | - $params = ['entity' => $entity, 'user' => $user]; |
|
136 | - return $this->hooks->trigger('permissions_check', $entity->getType(), $params, $default); |
|
137 | - } |
|
138 | - |
|
139 | - /** |
|
140 | - * Can a user delete this entity? |
|
141 | - * |
|
142 | - * @tip Can be overridden by registering for the permissions_check:delete plugin hook. |
|
143 | - * |
|
144 | - * @param ElggEntity $entity Object entity |
|
145 | - * @param int $user_guid The user GUID, optionally (default: logged in user) |
|
146 | - * |
|
147 | - * @return bool Whether this entity is deletable by the given user. |
|
148 | - * @since 1.11 |
|
149 | - * @see elgg_set_ignore_access() |
|
150 | - */ |
|
151 | - public function canDelete(ElggEntity $entity, $user_guid = 0) { |
|
152 | - if ($this->canBypassPermissionsCheck($user_guid)) { |
|
153 | - return true; |
|
154 | - } |
|
155 | - |
|
156 | - try { |
|
157 | - $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
158 | - } catch (UserFetchFailureException $e) { |
|
159 | - return false; |
|
160 | - } |
|
161 | - |
|
162 | - $return = $entity->canEdit($user_guid); |
|
163 | - |
|
164 | - $params = [ |
|
165 | - 'entity' => $entity, |
|
166 | - 'user' => $user |
|
167 | - ]; |
|
168 | - return $this->hooks->trigger('permissions_check:delete', $entity->getType(), $params, $return); |
|
169 | - } |
|
170 | - |
|
171 | - /** |
|
172 | - * Can a user delete this river item? |
|
173 | - * |
|
174 | - * @tip Can be overridden by registering for the "permissions_check:delete", "river" plugin hook. |
|
175 | - * |
|
176 | - * @param ElggRiverItem $item River item |
|
177 | - * @param int $user_guid The user GUID, optionally (default: logged in user) |
|
178 | - * |
|
179 | - * @return bool Whether this river item should be considered deletable by the given user. |
|
180 | - * @since 2.3 |
|
181 | - * @see elgg_set_ignore_access() |
|
182 | - */ |
|
183 | - public function canDeleteRiverItem(ElggRiverItem $item, $user_guid = 0) { |
|
184 | - if ($this->canBypassPermissionsCheck($user_guid)) { |
|
185 | - return true; |
|
186 | - } |
|
187 | - |
|
188 | - try { |
|
189 | - $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
190 | - } catch (UserFetchFailureException $e) { |
|
191 | - return false; |
|
192 | - } |
|
193 | - |
|
194 | - $params = [ |
|
195 | - 'item' => $item, |
|
196 | - 'user' => $user, |
|
197 | - ]; |
|
198 | - return $this->hooks->trigger('permissions_check:delete', 'river', $params, false); |
|
199 | - } |
|
200 | - |
|
201 | - /** |
|
202 | - * Can a user edit metadata on this entity? |
|
203 | - * |
|
204 | - * If no specific metadata is passed, it returns whether the user can |
|
205 | - * edit any metadata on the entity. |
|
206 | - * |
|
207 | - * @tip Can be overridden by by registering for the permissions_check:metadata |
|
208 | - * plugin hook. |
|
209 | - * |
|
210 | - * @param ElggEntity $entity Object entity |
|
211 | - * @param int $user_guid The user GUID, optionally (default: logged in user) |
|
212 | - * @param ElggMetadata $metadata The piece of metadata to specifically check or null for any metadata |
|
213 | - * |
|
214 | - * @return bool |
|
215 | - * @see elgg_set_ignore_access() |
|
216 | - */ |
|
217 | - public function canEditMetadata(ElggEntity $entity, $user_guid = 0, ElggMetadata $metadata = null) { |
|
218 | - if (!$entity->guid) { |
|
219 | - // @todo cannot edit metadata on unsaved entity? |
|
220 | - return false; |
|
221 | - } |
|
222 | - |
|
223 | - if ($this->canBypassPermissionsCheck($user_guid)) { |
|
224 | - return true; |
|
225 | - } |
|
226 | - |
|
227 | - try { |
|
228 | - $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
229 | - } catch (UserFetchFailureException $e) { |
|
230 | - return false; |
|
231 | - } |
|
232 | - |
|
233 | - if ($user) { |
|
234 | - $user_guid = $user->guid; |
|
235 | - } |
|
236 | - |
|
237 | - // if metadata is not owned or owned by the user, then can edit |
|
238 | - if ($metadata && ($metadata->owner_guid == 0 || $metadata->owner_guid == $user_guid)) { |
|
239 | - $return = true; |
|
240 | - } else { |
|
241 | - $return = $entity->canEdit($user_guid); |
|
242 | - } |
|
243 | - |
|
244 | - // metadata and user may be null |
|
245 | - $params = [ |
|
246 | - 'entity' => $entity, |
|
247 | - 'user' => $user, |
|
248 | - 'metadata' => $metadata |
|
249 | - ]; |
|
250 | - return $this->hooks->trigger('permissions_check:metadata', $entity->getType(), $params, $return); |
|
251 | - } |
|
252 | - |
|
253 | - /** |
|
254 | - * Determines whether or not the user can edit this annotation |
|
255 | - * |
|
256 | - * @param Elggentity $entity Object entity |
|
257 | - * @param int $user_guid The GUID of the user (defaults to currently logged in user) |
|
258 | - * @param ElggAnnotation $annotation Annotation |
|
259 | - * |
|
260 | - * @return bool |
|
261 | - * @see elgg_set_ignore_access() |
|
262 | - */ |
|
263 | - public function canEditAnnotation(ElggEntity $entity, $user_guid = 0, ElggAnnotation $annotation = null) { |
|
264 | - if (!$annotation) { |
|
265 | - return false; |
|
266 | - } |
|
267 | - |
|
268 | - if ($this->canBypassPermissionsCheck($user_guid)) { |
|
269 | - return true; |
|
270 | - } |
|
271 | - |
|
272 | - try { |
|
273 | - $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
274 | - } catch (UserFetchFailureException $e) { |
|
275 | - return false; |
|
276 | - } |
|
277 | - |
|
278 | - $result = false; |
|
279 | - |
|
280 | - if ($user) { |
|
281 | - // If the owner of annotation is the specified user, they can edit. |
|
282 | - if ($annotation->owner_guid == $user->guid) { |
|
283 | - $result = true; |
|
284 | - } |
|
285 | - |
|
286 | - // If the user can edit the entity this is attached to, they can edit. |
|
287 | - if ($result == false && $entity->canEdit($user->guid)) { |
|
288 | - $result = true; |
|
289 | - } |
|
290 | - } |
|
291 | - |
|
292 | - // Trigger plugin hook - note that $user may be null |
|
293 | - $params = [ |
|
294 | - 'entity' => $entity, |
|
295 | - 'user' => $user, |
|
296 | - 'annotation' => $annotation |
|
297 | - ]; |
|
298 | - |
|
299 | - return $this->hooks->trigger('permissions_check', 'annotation', $params, $result); |
|
300 | - } |
|
25 | + /** |
|
26 | + * @var PluginHooksService $hooks |
|
27 | + */ |
|
28 | + private $hooks; |
|
29 | + |
|
30 | + /** |
|
31 | + * @var EntityTable |
|
32 | + */ |
|
33 | + private $entities; |
|
34 | + |
|
35 | + /** |
|
36 | + * @var ElggSession |
|
37 | + */ |
|
38 | + private $session; |
|
39 | + |
|
40 | + /** |
|
41 | + * Constructor |
|
42 | + * |
|
43 | + * @param PluginHooksService $hooks Plugin hooks service |
|
44 | + * @param EntityTable $entities Entity table |
|
45 | + * @param ElggSession $session Session |
|
46 | + */ |
|
47 | + public function __construct(PluginHooksService $hooks, EntityTable $entities, ElggSession $session) { |
|
48 | + $this->hooks = $hooks; |
|
49 | + $this->entities = $entities; |
|
50 | + $this->session = $session; |
|
51 | + } |
|
52 | + |
|
53 | + /** |
|
54 | + * Decides if the access system should be ignored for a user. |
|
55 | + * |
|
56 | + * Returns true (meaning ignore access) if either of these 2 conditions are true: |
|
57 | + * 1) an admin user guid is passed to this function. |
|
58 | + * 2) {@link elgg_get_ignore_access()} returns true. |
|
59 | + * |
|
60 | + * @see elgg_set_ignore_access() |
|
61 | + * |
|
62 | + * @param int $user_guid The user to check against. |
|
63 | + * |
|
64 | + * @return bool |
|
65 | + */ |
|
66 | + public function canBypassPermissionsCheck($user_guid = 0) { |
|
67 | + if ($this->session->getIgnoreAccess()) { |
|
68 | + // Checking ignored access first to avoid infinite loops, |
|
69 | + // when trying to fetch a user by guid |
|
70 | + return true; |
|
71 | + } |
|
72 | + |
|
73 | + try { |
|
74 | + $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
75 | + } catch (UserFetchFailureException $e) { |
|
76 | + return false; |
|
77 | + } |
|
78 | + |
|
79 | + return $user && $user->isAdmin(); |
|
80 | + } |
|
81 | + |
|
82 | + /** |
|
83 | + * Can a user edit this entity? |
|
84 | + * |
|
85 | + * @tip Can be overridden by registering for the permissions_check plugin hook. |
|
86 | + * |
|
87 | + * @param ElggEntity $entity Object entity |
|
88 | + * @param int $user_guid The user GUID, optionally (default: logged in user) |
|
89 | + * |
|
90 | + * @return bool Whether this entity is editable by the given user. |
|
91 | + * @see elgg_set_ignore_access() |
|
92 | + */ |
|
93 | + public function canEdit(ElggEntity $entity, $user_guid = 0) { |
|
94 | + if ($this->canBypassPermissionsCheck($user_guid)) { |
|
95 | + return true; |
|
96 | + } |
|
97 | + |
|
98 | + try { |
|
99 | + $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
100 | + } catch (UserFetchFailureException $e) { |
|
101 | + return false; |
|
102 | + } |
|
103 | + |
|
104 | + // Test user if possible - should default to false unless a plugin hook says otherwise |
|
105 | + $default = call_user_func(function () use ($entity, $user) { |
|
106 | + if (!$user) { |
|
107 | + return false; |
|
108 | + } |
|
109 | + |
|
110 | + // favor the persisted attributes if not saved |
|
111 | + $attrs = array_merge( |
|
112 | + [ |
|
113 | + 'owner_guid' => $entity->owner_guid, |
|
114 | + 'container_guid' => $entity->container_guid, |
|
115 | + ], $entity->getOriginalAttributes() |
|
116 | + ); |
|
117 | + |
|
118 | + if ($attrs['owner_guid'] == $user->guid) { |
|
119 | + return true; |
|
120 | + } |
|
121 | + |
|
122 | + if ($attrs['container_guid'] == $user->guid) { |
|
123 | + return true; |
|
124 | + } |
|
125 | + |
|
126 | + if ($entity->guid == $user->guid) { |
|
127 | + return true; |
|
128 | + } |
|
129 | + |
|
130 | + $container = $this->entities->get($attrs['container_guid']); |
|
131 | + |
|
132 | + return ($container && $container->canEdit($user->guid)); |
|
133 | + }); |
|
134 | + |
|
135 | + $params = ['entity' => $entity, 'user' => $user]; |
|
136 | + return $this->hooks->trigger('permissions_check', $entity->getType(), $params, $default); |
|
137 | + } |
|
138 | + |
|
139 | + /** |
|
140 | + * Can a user delete this entity? |
|
141 | + * |
|
142 | + * @tip Can be overridden by registering for the permissions_check:delete plugin hook. |
|
143 | + * |
|
144 | + * @param ElggEntity $entity Object entity |
|
145 | + * @param int $user_guid The user GUID, optionally (default: logged in user) |
|
146 | + * |
|
147 | + * @return bool Whether this entity is deletable by the given user. |
|
148 | + * @since 1.11 |
|
149 | + * @see elgg_set_ignore_access() |
|
150 | + */ |
|
151 | + public function canDelete(ElggEntity $entity, $user_guid = 0) { |
|
152 | + if ($this->canBypassPermissionsCheck($user_guid)) { |
|
153 | + return true; |
|
154 | + } |
|
155 | + |
|
156 | + try { |
|
157 | + $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
158 | + } catch (UserFetchFailureException $e) { |
|
159 | + return false; |
|
160 | + } |
|
161 | + |
|
162 | + $return = $entity->canEdit($user_guid); |
|
163 | + |
|
164 | + $params = [ |
|
165 | + 'entity' => $entity, |
|
166 | + 'user' => $user |
|
167 | + ]; |
|
168 | + return $this->hooks->trigger('permissions_check:delete', $entity->getType(), $params, $return); |
|
169 | + } |
|
170 | + |
|
171 | + /** |
|
172 | + * Can a user delete this river item? |
|
173 | + * |
|
174 | + * @tip Can be overridden by registering for the "permissions_check:delete", "river" plugin hook. |
|
175 | + * |
|
176 | + * @param ElggRiverItem $item River item |
|
177 | + * @param int $user_guid The user GUID, optionally (default: logged in user) |
|
178 | + * |
|
179 | + * @return bool Whether this river item should be considered deletable by the given user. |
|
180 | + * @since 2.3 |
|
181 | + * @see elgg_set_ignore_access() |
|
182 | + */ |
|
183 | + public function canDeleteRiverItem(ElggRiverItem $item, $user_guid = 0) { |
|
184 | + if ($this->canBypassPermissionsCheck($user_guid)) { |
|
185 | + return true; |
|
186 | + } |
|
187 | + |
|
188 | + try { |
|
189 | + $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
190 | + } catch (UserFetchFailureException $e) { |
|
191 | + return false; |
|
192 | + } |
|
193 | + |
|
194 | + $params = [ |
|
195 | + 'item' => $item, |
|
196 | + 'user' => $user, |
|
197 | + ]; |
|
198 | + return $this->hooks->trigger('permissions_check:delete', 'river', $params, false); |
|
199 | + } |
|
200 | + |
|
201 | + /** |
|
202 | + * Can a user edit metadata on this entity? |
|
203 | + * |
|
204 | + * If no specific metadata is passed, it returns whether the user can |
|
205 | + * edit any metadata on the entity. |
|
206 | + * |
|
207 | + * @tip Can be overridden by by registering for the permissions_check:metadata |
|
208 | + * plugin hook. |
|
209 | + * |
|
210 | + * @param ElggEntity $entity Object entity |
|
211 | + * @param int $user_guid The user GUID, optionally (default: logged in user) |
|
212 | + * @param ElggMetadata $metadata The piece of metadata to specifically check or null for any metadata |
|
213 | + * |
|
214 | + * @return bool |
|
215 | + * @see elgg_set_ignore_access() |
|
216 | + */ |
|
217 | + public function canEditMetadata(ElggEntity $entity, $user_guid = 0, ElggMetadata $metadata = null) { |
|
218 | + if (!$entity->guid) { |
|
219 | + // @todo cannot edit metadata on unsaved entity? |
|
220 | + return false; |
|
221 | + } |
|
222 | + |
|
223 | + if ($this->canBypassPermissionsCheck($user_guid)) { |
|
224 | + return true; |
|
225 | + } |
|
226 | + |
|
227 | + try { |
|
228 | + $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
229 | + } catch (UserFetchFailureException $e) { |
|
230 | + return false; |
|
231 | + } |
|
232 | + |
|
233 | + if ($user) { |
|
234 | + $user_guid = $user->guid; |
|
235 | + } |
|
236 | + |
|
237 | + // if metadata is not owned or owned by the user, then can edit |
|
238 | + if ($metadata && ($metadata->owner_guid == 0 || $metadata->owner_guid == $user_guid)) { |
|
239 | + $return = true; |
|
240 | + } else { |
|
241 | + $return = $entity->canEdit($user_guid); |
|
242 | + } |
|
243 | + |
|
244 | + // metadata and user may be null |
|
245 | + $params = [ |
|
246 | + 'entity' => $entity, |
|
247 | + 'user' => $user, |
|
248 | + 'metadata' => $metadata |
|
249 | + ]; |
|
250 | + return $this->hooks->trigger('permissions_check:metadata', $entity->getType(), $params, $return); |
|
251 | + } |
|
252 | + |
|
253 | + /** |
|
254 | + * Determines whether or not the user can edit this annotation |
|
255 | + * |
|
256 | + * @param Elggentity $entity Object entity |
|
257 | + * @param int $user_guid The GUID of the user (defaults to currently logged in user) |
|
258 | + * @param ElggAnnotation $annotation Annotation |
|
259 | + * |
|
260 | + * @return bool |
|
261 | + * @see elgg_set_ignore_access() |
|
262 | + */ |
|
263 | + public function canEditAnnotation(ElggEntity $entity, $user_guid = 0, ElggAnnotation $annotation = null) { |
|
264 | + if (!$annotation) { |
|
265 | + return false; |
|
266 | + } |
|
267 | + |
|
268 | + if ($this->canBypassPermissionsCheck($user_guid)) { |
|
269 | + return true; |
|
270 | + } |
|
271 | + |
|
272 | + try { |
|
273 | + $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
274 | + } catch (UserFetchFailureException $e) { |
|
275 | + return false; |
|
276 | + } |
|
277 | + |
|
278 | + $result = false; |
|
279 | + |
|
280 | + if ($user) { |
|
281 | + // If the owner of annotation is the specified user, they can edit. |
|
282 | + if ($annotation->owner_guid == $user->guid) { |
|
283 | + $result = true; |
|
284 | + } |
|
285 | + |
|
286 | + // If the user can edit the entity this is attached to, they can edit. |
|
287 | + if ($result == false && $entity->canEdit($user->guid)) { |
|
288 | + $result = true; |
|
289 | + } |
|
290 | + } |
|
291 | + |
|
292 | + // Trigger plugin hook - note that $user may be null |
|
293 | + $params = [ |
|
294 | + 'entity' => $entity, |
|
295 | + 'user' => $user, |
|
296 | + 'annotation' => $annotation |
|
297 | + ]; |
|
298 | + |
|
299 | + return $this->hooks->trigger('permissions_check', 'annotation', $params, $result); |
|
300 | + } |
|
301 | 301 | |
302 | - /** |
|
303 | - * Can a user add an entity to this container |
|
304 | - * |
|
305 | - * @param ElggEntity $entity Container entity |
|
306 | - * @param int $user_guid The GUID of the user creating the entity (0 for logged in user). |
|
307 | - * @param string $type The type of entity we're looking to write |
|
308 | - * @param string $subtype The subtype of the entity we're looking to write |
|
309 | - * |
|
310 | - * @return bool |
|
311 | - * @see elgg_set_ignore_access() |
|
312 | - */ |
|
313 | - public function canWriteToContainer(ElggEntity $entity, $user_guid = 0, $type = 'all', $subtype = 'all') { |
|
314 | - try { |
|
315 | - $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
316 | - } catch (UserFetchFailureException $e) { |
|
317 | - return false; |
|
318 | - } |
|
319 | - |
|
320 | - if ($user) { |
|
321 | - $user_guid = $user->guid; |
|
322 | - } |
|
323 | - |
|
324 | - $params = [ |
|
325 | - 'container' => $entity, |
|
326 | - 'user' => $user, |
|
327 | - 'subtype' => $subtype |
|
328 | - ]; |
|
329 | - |
|
330 | - // Unlike permissions, logic check can be used to prevent certain entity |
|
331 | - // types from being contained by other entity types, |
|
332 | - // e.g. discussion reply objects can only be contained by discussion objects. |
|
333 | - // This hook can also be used to apply status logic, e.g. to disallow |
|
334 | - // new replies in closed discussions. |
|
335 | - // We do not take a stand hence the return is null. This can be used by |
|
336 | - // handlers to check if another hook has modified the value. |
|
337 | - $logic_check = $this->hooks->trigger('container_logic_check', $type, $params); |
|
338 | - |
|
339 | - if ($logic_check === false) { |
|
340 | - return false; |
|
341 | - } |
|
342 | - |
|
343 | - if ($this->canBypassPermissionsCheck($user_guid)) { |
|
344 | - return true; |
|
345 | - } |
|
346 | - |
|
347 | - $return = false; |
|
348 | - if ($entity) { |
|
349 | - // If the user can edit the container, they can also write to it |
|
350 | - if ($entity->canEdit($user_guid)) { |
|
351 | - $return = true; |
|
352 | - } |
|
353 | - } |
|
354 | - |
|
355 | - // Container permissions can prevent users from writing to an entity. |
|
356 | - // For instance, these permissions can prevent non-group members from writing |
|
357 | - // content to the group. |
|
358 | - return $this->hooks->trigger('container_permissions_check', $type, $params, $return); |
|
359 | - } |
|
360 | - |
|
361 | - /** |
|
362 | - * Can a user comment on an entity? |
|
363 | - * |
|
364 | - * @tip Can be overridden by registering for the permissions_check:comment, |
|
365 | - * <entity type> plugin hook. |
|
366 | - * |
|
367 | - * @param ElggEntity $entity Object entity |
|
368 | - * @param int $user_guid User guid (default is logged in user) |
|
369 | - * @param bool $default Default permission |
|
370 | - * @return bool |
|
371 | - */ |
|
372 | - public function canComment(ElggEntity $entity, $user_guid = 0, $default = null) { |
|
373 | - if ($this->canBypassPermissionsCheck($user_guid)) { |
|
374 | - return true; |
|
375 | - } |
|
376 | - |
|
377 | - try { |
|
378 | - $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
379 | - } catch (UserFetchFailureException $e) { |
|
380 | - return false; |
|
381 | - } |
|
382 | - |
|
383 | - // By default, we don't take a position of whether commenting is allowed |
|
384 | - // because it is handled by the subclasses of \ElggEntity |
|
385 | - $params = [ |
|
386 | - 'entity' => $entity, |
|
387 | - 'user' => $user |
|
388 | - ]; |
|
389 | - return $this->hooks->trigger('permissions_check:comment', $entity->getType(), $params, $default); |
|
390 | - } |
|
391 | - |
|
392 | - /** |
|
393 | - * Can a user annotate an entity? |
|
394 | - * |
|
395 | - * @tip Can be overridden by registering for the plugin hook [permissions_check:annotate:<name>, |
|
396 | - * <entity type>] or [permissions_check:annotate, <entity type>]. The hooks are called in that order. |
|
397 | - * |
|
398 | - * @tip If you want logged out users to annotate an object, do not call |
|
399 | - * canAnnotate(). It's easier than using the plugin hook. |
|
400 | - * |
|
401 | - * @param ElggEntity $entity Objet entity |
|
402 | - * @param int $user_guid User guid (default is logged in user) |
|
403 | - * @param string $annotation_name The name of the annotation (default is unspecified) |
|
404 | - * |
|
405 | - * @return bool |
|
406 | - */ |
|
407 | - public function canAnnotate(ElggEntity $entity, $user_guid = 0, $annotation_name = '') { |
|
408 | - if ($annotation_name === null || $annotation_name === false) { |
|
409 | - // accepting these for BC |
|
410 | - $annotation_name = ''; |
|
411 | - } elseif (!is_string($annotation_name)) { |
|
412 | - throw new InvalidArgumentException(__METHOD__ . ' expects \$annotation_name to be a string'); |
|
413 | - } |
|
414 | - |
|
415 | - if ($this->canBypassPermissionsCheck($user_guid)) { |
|
416 | - return true; |
|
417 | - } |
|
418 | - |
|
419 | - try { |
|
420 | - $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
421 | - } catch (UserFetchFailureException $e) { |
|
422 | - return false; |
|
423 | - } |
|
424 | - |
|
425 | - $return = (bool) $user; |
|
426 | - |
|
427 | - $params = [ |
|
428 | - 'entity' => $entity, |
|
429 | - 'user' => $user, |
|
430 | - 'annotation_name' => $annotation_name, |
|
431 | - ]; |
|
432 | - |
|
433 | - if (!empty($annotation_name)) { |
|
434 | - $return = $this->hooks->trigger("permissions_check:annotate:$annotation_name", $entity->getType(), $params, $return); |
|
435 | - } |
|
436 | - |
|
437 | - return $this->hooks->trigger('permissions_check:annotate', $entity->getType(), $params, $return); |
|
438 | - } |
|
439 | - |
|
440 | - /** |
|
441 | - * Can a user download a file? |
|
442 | - * |
|
443 | - * @tip Can be overridden by registering for the permissions_check:download,file plugin hook. |
|
444 | - * |
|
445 | - * @param ElggFile $entity File entity |
|
446 | - * @param int $user_guid User guid (default is logged in user) |
|
447 | - * @param bool $default Default permission |
|
448 | - * |
|
449 | - * @return bool |
|
450 | - */ |
|
451 | - public function canDownload(ElggFile $entity, $user_guid = 0, $default = true) { |
|
452 | - if ($this->canBypassPermissionsCheck($user_guid)) { |
|
453 | - return true; |
|
454 | - } |
|
455 | - |
|
456 | - try { |
|
457 | - $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
458 | - } catch (UserFetchFailureException $e) { |
|
459 | - return false; |
|
460 | - } |
|
461 | - |
|
462 | - $params = [ |
|
463 | - 'entity' => $entity, |
|
464 | - 'user' => $user |
|
465 | - ]; |
|
466 | - |
|
467 | - return $this->hooks->trigger('permissions_check:download', 'file', $params, $default); |
|
468 | - } |
|
302 | + /** |
|
303 | + * Can a user add an entity to this container |
|
304 | + * |
|
305 | + * @param ElggEntity $entity Container entity |
|
306 | + * @param int $user_guid The GUID of the user creating the entity (0 for logged in user). |
|
307 | + * @param string $type The type of entity we're looking to write |
|
308 | + * @param string $subtype The subtype of the entity we're looking to write |
|
309 | + * |
|
310 | + * @return bool |
|
311 | + * @see elgg_set_ignore_access() |
|
312 | + */ |
|
313 | + public function canWriteToContainer(ElggEntity $entity, $user_guid = 0, $type = 'all', $subtype = 'all') { |
|
314 | + try { |
|
315 | + $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
316 | + } catch (UserFetchFailureException $e) { |
|
317 | + return false; |
|
318 | + } |
|
319 | + |
|
320 | + if ($user) { |
|
321 | + $user_guid = $user->guid; |
|
322 | + } |
|
323 | + |
|
324 | + $params = [ |
|
325 | + 'container' => $entity, |
|
326 | + 'user' => $user, |
|
327 | + 'subtype' => $subtype |
|
328 | + ]; |
|
329 | + |
|
330 | + // Unlike permissions, logic check can be used to prevent certain entity |
|
331 | + // types from being contained by other entity types, |
|
332 | + // e.g. discussion reply objects can only be contained by discussion objects. |
|
333 | + // This hook can also be used to apply status logic, e.g. to disallow |
|
334 | + // new replies in closed discussions. |
|
335 | + // We do not take a stand hence the return is null. This can be used by |
|
336 | + // handlers to check if another hook has modified the value. |
|
337 | + $logic_check = $this->hooks->trigger('container_logic_check', $type, $params); |
|
338 | + |
|
339 | + if ($logic_check === false) { |
|
340 | + return false; |
|
341 | + } |
|
342 | + |
|
343 | + if ($this->canBypassPermissionsCheck($user_guid)) { |
|
344 | + return true; |
|
345 | + } |
|
346 | + |
|
347 | + $return = false; |
|
348 | + if ($entity) { |
|
349 | + // If the user can edit the container, they can also write to it |
|
350 | + if ($entity->canEdit($user_guid)) { |
|
351 | + $return = true; |
|
352 | + } |
|
353 | + } |
|
354 | + |
|
355 | + // Container permissions can prevent users from writing to an entity. |
|
356 | + // For instance, these permissions can prevent non-group members from writing |
|
357 | + // content to the group. |
|
358 | + return $this->hooks->trigger('container_permissions_check', $type, $params, $return); |
|
359 | + } |
|
360 | + |
|
361 | + /** |
|
362 | + * Can a user comment on an entity? |
|
363 | + * |
|
364 | + * @tip Can be overridden by registering for the permissions_check:comment, |
|
365 | + * <entity type> plugin hook. |
|
366 | + * |
|
367 | + * @param ElggEntity $entity Object entity |
|
368 | + * @param int $user_guid User guid (default is logged in user) |
|
369 | + * @param bool $default Default permission |
|
370 | + * @return bool |
|
371 | + */ |
|
372 | + public function canComment(ElggEntity $entity, $user_guid = 0, $default = null) { |
|
373 | + if ($this->canBypassPermissionsCheck($user_guid)) { |
|
374 | + return true; |
|
375 | + } |
|
376 | + |
|
377 | + try { |
|
378 | + $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
379 | + } catch (UserFetchFailureException $e) { |
|
380 | + return false; |
|
381 | + } |
|
382 | + |
|
383 | + // By default, we don't take a position of whether commenting is allowed |
|
384 | + // because it is handled by the subclasses of \ElggEntity |
|
385 | + $params = [ |
|
386 | + 'entity' => $entity, |
|
387 | + 'user' => $user |
|
388 | + ]; |
|
389 | + return $this->hooks->trigger('permissions_check:comment', $entity->getType(), $params, $default); |
|
390 | + } |
|
391 | + |
|
392 | + /** |
|
393 | + * Can a user annotate an entity? |
|
394 | + * |
|
395 | + * @tip Can be overridden by registering for the plugin hook [permissions_check:annotate:<name>, |
|
396 | + * <entity type>] or [permissions_check:annotate, <entity type>]. The hooks are called in that order. |
|
397 | + * |
|
398 | + * @tip If you want logged out users to annotate an object, do not call |
|
399 | + * canAnnotate(). It's easier than using the plugin hook. |
|
400 | + * |
|
401 | + * @param ElggEntity $entity Objet entity |
|
402 | + * @param int $user_guid User guid (default is logged in user) |
|
403 | + * @param string $annotation_name The name of the annotation (default is unspecified) |
|
404 | + * |
|
405 | + * @return bool |
|
406 | + */ |
|
407 | + public function canAnnotate(ElggEntity $entity, $user_guid = 0, $annotation_name = '') { |
|
408 | + if ($annotation_name === null || $annotation_name === false) { |
|
409 | + // accepting these for BC |
|
410 | + $annotation_name = ''; |
|
411 | + } elseif (!is_string($annotation_name)) { |
|
412 | + throw new InvalidArgumentException(__METHOD__ . ' expects \$annotation_name to be a string'); |
|
413 | + } |
|
414 | + |
|
415 | + if ($this->canBypassPermissionsCheck($user_guid)) { |
|
416 | + return true; |
|
417 | + } |
|
418 | + |
|
419 | + try { |
|
420 | + $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
421 | + } catch (UserFetchFailureException $e) { |
|
422 | + return false; |
|
423 | + } |
|
424 | + |
|
425 | + $return = (bool) $user; |
|
426 | + |
|
427 | + $params = [ |
|
428 | + 'entity' => $entity, |
|
429 | + 'user' => $user, |
|
430 | + 'annotation_name' => $annotation_name, |
|
431 | + ]; |
|
432 | + |
|
433 | + if (!empty($annotation_name)) { |
|
434 | + $return = $this->hooks->trigger("permissions_check:annotate:$annotation_name", $entity->getType(), $params, $return); |
|
435 | + } |
|
436 | + |
|
437 | + return $this->hooks->trigger('permissions_check:annotate', $entity->getType(), $params, $return); |
|
438 | + } |
|
439 | + |
|
440 | + /** |
|
441 | + * Can a user download a file? |
|
442 | + * |
|
443 | + * @tip Can be overridden by registering for the permissions_check:download,file plugin hook. |
|
444 | + * |
|
445 | + * @param ElggFile $entity File entity |
|
446 | + * @param int $user_guid User guid (default is logged in user) |
|
447 | + * @param bool $default Default permission |
|
448 | + * |
|
449 | + * @return bool |
|
450 | + */ |
|
451 | + public function canDownload(ElggFile $entity, $user_guid = 0, $default = true) { |
|
452 | + if ($this->canBypassPermissionsCheck($user_guid)) { |
|
453 | + return true; |
|
454 | + } |
|
455 | + |
|
456 | + try { |
|
457 | + $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
458 | + } catch (UserFetchFailureException $e) { |
|
459 | + return false; |
|
460 | + } |
|
461 | + |
|
462 | + $params = [ |
|
463 | + 'entity' => $entity, |
|
464 | + 'user' => $user |
|
465 | + ]; |
|
466 | + |
|
467 | + return $this->hooks->trigger('permissions_check:download', 'file', $params, $default); |
|
468 | + } |
|
469 | 469 | |
470 | 470 | } |
@@ -40,2162 +40,2162 @@ |
||
40 | 40 | * @property string $location A location of the entity |
41 | 41 | */ |
42 | 42 | abstract class ElggEntity extends \ElggData implements |
43 | - Locatable, // Geocoding interface |
|
44 | - \Elgg\EntityIcon // Icon interface |
|
43 | + Locatable, // Geocoding interface |
|
44 | + \Elgg\EntityIcon // Icon interface |
|
45 | 45 | { |
46 | 46 | |
47 | - /** |
|
48 | - * Holds metadata until entity is saved. Once the entity is saved, |
|
49 | - * metadata are written immediately to the database. |
|
50 | - */ |
|
51 | - protected $temp_metadata = []; |
|
52 | - |
|
53 | - /** |
|
54 | - * Holds annotations until entity is saved. Once the entity is saved, |
|
55 | - * annotations are written immediately to the database. |
|
56 | - */ |
|
57 | - protected $temp_annotations = []; |
|
58 | - |
|
59 | - /** |
|
60 | - * Holds private settings until entity is saved. Once the entity is saved, |
|
61 | - * private settings are written immediately to the database. |
|
62 | - */ |
|
63 | - protected $temp_private_settings = []; |
|
64 | - |
|
65 | - /** |
|
66 | - * Volatile data structure for this object, allows for storage of data |
|
67 | - * in-memory that isn't sync'd back to the metadata table. |
|
68 | - */ |
|
69 | - protected $volatile = []; |
|
70 | - |
|
71 | - /** |
|
72 | - * Holds the original (persisted) attribute values that have been changed but not yet saved. |
|
73 | - */ |
|
74 | - protected $orig_attributes = []; |
|
75 | - |
|
76 | - /** |
|
77 | - * Create a new entity. |
|
78 | - * |
|
79 | - * Plugin developers should only use the constructor to create a new entity. |
|
80 | - * To retrieve entities, use get_entity() and the elgg_get_entities* functions. |
|
81 | - * |
|
82 | - * If no arguments are passed, it creates a new entity. |
|
83 | - * If a database result is passed as a \stdClass instance, it instantiates |
|
84 | - * that entity. |
|
85 | - * |
|
86 | - * @param \stdClass $row Database row result. Default is null to create a new object. |
|
87 | - * |
|
88 | - * @throws IOException If cannot load remaining data from db |
|
89 | - */ |
|
90 | - public function __construct(\stdClass $row = null) { |
|
91 | - $this->initializeAttributes(); |
|
92 | - |
|
93 | - if ($row && !$this->load($row)) { |
|
94 | - $msg = "Failed to load new " . get_class() . " for GUID:" . $row->guid; |
|
95 | - throw new \IOException($msg); |
|
96 | - } |
|
97 | - } |
|
98 | - |
|
99 | - /** |
|
100 | - * Initialize the attributes array. |
|
101 | - * |
|
102 | - * This is vital to distinguish between metadata and base parameters. |
|
103 | - * |
|
104 | - * @return void |
|
105 | - */ |
|
106 | - protected function initializeAttributes() { |
|
107 | - parent::initializeAttributes(); |
|
108 | - |
|
109 | - $this->attributes['guid'] = null; |
|
110 | - $this->attributes['type'] = null; |
|
111 | - $this->attributes['subtype'] = null; |
|
112 | - |
|
113 | - $this->attributes['owner_guid'] = _elgg_services()->session->getLoggedInUserGuid(); |
|
114 | - $this->attributes['container_guid'] = _elgg_services()->session->getLoggedInUserGuid(); |
|
115 | - |
|
116 | - $this->attributes['access_id'] = ACCESS_PRIVATE; |
|
117 | - $this->attributes['time_updated'] = null; |
|
118 | - $this->attributes['last_action'] = null; |
|
119 | - $this->attributes['enabled'] = "yes"; |
|
120 | - |
|
121 | - $this->attributes['type'] = $this->getType(); |
|
122 | - $this->attributes += self::getExtraAttributeDefaults($this->getType()); |
|
123 | - } |
|
124 | - |
|
125 | - /** |
|
126 | - * Clone an entity |
|
127 | - * |
|
128 | - * Resets the guid so that the entity can be saved as a distinct entity from |
|
129 | - * the original. Creation time will be set when this new entity is saved. |
|
130 | - * The owner and container guids come from the original entity. The clone |
|
131 | - * method copies metadata but does not copy annotations or private settings. |
|
132 | - * |
|
133 | - * @note metadata will have its owner and access id set when the entity is saved |
|
134 | - * and it will be the same as that of the entity. |
|
135 | - * |
|
136 | - * @return void |
|
137 | - */ |
|
138 | - public function __clone() { |
|
139 | - $orig_entity = get_entity($this->guid); |
|
140 | - if (!$orig_entity) { |
|
141 | - _elgg_services()->logger->error("Failed to clone entity with GUID $this->guid"); |
|
142 | - return; |
|
143 | - } |
|
144 | - |
|
145 | - $metadata_array = elgg_get_metadata([ |
|
146 | - 'guid' => $this->guid, |
|
147 | - 'limit' => 0 |
|
148 | - ]); |
|
149 | - |
|
150 | - $this->attributes['guid'] = null; |
|
151 | - $this->attributes['time_created'] = null; |
|
152 | - $this->attributes['time_updated'] = null; |
|
153 | - $this->attributes['last_action'] = null; |
|
154 | - |
|
155 | - $this->attributes['subtype'] = $orig_entity->getSubtype(); |
|
156 | - |
|
157 | - // copy metadata over to new entity - slightly convoluted due to |
|
158 | - // handling of metadata arrays |
|
159 | - if (is_array($metadata_array)) { |
|
160 | - // create list of metadata names |
|
161 | - $metadata_names = []; |
|
162 | - foreach ($metadata_array as $metadata) { |
|
163 | - $metadata_names[] = $metadata['name']; |
|
164 | - } |
|
165 | - // arrays are stored with multiple enties per name |
|
166 | - $metadata_names = array_unique($metadata_names); |
|
167 | - |
|
168 | - // move the metadata over |
|
169 | - foreach ($metadata_names as $name) { |
|
170 | - $this->__set($name, $orig_entity->$name); |
|
171 | - } |
|
172 | - } |
|
173 | - } |
|
174 | - |
|
175 | - /** |
|
176 | - * Set an attribute or metadata value for this entity |
|
177 | - * |
|
178 | - * Anything that is not an attribute is saved as metadata. |
|
179 | - * |
|
180 | - * @warning Metadata set this way will inherit the entity's owner and |
|
181 | - * access ID. If you want more control over metadata, use \ElggEntity::setMetadata() |
|
182 | - * |
|
183 | - * @param string $name Name of the attribute or metadata |
|
184 | - * @param mixed $value The value to be set |
|
185 | - * @return void |
|
186 | - * @see \ElggEntity::setMetadata() |
|
187 | - */ |
|
188 | - public function __set($name, $value) { |
|
189 | - if ($this->$name === $value) { |
|
190 | - // quick return if value is not changing |
|
191 | - return; |
|
192 | - } |
|
193 | - |
|
194 | - if (array_key_exists($name, $this->attributes)) { |
|
195 | - // if an attribute is 1 (integer) and it's set to "1" (string), don't consider that a change. |
|
196 | - if (is_int($this->attributes[$name]) |
|
197 | - && is_string($value) |
|
198 | - && ((string) $this->attributes[$name] === $value)) { |
|
199 | - return; |
|
200 | - } |
|
201 | - |
|
202 | - // Due to https://github.com/Elgg/Elgg/pull/5456#issuecomment-17785173, certain attributes |
|
203 | - // will store empty strings as null in the DB. In the somewhat common case that we're re-setting |
|
204 | - // the value to empty string, don't consider this a change. |
|
205 | - if (in_array($name, ['title', 'name', 'description']) |
|
206 | - && $this->attributes[$name] === null |
|
207 | - && $value === "") { |
|
208 | - return; |
|
209 | - } |
|
210 | - |
|
211 | - // keep original values |
|
212 | - if ($this->guid && !array_key_exists($name, $this->orig_attributes)) { |
|
213 | - $this->orig_attributes[$name] = $this->attributes[$name]; |
|
214 | - } |
|
215 | - |
|
216 | - // Certain properties should not be manually changed! |
|
217 | - switch ($name) { |
|
218 | - case 'guid': |
|
219 | - case 'time_updated': |
|
220 | - case 'last_action': |
|
221 | - return; |
|
222 | - break; |
|
223 | - case 'access_id': |
|
224 | - case 'owner_guid': |
|
225 | - case 'container_guid': |
|
226 | - if ($value !== null) { |
|
227 | - $this->attributes[$name] = (int) $value; |
|
228 | - } else { |
|
229 | - $this->attributes[$name] = null; |
|
230 | - } |
|
231 | - break; |
|
232 | - default: |
|
233 | - $this->attributes[$name] = $value; |
|
234 | - break; |
|
235 | - } |
|
236 | - return; |
|
237 | - } |
|
238 | - |
|
239 | - $this->setMetadata($name, $value); |
|
240 | - } |
|
241 | - |
|
242 | - /** |
|
243 | - * Get the original values of attribute(s) that have been modified since the entity was persisted. |
|
244 | - * |
|
245 | - * @return array |
|
246 | - */ |
|
247 | - public function getOriginalAttributes() { |
|
248 | - return $this->orig_attributes; |
|
249 | - } |
|
250 | - |
|
251 | - /** |
|
252 | - * Get an attribute or metadata value |
|
253 | - * |
|
254 | - * If the name matches an attribute, the attribute is returned. If metadata |
|
255 | - * does not exist with that name, a null is returned. |
|
256 | - * |
|
257 | - * This only returns an array if there are multiple values for a particular |
|
258 | - * $name key. |
|
259 | - * |
|
260 | - * @param string $name Name of the attribute or metadata |
|
261 | - * @return mixed |
|
262 | - */ |
|
263 | - public function __get($name) { |
|
264 | - if (array_key_exists($name, $this->attributes)) { |
|
265 | - if ($name === 'subtype' && $this->attributes['guid']) { |
|
266 | - _elgg_services()->logger->warn('Reading ->subtype on a persisted entity is unreliable.'); |
|
267 | - } |
|
268 | - return $this->attributes[$name]; |
|
269 | - } |
|
270 | - |
|
271 | - return $this->getMetadata($name); |
|
272 | - } |
|
273 | - |
|
274 | - /** |
|
275 | - * Get the entity's display name |
|
276 | - * |
|
277 | - * @return string The title or name of this entity. |
|
278 | - */ |
|
279 | - public function getDisplayName() { |
|
280 | - $attr = $this->getSecondaryTableColumns()[0]; |
|
281 | - return $this->$attr; |
|
282 | - } |
|
283 | - |
|
284 | - /** |
|
285 | - * Sets the title or name of this entity. |
|
286 | - * |
|
287 | - * @param string $display_name The title or name of this entity. |
|
288 | - * @return void |
|
289 | - */ |
|
290 | - public function setDisplayName($display_name) { |
|
291 | - $attr = $this->getSecondaryTableColumns()[0]; |
|
292 | - $this->$attr = $display_name; |
|
293 | - } |
|
294 | - |
|
295 | - /** |
|
296 | - * Return the value of a piece of metadata. |
|
297 | - * |
|
298 | - * @param string $name Name |
|
299 | - * |
|
300 | - * @return mixed The value, or null if not found. |
|
301 | - */ |
|
302 | - public function getMetadata($name) { |
|
303 | - $guid = $this->guid; |
|
304 | - |
|
305 | - if (!$guid) { |
|
306 | - if (isset($this->temp_metadata[$name])) { |
|
307 | - // md is returned as an array only if more than 1 entry |
|
308 | - if (count($this->temp_metadata[$name]) == 1) { |
|
309 | - return $this->temp_metadata[$name][0]; |
|
310 | - } else { |
|
311 | - return $this->temp_metadata[$name]; |
|
312 | - } |
|
313 | - } else { |
|
314 | - return null; |
|
315 | - } |
|
316 | - } |
|
317 | - |
|
318 | - // upon first cache miss, just load/cache all the metadata and retry. |
|
319 | - // if this works, the rest of this function may not be needed! |
|
320 | - $cache = _elgg_services()->metadataCache; |
|
321 | - if ($cache->isLoaded($guid)) { |
|
322 | - return $cache->getSingle($guid, $name); |
|
323 | - } else { |
|
324 | - $cache->populateFromEntities([$guid]); |
|
325 | - // in case ignore_access was on, we have to check again... |
|
326 | - if ($cache->isLoaded($guid)) { |
|
327 | - return $cache->getSingle($guid, $name); |
|
328 | - } |
|
329 | - } |
|
330 | - |
|
331 | - $md = elgg_get_metadata([ |
|
332 | - 'guid' => $guid, |
|
333 | - 'metadata_name' => $name, |
|
334 | - 'limit' => 0, |
|
335 | - 'distinct' => false, |
|
336 | - ]); |
|
337 | - |
|
338 | - $value = null; |
|
339 | - |
|
340 | - if ($md && !is_array($md)) { |
|
341 | - $value = $md->value; |
|
342 | - } elseif (count($md) == 1) { |
|
343 | - $value = $md[0]->value; |
|
344 | - } else if ($md && is_array($md)) { |
|
345 | - $value = metadata_array_to_values($md); |
|
346 | - } |
|
347 | - |
|
348 | - return $value; |
|
349 | - } |
|
350 | - |
|
351 | - /** |
|
352 | - * Unset a property from metadata or attribute. |
|
353 | - * |
|
354 | - * @warning If you use this to unset an attribute, you must save the object! |
|
355 | - * |
|
356 | - * @param string $name The name of the attribute or metadata. |
|
357 | - * |
|
358 | - * @return void |
|
359 | - * @todo some attributes should be set to null or other default values |
|
360 | - */ |
|
361 | - public function __unset($name) { |
|
362 | - if (array_key_exists($name, $this->attributes)) { |
|
363 | - $this->attributes[$name] = ""; |
|
364 | - } else { |
|
365 | - $this->deleteMetadata($name); |
|
366 | - } |
|
367 | - } |
|
368 | - |
|
369 | - /** |
|
370 | - * Set metadata on this entity. |
|
371 | - * |
|
372 | - * Plugin developers usually want to use the magic set method ($entity->name = 'value'). |
|
373 | - * Use this method if you want to explicitly set the owner or access of the metadata. |
|
374 | - * You cannot set the owner/access before the entity has been saved. |
|
375 | - * |
|
376 | - * @param string $name Name of the metadata |
|
377 | - * @param mixed $value Value of the metadata (doesn't support assoc arrays) |
|
378 | - * @param string $value_type 'text', 'integer', or '' for automatic detection |
|
379 | - * @param bool $multiple Allow multiple values for a single name. |
|
380 | - * Does not support associative arrays. |
|
381 | - * @param int $owner_guid GUID of entity that owns the metadata. |
|
382 | - * Default is owner of entity. |
|
383 | - * |
|
384 | - * @return bool |
|
385 | - * @throws InvalidArgumentException |
|
386 | - */ |
|
387 | - public function setMetadata($name, $value, $value_type = '', $multiple = false, $owner_guid = 0) { |
|
388 | - |
|
389 | - // normalize value to an array that we will loop over |
|
390 | - // remove indexes if value already an array. |
|
391 | - if (is_array($value)) { |
|
392 | - $value = array_values($value); |
|
393 | - } else { |
|
394 | - $value = [$value]; |
|
395 | - } |
|
396 | - |
|
397 | - // saved entity. persist md to db. |
|
398 | - if ($this->guid) { |
|
399 | - // if overwriting, delete first. |
|
400 | - if (!$multiple) { |
|
401 | - $options = [ |
|
402 | - 'guid' => $this->getGUID(), |
|
403 | - 'metadata_name' => $name, |
|
404 | - 'limit' => 0 |
|
405 | - ]; |
|
406 | - // @todo in 1.9 make this return false if can't add metadata |
|
407 | - // https://github.com/elgg/elgg/issues/4520 |
|
408 | - // |
|
409 | - // need to remove access restrictions right now to delete |
|
410 | - // because this is the expected behavior |
|
411 | - $ia = elgg_set_ignore_access(true); |
|
412 | - $delete_result = elgg_delete_metadata($options); |
|
413 | - elgg_set_ignore_access($ia); |
|
414 | - |
|
415 | - if (false === $delete_result) { |
|
416 | - return false; |
|
417 | - } |
|
418 | - } |
|
419 | - |
|
420 | - $owner_guid = $owner_guid ? (int) $owner_guid : $this->owner_guid; |
|
421 | - |
|
422 | - // add new md |
|
423 | - foreach ($value as $value_tmp) { |
|
424 | - // at this point $value is appended because it was cleared above if needed. |
|
425 | - $md_id = _elgg_services()->metadataTable->create($this->guid, $name, $value_tmp, $value_type, |
|
426 | - $owner_guid, null, true); |
|
427 | - if (!$md_id) { |
|
428 | - return false; |
|
429 | - } |
|
430 | - } |
|
431 | - |
|
432 | - return true; |
|
433 | - } else { |
|
434 | - // unsaved entity. store in temp array |
|
435 | - |
|
436 | - // returning single entries instead of an array of 1 element is decided in |
|
437 | - // getMetaData(), just like pulling from the db. |
|
438 | - |
|
439 | - if ($owner_guid != 0) { |
|
440 | - $msg = "owner guid cannot be used in ElggEntity::setMetadata() until entity is saved."; |
|
441 | - throw new \InvalidArgumentException($msg); |
|
442 | - } |
|
443 | - |
|
444 | - // if overwrite, delete first |
|
445 | - if (!$multiple || !isset($this->temp_metadata[$name])) { |
|
446 | - $this->temp_metadata[$name] = []; |
|
447 | - } |
|
448 | - |
|
449 | - // add new md |
|
450 | - $this->temp_metadata[$name] = array_merge($this->temp_metadata[$name], $value); |
|
451 | - return true; |
|
452 | - } |
|
453 | - } |
|
454 | - |
|
455 | - /** |
|
456 | - * Deletes all metadata on this object (metadata.entity_guid = $this->guid). |
|
457 | - * If you pass a name, only metadata matching that name will be deleted. |
|
458 | - * |
|
459 | - * @warning Calling this with no $name will clear all metadata on the entity. |
|
460 | - * |
|
461 | - * @param null|string $name The name of the metadata to remove. |
|
462 | - * @return bool |
|
463 | - * @since 1.8 |
|
464 | - */ |
|
465 | - public function deleteMetadata($name = null) { |
|
466 | - |
|
467 | - if (!$this->guid) { |
|
468 | - return false; |
|
469 | - } |
|
470 | - |
|
471 | - $options = [ |
|
472 | - 'guid' => $this->guid, |
|
473 | - 'limit' => 0 |
|
474 | - ]; |
|
475 | - if ($name) { |
|
476 | - $options['metadata_name'] = $name; |
|
477 | - } |
|
478 | - |
|
479 | - return elgg_delete_metadata($options); |
|
480 | - } |
|
481 | - |
|
482 | - /** |
|
483 | - * Deletes all metadata owned by this object (metadata.owner_guid = $this->guid). |
|
484 | - * If you pass a name, only metadata matching that name will be deleted. |
|
485 | - * |
|
486 | - * @param null|string $name The name of metadata to delete. |
|
487 | - * @return bool |
|
488 | - * @since 1.8 |
|
489 | - */ |
|
490 | - public function deleteOwnedMetadata($name = null) { |
|
491 | - // access is turned off for this because they might |
|
492 | - // no longer have access to an entity they created metadata on. |
|
493 | - $ia = elgg_set_ignore_access(true); |
|
494 | - $options = [ |
|
495 | - 'metadata_owner_guid' => $this->guid, |
|
496 | - 'limit' => 0 |
|
497 | - ]; |
|
498 | - if ($name) { |
|
499 | - $options['metadata_name'] = $name; |
|
500 | - } |
|
501 | - |
|
502 | - $r = elgg_delete_metadata($options); |
|
503 | - elgg_set_ignore_access($ia); |
|
504 | - return $r; |
|
505 | - } |
|
506 | - |
|
507 | - /** |
|
508 | - * Disables metadata for this entity, optionally based on name. |
|
509 | - * |
|
510 | - * @param string $name An options name of metadata to disable. |
|
511 | - * @return bool |
|
512 | - * @since 1.8 |
|
513 | - */ |
|
514 | - public function disableMetadata($name = '') { |
|
515 | - $options = [ |
|
516 | - 'guid' => $this->guid, |
|
517 | - 'limit' => 0 |
|
518 | - ]; |
|
519 | - if ($name) { |
|
520 | - $options['metadata_name'] = $name; |
|
521 | - } |
|
522 | - |
|
523 | - return elgg_disable_metadata($options); |
|
524 | - } |
|
525 | - |
|
526 | - /** |
|
527 | - * Enables metadata for this entity, optionally based on name. |
|
528 | - * |
|
529 | - * @warning Before calling this, you must use {@link access_show_hidden_entities()} |
|
530 | - * |
|
531 | - * @param string $name An options name of metadata to enable. |
|
532 | - * @return bool |
|
533 | - * @since 1.8 |
|
534 | - */ |
|
535 | - public function enableMetadata($name = '') { |
|
536 | - $options = [ |
|
537 | - 'guid' => $this->guid, |
|
538 | - 'limit' => 0 |
|
539 | - ]; |
|
540 | - if ($name) { |
|
541 | - $options['metadata_name'] = $name; |
|
542 | - } |
|
543 | - |
|
544 | - return elgg_enable_metadata($options); |
|
545 | - } |
|
546 | - |
|
547 | - /** |
|
548 | - * Get a piece of volatile (non-persisted) data on this entity. |
|
549 | - * |
|
550 | - * @param string $name The name of the volatile data |
|
551 | - * |
|
552 | - * @return mixed The value or null if not found. |
|
553 | - */ |
|
554 | - public function getVolatileData($name) { |
|
555 | - return array_key_exists($name, $this->volatile) ? $this->volatile[$name] : null; |
|
556 | - } |
|
557 | - |
|
558 | - /** |
|
559 | - * Set a piece of volatile (non-persisted) data on this entity |
|
560 | - * |
|
561 | - * @param string $name Name |
|
562 | - * @param mixed $value Value |
|
563 | - * |
|
564 | - * @return void |
|
565 | - */ |
|
566 | - public function setVolatileData($name, $value) { |
|
567 | - $this->volatile[$name] = $value; |
|
568 | - } |
|
569 | - |
|
570 | - /** |
|
571 | - * Cache the entity in a persisted cache |
|
572 | - * |
|
573 | - * @param ElggSharedMemoryCache $cache Memcache or null cache |
|
574 | - * @param int $last_action Last action time |
|
575 | - * |
|
576 | - * @return void |
|
577 | - * @access private |
|
578 | - * @internal |
|
579 | - */ |
|
580 | - public function storeInPersistedCache(\ElggSharedMemoryCache $cache, $last_action = 0) { |
|
581 | - $tmp = $this->volatile; |
|
582 | - |
|
583 | - // don't store volatile data |
|
584 | - $this->volatile = []; |
|
585 | - if ($last_action) { |
|
586 | - $this->attributes['last_action'] = (int) $last_action; |
|
587 | - } |
|
588 | - $cache->save($this->guid, $this); |
|
589 | - |
|
590 | - $this->volatile = $tmp; |
|
591 | - } |
|
592 | - |
|
593 | - /** |
|
594 | - * Remove all relationships to and from this entity. |
|
595 | - * If you pass a relationship name, only relationships matching that name |
|
596 | - * will be deleted. |
|
597 | - * |
|
598 | - * @warning Calling this with no $relationship will clear all relationships |
|
599 | - * for this entity. |
|
600 | - * |
|
601 | - * @param null|string $relationship The name of the relationship to remove. |
|
602 | - * @return bool |
|
603 | - * @see \ElggEntity::addRelationship() |
|
604 | - * @see \ElggEntity::removeRelationship() |
|
605 | - */ |
|
606 | - public function deleteRelationships($relationship = null) { |
|
607 | - $relationship = (string) $relationship; |
|
608 | - $result = remove_entity_relationships($this->getGUID(), $relationship); |
|
609 | - return $result && remove_entity_relationships($this->getGUID(), $relationship, true); |
|
610 | - } |
|
611 | - |
|
612 | - /** |
|
613 | - * Add a relationship between this an another entity. |
|
614 | - * |
|
615 | - * @tip Read the relationship like "This entity is a $relationship of $guid_two." |
|
616 | - * |
|
617 | - * @param int $guid_two GUID of the target entity of the relationship. |
|
618 | - * @param string $relationship The type of relationship. |
|
619 | - * |
|
620 | - * @return bool |
|
621 | - * @see \ElggEntity::removeRelationship() |
|
622 | - * @see \ElggEntity::deleteRelationships() |
|
623 | - */ |
|
624 | - public function addRelationship($guid_two, $relationship) { |
|
625 | - return add_entity_relationship($this->getGUID(), $relationship, $guid_two); |
|
626 | - } |
|
627 | - |
|
628 | - /** |
|
629 | - * Remove a relationship |
|
630 | - * |
|
631 | - * @param int $guid_two GUID of the target entity of the relationship. |
|
632 | - * @param string $relationship The type of relationship. |
|
633 | - * |
|
634 | - * @return bool |
|
635 | - * @see \ElggEntity::addRelationship() |
|
636 | - * @see \ElggEntity::deleteRelationships() |
|
637 | - */ |
|
638 | - public function removeRelationship($guid_two, $relationship) { |
|
639 | - return remove_entity_relationship($this->getGUID(), $relationship, $guid_two); |
|
640 | - } |
|
641 | - |
|
642 | - /** |
|
643 | - * Adds a private setting to this entity. |
|
644 | - * |
|
645 | - * Private settings are similar to metadata but will not |
|
646 | - * be searched and there are fewer helper functions for them. |
|
647 | - * |
|
648 | - * @param string $name Name of private setting |
|
649 | - * @param mixed $value Value of private setting |
|
650 | - * |
|
651 | - * @return bool |
|
652 | - */ |
|
653 | - public function setPrivateSetting($name, $value) { |
|
654 | - if ((int) $this->guid > 0) { |
|
655 | - return set_private_setting($this->getGUID(), $name, $value); |
|
656 | - } else { |
|
657 | - $this->temp_private_settings[$name] = $value; |
|
658 | - return true; |
|
659 | - } |
|
660 | - } |
|
661 | - |
|
662 | - /** |
|
663 | - * Returns a private setting value |
|
664 | - * |
|
665 | - * @param string $name Name of the private setting |
|
666 | - * |
|
667 | - * @return mixed Null if the setting does not exist |
|
668 | - */ |
|
669 | - public function getPrivateSetting($name) { |
|
670 | - if ((int) ($this->guid) > 0) { |
|
671 | - return get_private_setting($this->getGUID(), $name); |
|
672 | - } else { |
|
673 | - if (isset($this->temp_private_settings[$name])) { |
|
674 | - return $this->temp_private_settings[$name]; |
|
675 | - } |
|
676 | - } |
|
677 | - return null; |
|
678 | - } |
|
679 | - |
|
680 | - /** |
|
681 | - * Removes private setting |
|
682 | - * |
|
683 | - * @param string $name Name of the private setting |
|
684 | - * |
|
685 | - * @return bool |
|
686 | - */ |
|
687 | - public function removePrivateSetting($name) { |
|
688 | - return remove_private_setting($this->getGUID(), $name); |
|
689 | - } |
|
690 | - |
|
691 | - /** |
|
692 | - * Deletes all annotations on this object (annotations.entity_guid = $this->guid). |
|
693 | - * If you pass a name, only annotations matching that name will be deleted. |
|
694 | - * |
|
695 | - * @warning Calling this with no or empty arguments will clear all annotations on the entity. |
|
696 | - * |
|
697 | - * @param null|string $name The annotations name to remove. |
|
698 | - * @return bool |
|
699 | - * @since 1.8 |
|
700 | - */ |
|
701 | - public function deleteAnnotations($name = null) { |
|
702 | - $options = [ |
|
703 | - 'guid' => $this->guid, |
|
704 | - 'limit' => 0 |
|
705 | - ]; |
|
706 | - if ($name) { |
|
707 | - $options['annotation_name'] = $name; |
|
708 | - } |
|
709 | - |
|
710 | - return elgg_delete_annotations($options); |
|
711 | - } |
|
712 | - |
|
713 | - /** |
|
714 | - * Deletes all annotations owned by this object (annotations.owner_guid = $this->guid). |
|
715 | - * If you pass a name, only annotations matching that name will be deleted. |
|
716 | - * |
|
717 | - * @param null|string $name The name of annotations to delete. |
|
718 | - * @return bool |
|
719 | - * @since 1.8 |
|
720 | - */ |
|
721 | - public function deleteOwnedAnnotations($name = null) { |
|
722 | - // access is turned off for this because they might |
|
723 | - // no longer have access to an entity they created annotations on. |
|
724 | - $ia = elgg_set_ignore_access(true); |
|
725 | - $options = [ |
|
726 | - 'annotation_owner_guid' => $this->guid, |
|
727 | - 'limit' => 0 |
|
728 | - ]; |
|
729 | - if ($name) { |
|
730 | - $options['annotation_name'] = $name; |
|
731 | - } |
|
732 | - |
|
733 | - $r = elgg_delete_annotations($options); |
|
734 | - elgg_set_ignore_access($ia); |
|
735 | - return $r; |
|
736 | - } |
|
737 | - |
|
738 | - /** |
|
739 | - * Disables annotations for this entity, optionally based on name. |
|
740 | - * |
|
741 | - * @param string $name An options name of annotations to disable. |
|
742 | - * @return bool |
|
743 | - * @since 1.8 |
|
744 | - */ |
|
745 | - public function disableAnnotations($name = '') { |
|
746 | - $options = [ |
|
747 | - 'guid' => $this->guid, |
|
748 | - 'limit' => 0 |
|
749 | - ]; |
|
750 | - if ($name) { |
|
751 | - $options['annotation_name'] = $name; |
|
752 | - } |
|
753 | - |
|
754 | - return elgg_disable_annotations($options); |
|
755 | - } |
|
756 | - |
|
757 | - /** |
|
758 | - * Enables annotations for this entity, optionally based on name. |
|
759 | - * |
|
760 | - * @warning Before calling this, you must use {@link access_show_hidden_entities()} |
|
761 | - * |
|
762 | - * @param string $name An options name of annotations to enable. |
|
763 | - * @return bool |
|
764 | - * @since 1.8 |
|
765 | - */ |
|
766 | - public function enableAnnotations($name = '') { |
|
767 | - $options = [ |
|
768 | - 'guid' => $this->guid, |
|
769 | - 'limit' => 0 |
|
770 | - ]; |
|
771 | - if ($name) { |
|
772 | - $options['annotation_name'] = $name; |
|
773 | - } |
|
774 | - |
|
775 | - return elgg_enable_annotations($options); |
|
776 | - } |
|
777 | - |
|
778 | - /** |
|
779 | - * Helper function to return annotation calculation results |
|
780 | - * |
|
781 | - * @param string $name The annotation name. |
|
782 | - * @param string $calculation A valid MySQL function to run its values through |
|
783 | - * @return mixed |
|
784 | - */ |
|
785 | - private function getAnnotationCalculation($name, $calculation) { |
|
786 | - $options = [ |
|
787 | - 'guid' => $this->getGUID(), |
|
788 | - 'distinct' => false, |
|
789 | - 'annotation_name' => $name, |
|
790 | - 'annotation_calculation' => $calculation |
|
791 | - ]; |
|
792 | - |
|
793 | - return elgg_get_annotations($options); |
|
794 | - } |
|
795 | - |
|
796 | - /** |
|
797 | - * Adds an annotation to an entity. |
|
798 | - * |
|
799 | - * @warning By default, annotations are private. |
|
800 | - * |
|
801 | - * @warning Annotating an unsaved entity more than once with the same name |
|
802 | - * will only save the last annotation. |
|
803 | - * |
|
804 | - * @param string $name Annotation name |
|
805 | - * @param mixed $value Annotation value |
|
806 | - * @param int $access_id Access ID |
|
807 | - * @param int $owner_guid GUID of the annotation owner |
|
808 | - * @param string $vartype The type of annotation value |
|
809 | - * |
|
810 | - * @return bool|int Returns int if an annotation is saved |
|
811 | - */ |
|
812 | - public function annotate($name, $value, $access_id = ACCESS_PRIVATE, $owner_guid = 0, $vartype = "") { |
|
813 | - if ((int) $this->guid > 0) { |
|
814 | - return create_annotation($this->getGUID(), $name, $value, $vartype, $owner_guid, $access_id); |
|
815 | - } else { |
|
816 | - $this->temp_annotations[$name] = $value; |
|
817 | - } |
|
818 | - return true; |
|
819 | - } |
|
820 | - |
|
821 | - /** |
|
822 | - * Gets an array of annotations. |
|
823 | - * |
|
824 | - * To retrieve annotations on an unsaved entity, pass array('name' => [annotation name]) |
|
825 | - * as the options array. |
|
826 | - * |
|
827 | - * @param array $options Array of options for elgg_get_annotations() except guid. |
|
828 | - * |
|
829 | - * @return array |
|
830 | - * @see elgg_get_annotations() |
|
831 | - */ |
|
832 | - public function getAnnotations(array $options = []) { |
|
833 | - if ($this->guid) { |
|
834 | - $options['guid'] = $this->guid; |
|
835 | - |
|
836 | - return elgg_get_annotations($options); |
|
837 | - } else { |
|
838 | - $name = elgg_extract('annotation_name', $options, ''); |
|
839 | - |
|
840 | - if (isset($this->temp_annotations[$name])) { |
|
841 | - return [$this->temp_annotations[$name]]; |
|
842 | - } |
|
843 | - } |
|
844 | - |
|
845 | - return []; |
|
846 | - } |
|
847 | - |
|
848 | - /** |
|
849 | - * Count annotations. |
|
850 | - * |
|
851 | - * @param string $name The type of annotation. |
|
852 | - * |
|
853 | - * @return int |
|
854 | - */ |
|
855 | - public function countAnnotations($name = "") { |
|
856 | - return $this->getAnnotationCalculation($name, 'count'); |
|
857 | - } |
|
858 | - |
|
859 | - /** |
|
860 | - * Get the average of an integer type annotation. |
|
861 | - * |
|
862 | - * @param string $name Annotation name |
|
863 | - * |
|
864 | - * @return int |
|
865 | - */ |
|
866 | - public function getAnnotationsAvg($name) { |
|
867 | - return $this->getAnnotationCalculation($name, 'avg'); |
|
868 | - } |
|
869 | - |
|
870 | - /** |
|
871 | - * Get the sum of integer type annotations of a given name. |
|
872 | - * |
|
873 | - * @param string $name Annotation name |
|
874 | - * |
|
875 | - * @return int |
|
876 | - */ |
|
877 | - public function getAnnotationsSum($name) { |
|
878 | - return $this->getAnnotationCalculation($name, 'sum'); |
|
879 | - } |
|
880 | - |
|
881 | - /** |
|
882 | - * Get the minimum of integer type annotations of given name. |
|
883 | - * |
|
884 | - * @param string $name Annotation name |
|
885 | - * |
|
886 | - * @return int |
|
887 | - */ |
|
888 | - public function getAnnotationsMin($name) { |
|
889 | - return $this->getAnnotationCalculation($name, 'min'); |
|
890 | - } |
|
891 | - |
|
892 | - /** |
|
893 | - * Get the maximum of integer type annotations of a given name. |
|
894 | - * |
|
895 | - * @param string $name Annotation name |
|
896 | - * |
|
897 | - * @return int |
|
898 | - */ |
|
899 | - public function getAnnotationsMax($name) { |
|
900 | - return $this->getAnnotationCalculation($name, 'max'); |
|
901 | - } |
|
902 | - |
|
903 | - /** |
|
904 | - * Count the number of comments attached to this entity. |
|
905 | - * |
|
906 | - * @return int Number of comments |
|
907 | - * @since 1.8.0 |
|
908 | - */ |
|
909 | - public function countComments() { |
|
910 | - $params = ['entity' => $this]; |
|
911 | - $num = _elgg_services()->hooks->trigger('comments:count', $this->getType(), $params); |
|
912 | - |
|
913 | - if (is_int($num)) { |
|
914 | - return $num; |
|
915 | - } else { |
|
916 | - return elgg_get_entities([ |
|
917 | - 'type' => 'object', |
|
918 | - 'subtype' => 'comment', |
|
919 | - 'container_guid' => $this->getGUID(), |
|
920 | - 'count' => true, |
|
921 | - 'distinct' => false, |
|
922 | - ]); |
|
923 | - } |
|
924 | - } |
|
925 | - |
|
926 | - /** |
|
927 | - * Gets an array of entities with a relationship to this entity. |
|
928 | - * |
|
929 | - * @param array $options Options array. See elgg_get_entities_from_relationship() |
|
930 | - * for a list of options. 'relationship_guid' is set to |
|
931 | - * this entity. |
|
932 | - * |
|
933 | - * @return array|false An array of entities or false on failure |
|
934 | - * @see elgg_get_entities_from_relationship() |
|
935 | - */ |
|
936 | - public function getEntitiesFromRelationship(array $options = []) { |
|
937 | - $options['relationship_guid'] = $this->guid; |
|
938 | - return elgg_get_entities_from_relationship($options); |
|
939 | - } |
|
940 | - |
|
941 | - /** |
|
942 | - * Gets the number of entities from a specific relationship type |
|
943 | - * |
|
944 | - * @param string $relationship Relationship type (eg "friends") |
|
945 | - * @param bool $inverse_relationship Invert relationship |
|
946 | - * |
|
947 | - * @return int|false The number of entities or false on failure |
|
948 | - */ |
|
949 | - public function countEntitiesFromRelationship($relationship, $inverse_relationship = false) { |
|
950 | - return elgg_get_entities_from_relationship([ |
|
951 | - 'relationship' => $relationship, |
|
952 | - 'relationship_guid' => $this->getGUID(), |
|
953 | - 'inverse_relationship' => $inverse_relationship, |
|
954 | - 'count' => true |
|
955 | - ]); |
|
956 | - } |
|
957 | - |
|
958 | - /** |
|
959 | - * Can a user edit this entity? |
|
960 | - * |
|
961 | - * @tip Can be overridden by registering for the permissions_check plugin hook. |
|
962 | - * |
|
963 | - * @param int $user_guid The user GUID, optionally (default: logged in user) |
|
964 | - * |
|
965 | - * @return bool Whether this entity is editable by the given user. |
|
966 | - * @see elgg_set_ignore_access() |
|
967 | - */ |
|
968 | - public function canEdit($user_guid = 0) { |
|
969 | - return _elgg_services()->userCapabilities->canEdit($this, $user_guid); |
|
970 | - } |
|
971 | - |
|
972 | - /** |
|
973 | - * Can a user delete this entity? |
|
974 | - * |
|
975 | - * @tip Can be overridden by registering for the permissions_check:delete plugin hook. |
|
976 | - * |
|
977 | - * @param int $user_guid The user GUID, optionally (default: logged in user) |
|
978 | - * |
|
979 | - * @return bool Whether this entity is deletable by the given user. |
|
980 | - * @since 1.11 |
|
981 | - * @see elgg_set_ignore_access() |
|
982 | - */ |
|
983 | - public function canDelete($user_guid = 0) { |
|
984 | - return _elgg_services()->userCapabilities->canDelete($this, $user_guid); |
|
985 | - } |
|
986 | - |
|
987 | - /** |
|
988 | - * Can a user edit metadata on this entity? |
|
989 | - * |
|
990 | - * If no specific metadata is passed, it returns whether the user can |
|
991 | - * edit any metadata on the entity. |
|
992 | - * |
|
993 | - * @tip Can be overridden by by registering for the permissions_check:metadata |
|
994 | - * plugin hook. |
|
995 | - * |
|
996 | - * @param \ElggMetadata $metadata The piece of metadata to specifically check or null for any metadata |
|
997 | - * @param int $user_guid The user GUID, optionally (default: logged in user) |
|
998 | - * |
|
999 | - * @return bool |
|
1000 | - * @see elgg_set_ignore_access() |
|
1001 | - */ |
|
1002 | - public function canEditMetadata($metadata = null, $user_guid = 0) { |
|
1003 | - return _elgg_services()->userCapabilities->canEditMetadata($this, $user_guid, $metadata); |
|
1004 | - } |
|
1005 | - |
|
1006 | - /** |
|
1007 | - * Can a user add an entity to this container |
|
1008 | - * |
|
1009 | - * @param int $user_guid The GUID of the user creating the entity (0 for logged in user). |
|
1010 | - * @param string $type The type of entity we're looking to write |
|
1011 | - * @param string $subtype The subtype of the entity we're looking to write |
|
1012 | - * |
|
1013 | - * @return bool |
|
1014 | - * @see elgg_set_ignore_access() |
|
1015 | - */ |
|
1016 | - public function canWriteToContainer($user_guid = 0, $type = 'all', $subtype = 'all') { |
|
1017 | - return _elgg_services()->userCapabilities->canWriteToContainer($this, $user_guid, $type, $subtype); |
|
1018 | - } |
|
1019 | - |
|
1020 | - /** |
|
1021 | - * Can a user comment on an entity? |
|
1022 | - * |
|
1023 | - * @tip Can be overridden by registering for the permissions_check:comment, |
|
1024 | - * <entity type> plugin hook. |
|
1025 | - * |
|
1026 | - * @param int $user_guid User guid (default is logged in user) |
|
1027 | - * @param bool $default Default permission |
|
1028 | - * @return bool |
|
1029 | - */ |
|
1030 | - public function canComment($user_guid = 0, $default = null) { |
|
1031 | - return _elgg_services()->userCapabilities->canComment($this, $user_guid, $default); |
|
1032 | - } |
|
1033 | - |
|
1034 | - /** |
|
1035 | - * Can a user annotate an entity? |
|
1036 | - * |
|
1037 | - * @tip Can be overridden by registering for the plugin hook [permissions_check:annotate:<name>, |
|
1038 | - * <entity type>] or [permissions_check:annotate, <entity type>]. The hooks are called in that order. |
|
1039 | - * |
|
1040 | - * @tip If you want logged out users to annotate an object, do not call |
|
1041 | - * canAnnotate(). It's easier than using the plugin hook. |
|
1042 | - * |
|
1043 | - * @param int $user_guid User guid (default is logged in user) |
|
1044 | - * @param string $annotation_name The name of the annotation (default is unspecified) |
|
1045 | - * |
|
1046 | - * @return bool |
|
1047 | - */ |
|
1048 | - public function canAnnotate($user_guid = 0, $annotation_name = '') { |
|
1049 | - return _elgg_services()->userCapabilities->canAnnotate($this, $user_guid, $annotation_name); |
|
1050 | - } |
|
1051 | - |
|
1052 | - /** |
|
1053 | - * Returns the access_id. |
|
1054 | - * |
|
1055 | - * @return int The access ID |
|
1056 | - */ |
|
1057 | - public function getAccessID() { |
|
1058 | - return $this->access_id; |
|
1059 | - } |
|
1060 | - |
|
1061 | - /** |
|
1062 | - * Returns the guid. |
|
1063 | - * |
|
1064 | - * @return int|null GUID |
|
1065 | - */ |
|
1066 | - public function getGUID() { |
|
1067 | - return $this->guid; |
|
1068 | - } |
|
1069 | - |
|
1070 | - /** |
|
1071 | - * Returns the entity type |
|
1072 | - * |
|
1073 | - * @return string The entity type |
|
1074 | - */ |
|
1075 | - public function getType() { |
|
1076 | - // this is just for the PHPUnit mocking framework |
|
1077 | - return $this->type; |
|
1078 | - } |
|
1079 | - |
|
1080 | - /** |
|
1081 | - * Get the entity subtype |
|
1082 | - * |
|
1083 | - * @return string The entity subtype |
|
1084 | - */ |
|
1085 | - public function getSubtype() { |
|
1086 | - // If this object hasn't been saved, then return the subtype string. |
|
1087 | - if ($this->attributes['guid']) { |
|
1088 | - return get_subtype_from_id($this->attributes['subtype']); |
|
1089 | - } |
|
1090 | - return $this->attributes['subtype']; |
|
1091 | - } |
|
1092 | - |
|
1093 | - /** |
|
1094 | - * Get the guid of the entity's owner. |
|
1095 | - * |
|
1096 | - * @return int The owner GUID |
|
1097 | - */ |
|
1098 | - public function getOwnerGUID() { |
|
1099 | - return (int) $this->owner_guid; |
|
1100 | - } |
|
1101 | - |
|
1102 | - /** |
|
1103 | - * Gets the \ElggEntity that owns this entity. |
|
1104 | - * |
|
1105 | - * @return \ElggEntity The owning entity |
|
1106 | - */ |
|
1107 | - public function getOwnerEntity() { |
|
1108 | - return get_entity($this->owner_guid); |
|
1109 | - } |
|
1110 | - |
|
1111 | - /** |
|
1112 | - * Set the container for this object. |
|
1113 | - * |
|
1114 | - * @param int $container_guid The ID of the container. |
|
1115 | - * |
|
1116 | - * @return bool |
|
1117 | - */ |
|
1118 | - public function setContainerGUID($container_guid) { |
|
1119 | - return $this->container_guid = (int) $container_guid; |
|
1120 | - } |
|
1121 | - |
|
1122 | - /** |
|
1123 | - * Gets the container GUID for this entity. |
|
1124 | - * |
|
1125 | - * @return int |
|
1126 | - */ |
|
1127 | - public function getContainerGUID() { |
|
1128 | - return (int) $this->container_guid; |
|
1129 | - } |
|
1130 | - |
|
1131 | - /** |
|
1132 | - * Get the container entity for this object. |
|
1133 | - * |
|
1134 | - * @return \ElggEntity |
|
1135 | - * @since 1.8.0 |
|
1136 | - */ |
|
1137 | - public function getContainerEntity() { |
|
1138 | - return get_entity($this->getContainerGUID()); |
|
1139 | - } |
|
1140 | - |
|
1141 | - /** |
|
1142 | - * Returns the UNIX epoch time that this entity was last updated |
|
1143 | - * |
|
1144 | - * @return int UNIX epoch time |
|
1145 | - */ |
|
1146 | - public function getTimeUpdated() { |
|
1147 | - return $this->time_updated; |
|
1148 | - } |
|
1149 | - |
|
1150 | - /** |
|
1151 | - * Gets the URL for this entity. |
|
1152 | - * |
|
1153 | - * Plugins can register for the 'entity:url', <type> plugin hook to |
|
1154 | - * customize the url for an entity. |
|
1155 | - * |
|
1156 | - * @return string The URL of the entity |
|
1157 | - */ |
|
1158 | - public function getURL() { |
|
1159 | - $url = _elgg_services()->hooks->trigger('entity:url', $this->getType(), ['entity' => $this]); |
|
47 | + /** |
|
48 | + * Holds metadata until entity is saved. Once the entity is saved, |
|
49 | + * metadata are written immediately to the database. |
|
50 | + */ |
|
51 | + protected $temp_metadata = []; |
|
52 | + |
|
53 | + /** |
|
54 | + * Holds annotations until entity is saved. Once the entity is saved, |
|
55 | + * annotations are written immediately to the database. |
|
56 | + */ |
|
57 | + protected $temp_annotations = []; |
|
58 | + |
|
59 | + /** |
|
60 | + * Holds private settings until entity is saved. Once the entity is saved, |
|
61 | + * private settings are written immediately to the database. |
|
62 | + */ |
|
63 | + protected $temp_private_settings = []; |
|
64 | + |
|
65 | + /** |
|
66 | + * Volatile data structure for this object, allows for storage of data |
|
67 | + * in-memory that isn't sync'd back to the metadata table. |
|
68 | + */ |
|
69 | + protected $volatile = []; |
|
70 | + |
|
71 | + /** |
|
72 | + * Holds the original (persisted) attribute values that have been changed but not yet saved. |
|
73 | + */ |
|
74 | + protected $orig_attributes = []; |
|
75 | + |
|
76 | + /** |
|
77 | + * Create a new entity. |
|
78 | + * |
|
79 | + * Plugin developers should only use the constructor to create a new entity. |
|
80 | + * To retrieve entities, use get_entity() and the elgg_get_entities* functions. |
|
81 | + * |
|
82 | + * If no arguments are passed, it creates a new entity. |
|
83 | + * If a database result is passed as a \stdClass instance, it instantiates |
|
84 | + * that entity. |
|
85 | + * |
|
86 | + * @param \stdClass $row Database row result. Default is null to create a new object. |
|
87 | + * |
|
88 | + * @throws IOException If cannot load remaining data from db |
|
89 | + */ |
|
90 | + public function __construct(\stdClass $row = null) { |
|
91 | + $this->initializeAttributes(); |
|
92 | + |
|
93 | + if ($row && !$this->load($row)) { |
|
94 | + $msg = "Failed to load new " . get_class() . " for GUID:" . $row->guid; |
|
95 | + throw new \IOException($msg); |
|
96 | + } |
|
97 | + } |
|
98 | + |
|
99 | + /** |
|
100 | + * Initialize the attributes array. |
|
101 | + * |
|
102 | + * This is vital to distinguish between metadata and base parameters. |
|
103 | + * |
|
104 | + * @return void |
|
105 | + */ |
|
106 | + protected function initializeAttributes() { |
|
107 | + parent::initializeAttributes(); |
|
108 | + |
|
109 | + $this->attributes['guid'] = null; |
|
110 | + $this->attributes['type'] = null; |
|
111 | + $this->attributes['subtype'] = null; |
|
112 | + |
|
113 | + $this->attributes['owner_guid'] = _elgg_services()->session->getLoggedInUserGuid(); |
|
114 | + $this->attributes['container_guid'] = _elgg_services()->session->getLoggedInUserGuid(); |
|
115 | + |
|
116 | + $this->attributes['access_id'] = ACCESS_PRIVATE; |
|
117 | + $this->attributes['time_updated'] = null; |
|
118 | + $this->attributes['last_action'] = null; |
|
119 | + $this->attributes['enabled'] = "yes"; |
|
120 | + |
|
121 | + $this->attributes['type'] = $this->getType(); |
|
122 | + $this->attributes += self::getExtraAttributeDefaults($this->getType()); |
|
123 | + } |
|
124 | + |
|
125 | + /** |
|
126 | + * Clone an entity |
|
127 | + * |
|
128 | + * Resets the guid so that the entity can be saved as a distinct entity from |
|
129 | + * the original. Creation time will be set when this new entity is saved. |
|
130 | + * The owner and container guids come from the original entity. The clone |
|
131 | + * method copies metadata but does not copy annotations or private settings. |
|
132 | + * |
|
133 | + * @note metadata will have its owner and access id set when the entity is saved |
|
134 | + * and it will be the same as that of the entity. |
|
135 | + * |
|
136 | + * @return void |
|
137 | + */ |
|
138 | + public function __clone() { |
|
139 | + $orig_entity = get_entity($this->guid); |
|
140 | + if (!$orig_entity) { |
|
141 | + _elgg_services()->logger->error("Failed to clone entity with GUID $this->guid"); |
|
142 | + return; |
|
143 | + } |
|
144 | + |
|
145 | + $metadata_array = elgg_get_metadata([ |
|
146 | + 'guid' => $this->guid, |
|
147 | + 'limit' => 0 |
|
148 | + ]); |
|
149 | + |
|
150 | + $this->attributes['guid'] = null; |
|
151 | + $this->attributes['time_created'] = null; |
|
152 | + $this->attributes['time_updated'] = null; |
|
153 | + $this->attributes['last_action'] = null; |
|
154 | + |
|
155 | + $this->attributes['subtype'] = $orig_entity->getSubtype(); |
|
156 | + |
|
157 | + // copy metadata over to new entity - slightly convoluted due to |
|
158 | + // handling of metadata arrays |
|
159 | + if (is_array($metadata_array)) { |
|
160 | + // create list of metadata names |
|
161 | + $metadata_names = []; |
|
162 | + foreach ($metadata_array as $metadata) { |
|
163 | + $metadata_names[] = $metadata['name']; |
|
164 | + } |
|
165 | + // arrays are stored with multiple enties per name |
|
166 | + $metadata_names = array_unique($metadata_names); |
|
167 | + |
|
168 | + // move the metadata over |
|
169 | + foreach ($metadata_names as $name) { |
|
170 | + $this->__set($name, $orig_entity->$name); |
|
171 | + } |
|
172 | + } |
|
173 | + } |
|
174 | + |
|
175 | + /** |
|
176 | + * Set an attribute or metadata value for this entity |
|
177 | + * |
|
178 | + * Anything that is not an attribute is saved as metadata. |
|
179 | + * |
|
180 | + * @warning Metadata set this way will inherit the entity's owner and |
|
181 | + * access ID. If you want more control over metadata, use \ElggEntity::setMetadata() |
|
182 | + * |
|
183 | + * @param string $name Name of the attribute or metadata |
|
184 | + * @param mixed $value The value to be set |
|
185 | + * @return void |
|
186 | + * @see \ElggEntity::setMetadata() |
|
187 | + */ |
|
188 | + public function __set($name, $value) { |
|
189 | + if ($this->$name === $value) { |
|
190 | + // quick return if value is not changing |
|
191 | + return; |
|
192 | + } |
|
193 | + |
|
194 | + if (array_key_exists($name, $this->attributes)) { |
|
195 | + // if an attribute is 1 (integer) and it's set to "1" (string), don't consider that a change. |
|
196 | + if (is_int($this->attributes[$name]) |
|
197 | + && is_string($value) |
|
198 | + && ((string) $this->attributes[$name] === $value)) { |
|
199 | + return; |
|
200 | + } |
|
201 | + |
|
202 | + // Due to https://github.com/Elgg/Elgg/pull/5456#issuecomment-17785173, certain attributes |
|
203 | + // will store empty strings as null in the DB. In the somewhat common case that we're re-setting |
|
204 | + // the value to empty string, don't consider this a change. |
|
205 | + if (in_array($name, ['title', 'name', 'description']) |
|
206 | + && $this->attributes[$name] === null |
|
207 | + && $value === "") { |
|
208 | + return; |
|
209 | + } |
|
210 | + |
|
211 | + // keep original values |
|
212 | + if ($this->guid && !array_key_exists($name, $this->orig_attributes)) { |
|
213 | + $this->orig_attributes[$name] = $this->attributes[$name]; |
|
214 | + } |
|
215 | + |
|
216 | + // Certain properties should not be manually changed! |
|
217 | + switch ($name) { |
|
218 | + case 'guid': |
|
219 | + case 'time_updated': |
|
220 | + case 'last_action': |
|
221 | + return; |
|
222 | + break; |
|
223 | + case 'access_id': |
|
224 | + case 'owner_guid': |
|
225 | + case 'container_guid': |
|
226 | + if ($value !== null) { |
|
227 | + $this->attributes[$name] = (int) $value; |
|
228 | + } else { |
|
229 | + $this->attributes[$name] = null; |
|
230 | + } |
|
231 | + break; |
|
232 | + default: |
|
233 | + $this->attributes[$name] = $value; |
|
234 | + break; |
|
235 | + } |
|
236 | + return; |
|
237 | + } |
|
238 | + |
|
239 | + $this->setMetadata($name, $value); |
|
240 | + } |
|
241 | + |
|
242 | + /** |
|
243 | + * Get the original values of attribute(s) that have been modified since the entity was persisted. |
|
244 | + * |
|
245 | + * @return array |
|
246 | + */ |
|
247 | + public function getOriginalAttributes() { |
|
248 | + return $this->orig_attributes; |
|
249 | + } |
|
250 | + |
|
251 | + /** |
|
252 | + * Get an attribute or metadata value |
|
253 | + * |
|
254 | + * If the name matches an attribute, the attribute is returned. If metadata |
|
255 | + * does not exist with that name, a null is returned. |
|
256 | + * |
|
257 | + * This only returns an array if there are multiple values for a particular |
|
258 | + * $name key. |
|
259 | + * |
|
260 | + * @param string $name Name of the attribute or metadata |
|
261 | + * @return mixed |
|
262 | + */ |
|
263 | + public function __get($name) { |
|
264 | + if (array_key_exists($name, $this->attributes)) { |
|
265 | + if ($name === 'subtype' && $this->attributes['guid']) { |
|
266 | + _elgg_services()->logger->warn('Reading ->subtype on a persisted entity is unreliable.'); |
|
267 | + } |
|
268 | + return $this->attributes[$name]; |
|
269 | + } |
|
270 | + |
|
271 | + return $this->getMetadata($name); |
|
272 | + } |
|
273 | + |
|
274 | + /** |
|
275 | + * Get the entity's display name |
|
276 | + * |
|
277 | + * @return string The title or name of this entity. |
|
278 | + */ |
|
279 | + public function getDisplayName() { |
|
280 | + $attr = $this->getSecondaryTableColumns()[0]; |
|
281 | + return $this->$attr; |
|
282 | + } |
|
283 | + |
|
284 | + /** |
|
285 | + * Sets the title or name of this entity. |
|
286 | + * |
|
287 | + * @param string $display_name The title or name of this entity. |
|
288 | + * @return void |
|
289 | + */ |
|
290 | + public function setDisplayName($display_name) { |
|
291 | + $attr = $this->getSecondaryTableColumns()[0]; |
|
292 | + $this->$attr = $display_name; |
|
293 | + } |
|
294 | + |
|
295 | + /** |
|
296 | + * Return the value of a piece of metadata. |
|
297 | + * |
|
298 | + * @param string $name Name |
|
299 | + * |
|
300 | + * @return mixed The value, or null if not found. |
|
301 | + */ |
|
302 | + public function getMetadata($name) { |
|
303 | + $guid = $this->guid; |
|
304 | + |
|
305 | + if (!$guid) { |
|
306 | + if (isset($this->temp_metadata[$name])) { |
|
307 | + // md is returned as an array only if more than 1 entry |
|
308 | + if (count($this->temp_metadata[$name]) == 1) { |
|
309 | + return $this->temp_metadata[$name][0]; |
|
310 | + } else { |
|
311 | + return $this->temp_metadata[$name]; |
|
312 | + } |
|
313 | + } else { |
|
314 | + return null; |
|
315 | + } |
|
316 | + } |
|
317 | + |
|
318 | + // upon first cache miss, just load/cache all the metadata and retry. |
|
319 | + // if this works, the rest of this function may not be needed! |
|
320 | + $cache = _elgg_services()->metadataCache; |
|
321 | + if ($cache->isLoaded($guid)) { |
|
322 | + return $cache->getSingle($guid, $name); |
|
323 | + } else { |
|
324 | + $cache->populateFromEntities([$guid]); |
|
325 | + // in case ignore_access was on, we have to check again... |
|
326 | + if ($cache->isLoaded($guid)) { |
|
327 | + return $cache->getSingle($guid, $name); |
|
328 | + } |
|
329 | + } |
|
330 | + |
|
331 | + $md = elgg_get_metadata([ |
|
332 | + 'guid' => $guid, |
|
333 | + 'metadata_name' => $name, |
|
334 | + 'limit' => 0, |
|
335 | + 'distinct' => false, |
|
336 | + ]); |
|
337 | + |
|
338 | + $value = null; |
|
339 | + |
|
340 | + if ($md && !is_array($md)) { |
|
341 | + $value = $md->value; |
|
342 | + } elseif (count($md) == 1) { |
|
343 | + $value = $md[0]->value; |
|
344 | + } else if ($md && is_array($md)) { |
|
345 | + $value = metadata_array_to_values($md); |
|
346 | + } |
|
347 | + |
|
348 | + return $value; |
|
349 | + } |
|
350 | + |
|
351 | + /** |
|
352 | + * Unset a property from metadata or attribute. |
|
353 | + * |
|
354 | + * @warning If you use this to unset an attribute, you must save the object! |
|
355 | + * |
|
356 | + * @param string $name The name of the attribute or metadata. |
|
357 | + * |
|
358 | + * @return void |
|
359 | + * @todo some attributes should be set to null or other default values |
|
360 | + */ |
|
361 | + public function __unset($name) { |
|
362 | + if (array_key_exists($name, $this->attributes)) { |
|
363 | + $this->attributes[$name] = ""; |
|
364 | + } else { |
|
365 | + $this->deleteMetadata($name); |
|
366 | + } |
|
367 | + } |
|
368 | + |
|
369 | + /** |
|
370 | + * Set metadata on this entity. |
|
371 | + * |
|
372 | + * Plugin developers usually want to use the magic set method ($entity->name = 'value'). |
|
373 | + * Use this method if you want to explicitly set the owner or access of the metadata. |
|
374 | + * You cannot set the owner/access before the entity has been saved. |
|
375 | + * |
|
376 | + * @param string $name Name of the metadata |
|
377 | + * @param mixed $value Value of the metadata (doesn't support assoc arrays) |
|
378 | + * @param string $value_type 'text', 'integer', or '' for automatic detection |
|
379 | + * @param bool $multiple Allow multiple values for a single name. |
|
380 | + * Does not support associative arrays. |
|
381 | + * @param int $owner_guid GUID of entity that owns the metadata. |
|
382 | + * Default is owner of entity. |
|
383 | + * |
|
384 | + * @return bool |
|
385 | + * @throws InvalidArgumentException |
|
386 | + */ |
|
387 | + public function setMetadata($name, $value, $value_type = '', $multiple = false, $owner_guid = 0) { |
|
388 | + |
|
389 | + // normalize value to an array that we will loop over |
|
390 | + // remove indexes if value already an array. |
|
391 | + if (is_array($value)) { |
|
392 | + $value = array_values($value); |
|
393 | + } else { |
|
394 | + $value = [$value]; |
|
395 | + } |
|
396 | + |
|
397 | + // saved entity. persist md to db. |
|
398 | + if ($this->guid) { |
|
399 | + // if overwriting, delete first. |
|
400 | + if (!$multiple) { |
|
401 | + $options = [ |
|
402 | + 'guid' => $this->getGUID(), |
|
403 | + 'metadata_name' => $name, |
|
404 | + 'limit' => 0 |
|
405 | + ]; |
|
406 | + // @todo in 1.9 make this return false if can't add metadata |
|
407 | + // https://github.com/elgg/elgg/issues/4520 |
|
408 | + // |
|
409 | + // need to remove access restrictions right now to delete |
|
410 | + // because this is the expected behavior |
|
411 | + $ia = elgg_set_ignore_access(true); |
|
412 | + $delete_result = elgg_delete_metadata($options); |
|
413 | + elgg_set_ignore_access($ia); |
|
414 | + |
|
415 | + if (false === $delete_result) { |
|
416 | + return false; |
|
417 | + } |
|
418 | + } |
|
419 | + |
|
420 | + $owner_guid = $owner_guid ? (int) $owner_guid : $this->owner_guid; |
|
421 | + |
|
422 | + // add new md |
|
423 | + foreach ($value as $value_tmp) { |
|
424 | + // at this point $value is appended because it was cleared above if needed. |
|
425 | + $md_id = _elgg_services()->metadataTable->create($this->guid, $name, $value_tmp, $value_type, |
|
426 | + $owner_guid, null, true); |
|
427 | + if (!$md_id) { |
|
428 | + return false; |
|
429 | + } |
|
430 | + } |
|
431 | + |
|
432 | + return true; |
|
433 | + } else { |
|
434 | + // unsaved entity. store in temp array |
|
435 | + |
|
436 | + // returning single entries instead of an array of 1 element is decided in |
|
437 | + // getMetaData(), just like pulling from the db. |
|
438 | + |
|
439 | + if ($owner_guid != 0) { |
|
440 | + $msg = "owner guid cannot be used in ElggEntity::setMetadata() until entity is saved."; |
|
441 | + throw new \InvalidArgumentException($msg); |
|
442 | + } |
|
443 | + |
|
444 | + // if overwrite, delete first |
|
445 | + if (!$multiple || !isset($this->temp_metadata[$name])) { |
|
446 | + $this->temp_metadata[$name] = []; |
|
447 | + } |
|
448 | + |
|
449 | + // add new md |
|
450 | + $this->temp_metadata[$name] = array_merge($this->temp_metadata[$name], $value); |
|
451 | + return true; |
|
452 | + } |
|
453 | + } |
|
454 | + |
|
455 | + /** |
|
456 | + * Deletes all metadata on this object (metadata.entity_guid = $this->guid). |
|
457 | + * If you pass a name, only metadata matching that name will be deleted. |
|
458 | + * |
|
459 | + * @warning Calling this with no $name will clear all metadata on the entity. |
|
460 | + * |
|
461 | + * @param null|string $name The name of the metadata to remove. |
|
462 | + * @return bool |
|
463 | + * @since 1.8 |
|
464 | + */ |
|
465 | + public function deleteMetadata($name = null) { |
|
466 | + |
|
467 | + if (!$this->guid) { |
|
468 | + return false; |
|
469 | + } |
|
470 | + |
|
471 | + $options = [ |
|
472 | + 'guid' => $this->guid, |
|
473 | + 'limit' => 0 |
|
474 | + ]; |
|
475 | + if ($name) { |
|
476 | + $options['metadata_name'] = $name; |
|
477 | + } |
|
478 | + |
|
479 | + return elgg_delete_metadata($options); |
|
480 | + } |
|
481 | + |
|
482 | + /** |
|
483 | + * Deletes all metadata owned by this object (metadata.owner_guid = $this->guid). |
|
484 | + * If you pass a name, only metadata matching that name will be deleted. |
|
485 | + * |
|
486 | + * @param null|string $name The name of metadata to delete. |
|
487 | + * @return bool |
|
488 | + * @since 1.8 |
|
489 | + */ |
|
490 | + public function deleteOwnedMetadata($name = null) { |
|
491 | + // access is turned off for this because they might |
|
492 | + // no longer have access to an entity they created metadata on. |
|
493 | + $ia = elgg_set_ignore_access(true); |
|
494 | + $options = [ |
|
495 | + 'metadata_owner_guid' => $this->guid, |
|
496 | + 'limit' => 0 |
|
497 | + ]; |
|
498 | + if ($name) { |
|
499 | + $options['metadata_name'] = $name; |
|
500 | + } |
|
501 | + |
|
502 | + $r = elgg_delete_metadata($options); |
|
503 | + elgg_set_ignore_access($ia); |
|
504 | + return $r; |
|
505 | + } |
|
506 | + |
|
507 | + /** |
|
508 | + * Disables metadata for this entity, optionally based on name. |
|
509 | + * |
|
510 | + * @param string $name An options name of metadata to disable. |
|
511 | + * @return bool |
|
512 | + * @since 1.8 |
|
513 | + */ |
|
514 | + public function disableMetadata($name = '') { |
|
515 | + $options = [ |
|
516 | + 'guid' => $this->guid, |
|
517 | + 'limit' => 0 |
|
518 | + ]; |
|
519 | + if ($name) { |
|
520 | + $options['metadata_name'] = $name; |
|
521 | + } |
|
522 | + |
|
523 | + return elgg_disable_metadata($options); |
|
524 | + } |
|
525 | + |
|
526 | + /** |
|
527 | + * Enables metadata for this entity, optionally based on name. |
|
528 | + * |
|
529 | + * @warning Before calling this, you must use {@link access_show_hidden_entities()} |
|
530 | + * |
|
531 | + * @param string $name An options name of metadata to enable. |
|
532 | + * @return bool |
|
533 | + * @since 1.8 |
|
534 | + */ |
|
535 | + public function enableMetadata($name = '') { |
|
536 | + $options = [ |
|
537 | + 'guid' => $this->guid, |
|
538 | + 'limit' => 0 |
|
539 | + ]; |
|
540 | + if ($name) { |
|
541 | + $options['metadata_name'] = $name; |
|
542 | + } |
|
543 | + |
|
544 | + return elgg_enable_metadata($options); |
|
545 | + } |
|
546 | + |
|
547 | + /** |
|
548 | + * Get a piece of volatile (non-persisted) data on this entity. |
|
549 | + * |
|
550 | + * @param string $name The name of the volatile data |
|
551 | + * |
|
552 | + * @return mixed The value or null if not found. |
|
553 | + */ |
|
554 | + public function getVolatileData($name) { |
|
555 | + return array_key_exists($name, $this->volatile) ? $this->volatile[$name] : null; |
|
556 | + } |
|
557 | + |
|
558 | + /** |
|
559 | + * Set a piece of volatile (non-persisted) data on this entity |
|
560 | + * |
|
561 | + * @param string $name Name |
|
562 | + * @param mixed $value Value |
|
563 | + * |
|
564 | + * @return void |
|
565 | + */ |
|
566 | + public function setVolatileData($name, $value) { |
|
567 | + $this->volatile[$name] = $value; |
|
568 | + } |
|
569 | + |
|
570 | + /** |
|
571 | + * Cache the entity in a persisted cache |
|
572 | + * |
|
573 | + * @param ElggSharedMemoryCache $cache Memcache or null cache |
|
574 | + * @param int $last_action Last action time |
|
575 | + * |
|
576 | + * @return void |
|
577 | + * @access private |
|
578 | + * @internal |
|
579 | + */ |
|
580 | + public function storeInPersistedCache(\ElggSharedMemoryCache $cache, $last_action = 0) { |
|
581 | + $tmp = $this->volatile; |
|
582 | + |
|
583 | + // don't store volatile data |
|
584 | + $this->volatile = []; |
|
585 | + if ($last_action) { |
|
586 | + $this->attributes['last_action'] = (int) $last_action; |
|
587 | + } |
|
588 | + $cache->save($this->guid, $this); |
|
589 | + |
|
590 | + $this->volatile = $tmp; |
|
591 | + } |
|
592 | + |
|
593 | + /** |
|
594 | + * Remove all relationships to and from this entity. |
|
595 | + * If you pass a relationship name, only relationships matching that name |
|
596 | + * will be deleted. |
|
597 | + * |
|
598 | + * @warning Calling this with no $relationship will clear all relationships |
|
599 | + * for this entity. |
|
600 | + * |
|
601 | + * @param null|string $relationship The name of the relationship to remove. |
|
602 | + * @return bool |
|
603 | + * @see \ElggEntity::addRelationship() |
|
604 | + * @see \ElggEntity::removeRelationship() |
|
605 | + */ |
|
606 | + public function deleteRelationships($relationship = null) { |
|
607 | + $relationship = (string) $relationship; |
|
608 | + $result = remove_entity_relationships($this->getGUID(), $relationship); |
|
609 | + return $result && remove_entity_relationships($this->getGUID(), $relationship, true); |
|
610 | + } |
|
611 | + |
|
612 | + /** |
|
613 | + * Add a relationship between this an another entity. |
|
614 | + * |
|
615 | + * @tip Read the relationship like "This entity is a $relationship of $guid_two." |
|
616 | + * |
|
617 | + * @param int $guid_two GUID of the target entity of the relationship. |
|
618 | + * @param string $relationship The type of relationship. |
|
619 | + * |
|
620 | + * @return bool |
|
621 | + * @see \ElggEntity::removeRelationship() |
|
622 | + * @see \ElggEntity::deleteRelationships() |
|
623 | + */ |
|
624 | + public function addRelationship($guid_two, $relationship) { |
|
625 | + return add_entity_relationship($this->getGUID(), $relationship, $guid_two); |
|
626 | + } |
|
627 | + |
|
628 | + /** |
|
629 | + * Remove a relationship |
|
630 | + * |
|
631 | + * @param int $guid_two GUID of the target entity of the relationship. |
|
632 | + * @param string $relationship The type of relationship. |
|
633 | + * |
|
634 | + * @return bool |
|
635 | + * @see \ElggEntity::addRelationship() |
|
636 | + * @see \ElggEntity::deleteRelationships() |
|
637 | + */ |
|
638 | + public function removeRelationship($guid_two, $relationship) { |
|
639 | + return remove_entity_relationship($this->getGUID(), $relationship, $guid_two); |
|
640 | + } |
|
641 | + |
|
642 | + /** |
|
643 | + * Adds a private setting to this entity. |
|
644 | + * |
|
645 | + * Private settings are similar to metadata but will not |
|
646 | + * be searched and there are fewer helper functions for them. |
|
647 | + * |
|
648 | + * @param string $name Name of private setting |
|
649 | + * @param mixed $value Value of private setting |
|
650 | + * |
|
651 | + * @return bool |
|
652 | + */ |
|
653 | + public function setPrivateSetting($name, $value) { |
|
654 | + if ((int) $this->guid > 0) { |
|
655 | + return set_private_setting($this->getGUID(), $name, $value); |
|
656 | + } else { |
|
657 | + $this->temp_private_settings[$name] = $value; |
|
658 | + return true; |
|
659 | + } |
|
660 | + } |
|
661 | + |
|
662 | + /** |
|
663 | + * Returns a private setting value |
|
664 | + * |
|
665 | + * @param string $name Name of the private setting |
|
666 | + * |
|
667 | + * @return mixed Null if the setting does not exist |
|
668 | + */ |
|
669 | + public function getPrivateSetting($name) { |
|
670 | + if ((int) ($this->guid) > 0) { |
|
671 | + return get_private_setting($this->getGUID(), $name); |
|
672 | + } else { |
|
673 | + if (isset($this->temp_private_settings[$name])) { |
|
674 | + return $this->temp_private_settings[$name]; |
|
675 | + } |
|
676 | + } |
|
677 | + return null; |
|
678 | + } |
|
679 | + |
|
680 | + /** |
|
681 | + * Removes private setting |
|
682 | + * |
|
683 | + * @param string $name Name of the private setting |
|
684 | + * |
|
685 | + * @return bool |
|
686 | + */ |
|
687 | + public function removePrivateSetting($name) { |
|
688 | + return remove_private_setting($this->getGUID(), $name); |
|
689 | + } |
|
690 | + |
|
691 | + /** |
|
692 | + * Deletes all annotations on this object (annotations.entity_guid = $this->guid). |
|
693 | + * If you pass a name, only annotations matching that name will be deleted. |
|
694 | + * |
|
695 | + * @warning Calling this with no or empty arguments will clear all annotations on the entity. |
|
696 | + * |
|
697 | + * @param null|string $name The annotations name to remove. |
|
698 | + * @return bool |
|
699 | + * @since 1.8 |
|
700 | + */ |
|
701 | + public function deleteAnnotations($name = null) { |
|
702 | + $options = [ |
|
703 | + 'guid' => $this->guid, |
|
704 | + 'limit' => 0 |
|
705 | + ]; |
|
706 | + if ($name) { |
|
707 | + $options['annotation_name'] = $name; |
|
708 | + } |
|
709 | + |
|
710 | + return elgg_delete_annotations($options); |
|
711 | + } |
|
712 | + |
|
713 | + /** |
|
714 | + * Deletes all annotations owned by this object (annotations.owner_guid = $this->guid). |
|
715 | + * If you pass a name, only annotations matching that name will be deleted. |
|
716 | + * |
|
717 | + * @param null|string $name The name of annotations to delete. |
|
718 | + * @return bool |
|
719 | + * @since 1.8 |
|
720 | + */ |
|
721 | + public function deleteOwnedAnnotations($name = null) { |
|
722 | + // access is turned off for this because they might |
|
723 | + // no longer have access to an entity they created annotations on. |
|
724 | + $ia = elgg_set_ignore_access(true); |
|
725 | + $options = [ |
|
726 | + 'annotation_owner_guid' => $this->guid, |
|
727 | + 'limit' => 0 |
|
728 | + ]; |
|
729 | + if ($name) { |
|
730 | + $options['annotation_name'] = $name; |
|
731 | + } |
|
732 | + |
|
733 | + $r = elgg_delete_annotations($options); |
|
734 | + elgg_set_ignore_access($ia); |
|
735 | + return $r; |
|
736 | + } |
|
737 | + |
|
738 | + /** |
|
739 | + * Disables annotations for this entity, optionally based on name. |
|
740 | + * |
|
741 | + * @param string $name An options name of annotations to disable. |
|
742 | + * @return bool |
|
743 | + * @since 1.8 |
|
744 | + */ |
|
745 | + public function disableAnnotations($name = '') { |
|
746 | + $options = [ |
|
747 | + 'guid' => $this->guid, |
|
748 | + 'limit' => 0 |
|
749 | + ]; |
|
750 | + if ($name) { |
|
751 | + $options['annotation_name'] = $name; |
|
752 | + } |
|
753 | + |
|
754 | + return elgg_disable_annotations($options); |
|
755 | + } |
|
756 | + |
|
757 | + /** |
|
758 | + * Enables annotations for this entity, optionally based on name. |
|
759 | + * |
|
760 | + * @warning Before calling this, you must use {@link access_show_hidden_entities()} |
|
761 | + * |
|
762 | + * @param string $name An options name of annotations to enable. |
|
763 | + * @return bool |
|
764 | + * @since 1.8 |
|
765 | + */ |
|
766 | + public function enableAnnotations($name = '') { |
|
767 | + $options = [ |
|
768 | + 'guid' => $this->guid, |
|
769 | + 'limit' => 0 |
|
770 | + ]; |
|
771 | + if ($name) { |
|
772 | + $options['annotation_name'] = $name; |
|
773 | + } |
|
774 | + |
|
775 | + return elgg_enable_annotations($options); |
|
776 | + } |
|
777 | + |
|
778 | + /** |
|
779 | + * Helper function to return annotation calculation results |
|
780 | + * |
|
781 | + * @param string $name The annotation name. |
|
782 | + * @param string $calculation A valid MySQL function to run its values through |
|
783 | + * @return mixed |
|
784 | + */ |
|
785 | + private function getAnnotationCalculation($name, $calculation) { |
|
786 | + $options = [ |
|
787 | + 'guid' => $this->getGUID(), |
|
788 | + 'distinct' => false, |
|
789 | + 'annotation_name' => $name, |
|
790 | + 'annotation_calculation' => $calculation |
|
791 | + ]; |
|
792 | + |
|
793 | + return elgg_get_annotations($options); |
|
794 | + } |
|
795 | + |
|
796 | + /** |
|
797 | + * Adds an annotation to an entity. |
|
798 | + * |
|
799 | + * @warning By default, annotations are private. |
|
800 | + * |
|
801 | + * @warning Annotating an unsaved entity more than once with the same name |
|
802 | + * will only save the last annotation. |
|
803 | + * |
|
804 | + * @param string $name Annotation name |
|
805 | + * @param mixed $value Annotation value |
|
806 | + * @param int $access_id Access ID |
|
807 | + * @param int $owner_guid GUID of the annotation owner |
|
808 | + * @param string $vartype The type of annotation value |
|
809 | + * |
|
810 | + * @return bool|int Returns int if an annotation is saved |
|
811 | + */ |
|
812 | + public function annotate($name, $value, $access_id = ACCESS_PRIVATE, $owner_guid = 0, $vartype = "") { |
|
813 | + if ((int) $this->guid > 0) { |
|
814 | + return create_annotation($this->getGUID(), $name, $value, $vartype, $owner_guid, $access_id); |
|
815 | + } else { |
|
816 | + $this->temp_annotations[$name] = $value; |
|
817 | + } |
|
818 | + return true; |
|
819 | + } |
|
820 | + |
|
821 | + /** |
|
822 | + * Gets an array of annotations. |
|
823 | + * |
|
824 | + * To retrieve annotations on an unsaved entity, pass array('name' => [annotation name]) |
|
825 | + * as the options array. |
|
826 | + * |
|
827 | + * @param array $options Array of options for elgg_get_annotations() except guid. |
|
828 | + * |
|
829 | + * @return array |
|
830 | + * @see elgg_get_annotations() |
|
831 | + */ |
|
832 | + public function getAnnotations(array $options = []) { |
|
833 | + if ($this->guid) { |
|
834 | + $options['guid'] = $this->guid; |
|
835 | + |
|
836 | + return elgg_get_annotations($options); |
|
837 | + } else { |
|
838 | + $name = elgg_extract('annotation_name', $options, ''); |
|
839 | + |
|
840 | + if (isset($this->temp_annotations[$name])) { |
|
841 | + return [$this->temp_annotations[$name]]; |
|
842 | + } |
|
843 | + } |
|
844 | + |
|
845 | + return []; |
|
846 | + } |
|
847 | + |
|
848 | + /** |
|
849 | + * Count annotations. |
|
850 | + * |
|
851 | + * @param string $name The type of annotation. |
|
852 | + * |
|
853 | + * @return int |
|
854 | + */ |
|
855 | + public function countAnnotations($name = "") { |
|
856 | + return $this->getAnnotationCalculation($name, 'count'); |
|
857 | + } |
|
858 | + |
|
859 | + /** |
|
860 | + * Get the average of an integer type annotation. |
|
861 | + * |
|
862 | + * @param string $name Annotation name |
|
863 | + * |
|
864 | + * @return int |
|
865 | + */ |
|
866 | + public function getAnnotationsAvg($name) { |
|
867 | + return $this->getAnnotationCalculation($name, 'avg'); |
|
868 | + } |
|
869 | + |
|
870 | + /** |
|
871 | + * Get the sum of integer type annotations of a given name. |
|
872 | + * |
|
873 | + * @param string $name Annotation name |
|
874 | + * |
|
875 | + * @return int |
|
876 | + */ |
|
877 | + public function getAnnotationsSum($name) { |
|
878 | + return $this->getAnnotationCalculation($name, 'sum'); |
|
879 | + } |
|
880 | + |
|
881 | + /** |
|
882 | + * Get the minimum of integer type annotations of given name. |
|
883 | + * |
|
884 | + * @param string $name Annotation name |
|
885 | + * |
|
886 | + * @return int |
|
887 | + */ |
|
888 | + public function getAnnotationsMin($name) { |
|
889 | + return $this->getAnnotationCalculation($name, 'min'); |
|
890 | + } |
|
891 | + |
|
892 | + /** |
|
893 | + * Get the maximum of integer type annotations of a given name. |
|
894 | + * |
|
895 | + * @param string $name Annotation name |
|
896 | + * |
|
897 | + * @return int |
|
898 | + */ |
|
899 | + public function getAnnotationsMax($name) { |
|
900 | + return $this->getAnnotationCalculation($name, 'max'); |
|
901 | + } |
|
902 | + |
|
903 | + /** |
|
904 | + * Count the number of comments attached to this entity. |
|
905 | + * |
|
906 | + * @return int Number of comments |
|
907 | + * @since 1.8.0 |
|
908 | + */ |
|
909 | + public function countComments() { |
|
910 | + $params = ['entity' => $this]; |
|
911 | + $num = _elgg_services()->hooks->trigger('comments:count', $this->getType(), $params); |
|
912 | + |
|
913 | + if (is_int($num)) { |
|
914 | + return $num; |
|
915 | + } else { |
|
916 | + return elgg_get_entities([ |
|
917 | + 'type' => 'object', |
|
918 | + 'subtype' => 'comment', |
|
919 | + 'container_guid' => $this->getGUID(), |
|
920 | + 'count' => true, |
|
921 | + 'distinct' => false, |
|
922 | + ]); |
|
923 | + } |
|
924 | + } |
|
925 | + |
|
926 | + /** |
|
927 | + * Gets an array of entities with a relationship to this entity. |
|
928 | + * |
|
929 | + * @param array $options Options array. See elgg_get_entities_from_relationship() |
|
930 | + * for a list of options. 'relationship_guid' is set to |
|
931 | + * this entity. |
|
932 | + * |
|
933 | + * @return array|false An array of entities or false on failure |
|
934 | + * @see elgg_get_entities_from_relationship() |
|
935 | + */ |
|
936 | + public function getEntitiesFromRelationship(array $options = []) { |
|
937 | + $options['relationship_guid'] = $this->guid; |
|
938 | + return elgg_get_entities_from_relationship($options); |
|
939 | + } |
|
940 | + |
|
941 | + /** |
|
942 | + * Gets the number of entities from a specific relationship type |
|
943 | + * |
|
944 | + * @param string $relationship Relationship type (eg "friends") |
|
945 | + * @param bool $inverse_relationship Invert relationship |
|
946 | + * |
|
947 | + * @return int|false The number of entities or false on failure |
|
948 | + */ |
|
949 | + public function countEntitiesFromRelationship($relationship, $inverse_relationship = false) { |
|
950 | + return elgg_get_entities_from_relationship([ |
|
951 | + 'relationship' => $relationship, |
|
952 | + 'relationship_guid' => $this->getGUID(), |
|
953 | + 'inverse_relationship' => $inverse_relationship, |
|
954 | + 'count' => true |
|
955 | + ]); |
|
956 | + } |
|
957 | + |
|
958 | + /** |
|
959 | + * Can a user edit this entity? |
|
960 | + * |
|
961 | + * @tip Can be overridden by registering for the permissions_check plugin hook. |
|
962 | + * |
|
963 | + * @param int $user_guid The user GUID, optionally (default: logged in user) |
|
964 | + * |
|
965 | + * @return bool Whether this entity is editable by the given user. |
|
966 | + * @see elgg_set_ignore_access() |
|
967 | + */ |
|
968 | + public function canEdit($user_guid = 0) { |
|
969 | + return _elgg_services()->userCapabilities->canEdit($this, $user_guid); |
|
970 | + } |
|
971 | + |
|
972 | + /** |
|
973 | + * Can a user delete this entity? |
|
974 | + * |
|
975 | + * @tip Can be overridden by registering for the permissions_check:delete plugin hook. |
|
976 | + * |
|
977 | + * @param int $user_guid The user GUID, optionally (default: logged in user) |
|
978 | + * |
|
979 | + * @return bool Whether this entity is deletable by the given user. |
|
980 | + * @since 1.11 |
|
981 | + * @see elgg_set_ignore_access() |
|
982 | + */ |
|
983 | + public function canDelete($user_guid = 0) { |
|
984 | + return _elgg_services()->userCapabilities->canDelete($this, $user_guid); |
|
985 | + } |
|
986 | + |
|
987 | + /** |
|
988 | + * Can a user edit metadata on this entity? |
|
989 | + * |
|
990 | + * If no specific metadata is passed, it returns whether the user can |
|
991 | + * edit any metadata on the entity. |
|
992 | + * |
|
993 | + * @tip Can be overridden by by registering for the permissions_check:metadata |
|
994 | + * plugin hook. |
|
995 | + * |
|
996 | + * @param \ElggMetadata $metadata The piece of metadata to specifically check or null for any metadata |
|
997 | + * @param int $user_guid The user GUID, optionally (default: logged in user) |
|
998 | + * |
|
999 | + * @return bool |
|
1000 | + * @see elgg_set_ignore_access() |
|
1001 | + */ |
|
1002 | + public function canEditMetadata($metadata = null, $user_guid = 0) { |
|
1003 | + return _elgg_services()->userCapabilities->canEditMetadata($this, $user_guid, $metadata); |
|
1004 | + } |
|
1005 | + |
|
1006 | + /** |
|
1007 | + * Can a user add an entity to this container |
|
1008 | + * |
|
1009 | + * @param int $user_guid The GUID of the user creating the entity (0 for logged in user). |
|
1010 | + * @param string $type The type of entity we're looking to write |
|
1011 | + * @param string $subtype The subtype of the entity we're looking to write |
|
1012 | + * |
|
1013 | + * @return bool |
|
1014 | + * @see elgg_set_ignore_access() |
|
1015 | + */ |
|
1016 | + public function canWriteToContainer($user_guid = 0, $type = 'all', $subtype = 'all') { |
|
1017 | + return _elgg_services()->userCapabilities->canWriteToContainer($this, $user_guid, $type, $subtype); |
|
1018 | + } |
|
1019 | + |
|
1020 | + /** |
|
1021 | + * Can a user comment on an entity? |
|
1022 | + * |
|
1023 | + * @tip Can be overridden by registering for the permissions_check:comment, |
|
1024 | + * <entity type> plugin hook. |
|
1025 | + * |
|
1026 | + * @param int $user_guid User guid (default is logged in user) |
|
1027 | + * @param bool $default Default permission |
|
1028 | + * @return bool |
|
1029 | + */ |
|
1030 | + public function canComment($user_guid = 0, $default = null) { |
|
1031 | + return _elgg_services()->userCapabilities->canComment($this, $user_guid, $default); |
|
1032 | + } |
|
1033 | + |
|
1034 | + /** |
|
1035 | + * Can a user annotate an entity? |
|
1036 | + * |
|
1037 | + * @tip Can be overridden by registering for the plugin hook [permissions_check:annotate:<name>, |
|
1038 | + * <entity type>] or [permissions_check:annotate, <entity type>]. The hooks are called in that order. |
|
1039 | + * |
|
1040 | + * @tip If you want logged out users to annotate an object, do not call |
|
1041 | + * canAnnotate(). It's easier than using the plugin hook. |
|
1042 | + * |
|
1043 | + * @param int $user_guid User guid (default is logged in user) |
|
1044 | + * @param string $annotation_name The name of the annotation (default is unspecified) |
|
1045 | + * |
|
1046 | + * @return bool |
|
1047 | + */ |
|
1048 | + public function canAnnotate($user_guid = 0, $annotation_name = '') { |
|
1049 | + return _elgg_services()->userCapabilities->canAnnotate($this, $user_guid, $annotation_name); |
|
1050 | + } |
|
1051 | + |
|
1052 | + /** |
|
1053 | + * Returns the access_id. |
|
1054 | + * |
|
1055 | + * @return int The access ID |
|
1056 | + */ |
|
1057 | + public function getAccessID() { |
|
1058 | + return $this->access_id; |
|
1059 | + } |
|
1060 | + |
|
1061 | + /** |
|
1062 | + * Returns the guid. |
|
1063 | + * |
|
1064 | + * @return int|null GUID |
|
1065 | + */ |
|
1066 | + public function getGUID() { |
|
1067 | + return $this->guid; |
|
1068 | + } |
|
1069 | + |
|
1070 | + /** |
|
1071 | + * Returns the entity type |
|
1072 | + * |
|
1073 | + * @return string The entity type |
|
1074 | + */ |
|
1075 | + public function getType() { |
|
1076 | + // this is just for the PHPUnit mocking framework |
|
1077 | + return $this->type; |
|
1078 | + } |
|
1079 | + |
|
1080 | + /** |
|
1081 | + * Get the entity subtype |
|
1082 | + * |
|
1083 | + * @return string The entity subtype |
|
1084 | + */ |
|
1085 | + public function getSubtype() { |
|
1086 | + // If this object hasn't been saved, then return the subtype string. |
|
1087 | + if ($this->attributes['guid']) { |
|
1088 | + return get_subtype_from_id($this->attributes['subtype']); |
|
1089 | + } |
|
1090 | + return $this->attributes['subtype']; |
|
1091 | + } |
|
1092 | + |
|
1093 | + /** |
|
1094 | + * Get the guid of the entity's owner. |
|
1095 | + * |
|
1096 | + * @return int The owner GUID |
|
1097 | + */ |
|
1098 | + public function getOwnerGUID() { |
|
1099 | + return (int) $this->owner_guid; |
|
1100 | + } |
|
1101 | + |
|
1102 | + /** |
|
1103 | + * Gets the \ElggEntity that owns this entity. |
|
1104 | + * |
|
1105 | + * @return \ElggEntity The owning entity |
|
1106 | + */ |
|
1107 | + public function getOwnerEntity() { |
|
1108 | + return get_entity($this->owner_guid); |
|
1109 | + } |
|
1110 | + |
|
1111 | + /** |
|
1112 | + * Set the container for this object. |
|
1113 | + * |
|
1114 | + * @param int $container_guid The ID of the container. |
|
1115 | + * |
|
1116 | + * @return bool |
|
1117 | + */ |
|
1118 | + public function setContainerGUID($container_guid) { |
|
1119 | + return $this->container_guid = (int) $container_guid; |
|
1120 | + } |
|
1121 | + |
|
1122 | + /** |
|
1123 | + * Gets the container GUID for this entity. |
|
1124 | + * |
|
1125 | + * @return int |
|
1126 | + */ |
|
1127 | + public function getContainerGUID() { |
|
1128 | + return (int) $this->container_guid; |
|
1129 | + } |
|
1130 | + |
|
1131 | + /** |
|
1132 | + * Get the container entity for this object. |
|
1133 | + * |
|
1134 | + * @return \ElggEntity |
|
1135 | + * @since 1.8.0 |
|
1136 | + */ |
|
1137 | + public function getContainerEntity() { |
|
1138 | + return get_entity($this->getContainerGUID()); |
|
1139 | + } |
|
1140 | + |
|
1141 | + /** |
|
1142 | + * Returns the UNIX epoch time that this entity was last updated |
|
1143 | + * |
|
1144 | + * @return int UNIX epoch time |
|
1145 | + */ |
|
1146 | + public function getTimeUpdated() { |
|
1147 | + return $this->time_updated; |
|
1148 | + } |
|
1149 | + |
|
1150 | + /** |
|
1151 | + * Gets the URL for this entity. |
|
1152 | + * |
|
1153 | + * Plugins can register for the 'entity:url', <type> plugin hook to |
|
1154 | + * customize the url for an entity. |
|
1155 | + * |
|
1156 | + * @return string The URL of the entity |
|
1157 | + */ |
|
1158 | + public function getURL() { |
|
1159 | + $url = _elgg_services()->hooks->trigger('entity:url', $this->getType(), ['entity' => $this]); |
|
1160 | 1160 | |
1161 | - if ($url === null || $url === '' || $url === false) { |
|
1162 | - return ''; |
|
1163 | - } |
|
1164 | - |
|
1165 | - return elgg_normalize_url($url); |
|
1166 | - } |
|
1167 | - |
|
1168 | - /** |
|
1169 | - * Saves icons using an uploaded file as the source. |
|
1170 | - * |
|
1171 | - * @param string $input_name Form input name |
|
1172 | - * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' |
|
1173 | - * @param array $coords An array of cropping coordinates x1, y1, x2, y2 |
|
1174 | - * @return bool |
|
1175 | - */ |
|
1176 | - public function saveIconFromUploadedFile($input_name, $type = 'icon', array $coords = []) { |
|
1177 | - return _elgg_services()->iconService->saveIconFromUploadedFile($this, $input_name, $type, $coords); |
|
1178 | - } |
|
1179 | - |
|
1180 | - /** |
|
1181 | - * Saves icons using a local file as the source. |
|
1182 | - * |
|
1183 | - * @param string $filename The full path to the local file |
|
1184 | - * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' |
|
1185 | - * @param array $coords An array of cropping coordinates x1, y1, x2, y2 |
|
1186 | - * @return bool |
|
1187 | - */ |
|
1188 | - public function saveIconFromLocalFile($filename, $type = 'icon', array $coords = []) { |
|
1189 | - return _elgg_services()->iconService->saveIconFromLocalFile($this, $filename, $type, $coords); |
|
1190 | - } |
|
1191 | - |
|
1192 | - /** |
|
1193 | - * Saves icons using a file located in the data store as the source. |
|
1194 | - * |
|
1195 | - * @param string $file An ElggFile instance |
|
1196 | - * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' |
|
1197 | - * @param array $coords An array of cropping coordinates x1, y1, x2, y2 |
|
1198 | - * @return bool |
|
1199 | - */ |
|
1200 | - public function saveIconFromElggFile(\ElggFile $file, $type = 'icon', array $coords = []) { |
|
1201 | - return _elgg_services()->iconService->saveIconFromElggFile($this, $file, $type, $coords); |
|
1202 | - } |
|
1161 | + if ($url === null || $url === '' || $url === false) { |
|
1162 | + return ''; |
|
1163 | + } |
|
1164 | + |
|
1165 | + return elgg_normalize_url($url); |
|
1166 | + } |
|
1167 | + |
|
1168 | + /** |
|
1169 | + * Saves icons using an uploaded file as the source. |
|
1170 | + * |
|
1171 | + * @param string $input_name Form input name |
|
1172 | + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' |
|
1173 | + * @param array $coords An array of cropping coordinates x1, y1, x2, y2 |
|
1174 | + * @return bool |
|
1175 | + */ |
|
1176 | + public function saveIconFromUploadedFile($input_name, $type = 'icon', array $coords = []) { |
|
1177 | + return _elgg_services()->iconService->saveIconFromUploadedFile($this, $input_name, $type, $coords); |
|
1178 | + } |
|
1179 | + |
|
1180 | + /** |
|
1181 | + * Saves icons using a local file as the source. |
|
1182 | + * |
|
1183 | + * @param string $filename The full path to the local file |
|
1184 | + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' |
|
1185 | + * @param array $coords An array of cropping coordinates x1, y1, x2, y2 |
|
1186 | + * @return bool |
|
1187 | + */ |
|
1188 | + public function saveIconFromLocalFile($filename, $type = 'icon', array $coords = []) { |
|
1189 | + return _elgg_services()->iconService->saveIconFromLocalFile($this, $filename, $type, $coords); |
|
1190 | + } |
|
1191 | + |
|
1192 | + /** |
|
1193 | + * Saves icons using a file located in the data store as the source. |
|
1194 | + * |
|
1195 | + * @param string $file An ElggFile instance |
|
1196 | + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' |
|
1197 | + * @param array $coords An array of cropping coordinates x1, y1, x2, y2 |
|
1198 | + * @return bool |
|
1199 | + */ |
|
1200 | + public function saveIconFromElggFile(\ElggFile $file, $type = 'icon', array $coords = []) { |
|
1201 | + return _elgg_services()->iconService->saveIconFromElggFile($this, $file, $type, $coords); |
|
1202 | + } |
|
1203 | 1203 | |
1204 | - /** |
|
1205 | - * Returns entity icon as an ElggIcon object |
|
1206 | - * The icon file may or may not exist on filestore |
|
1207 | - * |
|
1208 | - * @param string $size Size of the icon |
|
1209 | - * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' |
|
1210 | - * @return \ElggIcon |
|
1211 | - */ |
|
1212 | - public function getIcon($size, $type = 'icon') { |
|
1213 | - return _elgg_services()->iconService->getIcon($this, $size, $type); |
|
1214 | - } |
|
1215 | - |
|
1216 | - /** |
|
1217 | - * Removes all icon files and metadata for the passed type of icon. |
|
1218 | - * |
|
1219 | - * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' |
|
1220 | - * @return bool |
|
1221 | - */ |
|
1222 | - public function deleteIcon($type = 'icon') { |
|
1223 | - return _elgg_services()->iconService->deleteIcon($this, $type); |
|
1224 | - } |
|
1204 | + /** |
|
1205 | + * Returns entity icon as an ElggIcon object |
|
1206 | + * The icon file may or may not exist on filestore |
|
1207 | + * |
|
1208 | + * @param string $size Size of the icon |
|
1209 | + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' |
|
1210 | + * @return \ElggIcon |
|
1211 | + */ |
|
1212 | + public function getIcon($size, $type = 'icon') { |
|
1213 | + return _elgg_services()->iconService->getIcon($this, $size, $type); |
|
1214 | + } |
|
1215 | + |
|
1216 | + /** |
|
1217 | + * Removes all icon files and metadata for the passed type of icon. |
|
1218 | + * |
|
1219 | + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' |
|
1220 | + * @return bool |
|
1221 | + */ |
|
1222 | + public function deleteIcon($type = 'icon') { |
|
1223 | + return _elgg_services()->iconService->deleteIcon($this, $type); |
|
1224 | + } |
|
1225 | 1225 | |
1226 | - /** |
|
1227 | - * Returns the timestamp of when the icon was changed. |
|
1228 | - * |
|
1229 | - * @param string $size The size of the icon |
|
1230 | - * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' |
|
1231 | - * |
|
1232 | - * @return int|null A unix timestamp of when the icon was last changed, or null if not set. |
|
1233 | - */ |
|
1234 | - public function getIconLastChange($size, $type = 'icon') { |
|
1235 | - return _elgg_services()->iconService->getIconLastChange($this, $size, $type); |
|
1236 | - } |
|
1226 | + /** |
|
1227 | + * Returns the timestamp of when the icon was changed. |
|
1228 | + * |
|
1229 | + * @param string $size The size of the icon |
|
1230 | + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' |
|
1231 | + * |
|
1232 | + * @return int|null A unix timestamp of when the icon was last changed, or null if not set. |
|
1233 | + */ |
|
1234 | + public function getIconLastChange($size, $type = 'icon') { |
|
1235 | + return _elgg_services()->iconService->getIconLastChange($this, $size, $type); |
|
1236 | + } |
|
1237 | 1237 | |
1238 | - /** |
|
1239 | - * Returns if the entity has an icon of the passed type. |
|
1240 | - * |
|
1241 | - * @param string $size The size of the icon |
|
1242 | - * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' |
|
1243 | - * @return bool |
|
1244 | - */ |
|
1245 | - public function hasIcon($size, $type = 'icon') { |
|
1246 | - return _elgg_services()->iconService->hasIcon($this, $size, $type); |
|
1247 | - } |
|
1248 | - |
|
1249 | - /** |
|
1250 | - * Get the URL for this entity's icon |
|
1251 | - * |
|
1252 | - * Plugins can register for the 'entity:icon:url', <type> plugin hook |
|
1253 | - * to customize the icon for an entity. |
|
1254 | - * |
|
1255 | - * @param mixed $params A string defining the size of the icon (e.g. tiny, small, medium, large) |
|
1256 | - * or an array of parameters including 'size' |
|
1257 | - * @return string The URL |
|
1258 | - * @since 1.8.0 |
|
1259 | - */ |
|
1260 | - public function getIconURL($params = []) { |
|
1261 | - return _elgg_services()->iconService->getIconURL($this, $params); |
|
1262 | - } |
|
1263 | - |
|
1264 | - /** |
|
1265 | - * Save an entity. |
|
1266 | - * |
|
1267 | - * @return bool|int |
|
1268 | - * @throws InvalidParameterException |
|
1269 | - * @throws IOException |
|
1270 | - */ |
|
1271 | - public function save() { |
|
1272 | - $guid = $this->guid; |
|
1273 | - if ($guid > 0) { |
|
1274 | - $guid = $this->update(); |
|
1275 | - } else { |
|
1276 | - $guid = $this->create(); |
|
1277 | - if ($guid && !_elgg_services()->hooks->getEvents()->trigger('create', $this->type, $this)) { |
|
1278 | - // plugins that return false to event don't need to override the access system |
|
1279 | - $ia = elgg_set_ignore_access(true); |
|
1280 | - $this->delete(); |
|
1281 | - elgg_set_ignore_access($ia); |
|
1282 | - return false; |
|
1283 | - } |
|
1284 | - } |
|
1285 | - |
|
1286 | - if ($guid) { |
|
1287 | - _elgg_services()->entityCache->set($this); |
|
1288 | - $this->storeInPersistedCache(_elgg_get_memcache('new_entity_cache')); |
|
1289 | - } |
|
1290 | - |
|
1291 | - return $guid; |
|
1292 | - } |
|
1293 | - |
|
1294 | - /** |
|
1295 | - * Create a new entry in the entities table. |
|
1296 | - * |
|
1297 | - * Saves the base information in the entities table for the entity. Saving |
|
1298 | - * the type-specific information is handled in the calling class method. |
|
1299 | - * |
|
1300 | - * @warning Entities must have an entry in both the entities table and their type table |
|
1301 | - * or they will throw an exception when loaded. |
|
1302 | - * |
|
1303 | - * @return int The new entity's GUID |
|
1304 | - * @throws InvalidParameterException If the entity's type has not been set. |
|
1305 | - * @throws IOException If the new row fails to write to the DB. |
|
1306 | - */ |
|
1307 | - protected function create() { |
|
1308 | - |
|
1309 | - $type = $this->attributes['type']; |
|
1310 | - if (!in_array($type, \Elgg\Config::getEntityTypes())) { |
|
1311 | - throw new \InvalidParameterException('Entity type must be one of the allowed types: ' |
|
1312 | - . implode(', ', \Elgg\Config::getEntityTypes())); |
|
1313 | - } |
|
1238 | + /** |
|
1239 | + * Returns if the entity has an icon of the passed type. |
|
1240 | + * |
|
1241 | + * @param string $size The size of the icon |
|
1242 | + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' |
|
1243 | + * @return bool |
|
1244 | + */ |
|
1245 | + public function hasIcon($size, $type = 'icon') { |
|
1246 | + return _elgg_services()->iconService->hasIcon($this, $size, $type); |
|
1247 | + } |
|
1248 | + |
|
1249 | + /** |
|
1250 | + * Get the URL for this entity's icon |
|
1251 | + * |
|
1252 | + * Plugins can register for the 'entity:icon:url', <type> plugin hook |
|
1253 | + * to customize the icon for an entity. |
|
1254 | + * |
|
1255 | + * @param mixed $params A string defining the size of the icon (e.g. tiny, small, medium, large) |
|
1256 | + * or an array of parameters including 'size' |
|
1257 | + * @return string The URL |
|
1258 | + * @since 1.8.0 |
|
1259 | + */ |
|
1260 | + public function getIconURL($params = []) { |
|
1261 | + return _elgg_services()->iconService->getIconURL($this, $params); |
|
1262 | + } |
|
1263 | + |
|
1264 | + /** |
|
1265 | + * Save an entity. |
|
1266 | + * |
|
1267 | + * @return bool|int |
|
1268 | + * @throws InvalidParameterException |
|
1269 | + * @throws IOException |
|
1270 | + */ |
|
1271 | + public function save() { |
|
1272 | + $guid = $this->guid; |
|
1273 | + if ($guid > 0) { |
|
1274 | + $guid = $this->update(); |
|
1275 | + } else { |
|
1276 | + $guid = $this->create(); |
|
1277 | + if ($guid && !_elgg_services()->hooks->getEvents()->trigger('create', $this->type, $this)) { |
|
1278 | + // plugins that return false to event don't need to override the access system |
|
1279 | + $ia = elgg_set_ignore_access(true); |
|
1280 | + $this->delete(); |
|
1281 | + elgg_set_ignore_access($ia); |
|
1282 | + return false; |
|
1283 | + } |
|
1284 | + } |
|
1285 | + |
|
1286 | + if ($guid) { |
|
1287 | + _elgg_services()->entityCache->set($this); |
|
1288 | + $this->storeInPersistedCache(_elgg_get_memcache('new_entity_cache')); |
|
1289 | + } |
|
1290 | + |
|
1291 | + return $guid; |
|
1292 | + } |
|
1293 | + |
|
1294 | + /** |
|
1295 | + * Create a new entry in the entities table. |
|
1296 | + * |
|
1297 | + * Saves the base information in the entities table for the entity. Saving |
|
1298 | + * the type-specific information is handled in the calling class method. |
|
1299 | + * |
|
1300 | + * @warning Entities must have an entry in both the entities table and their type table |
|
1301 | + * or they will throw an exception when loaded. |
|
1302 | + * |
|
1303 | + * @return int The new entity's GUID |
|
1304 | + * @throws InvalidParameterException If the entity's type has not been set. |
|
1305 | + * @throws IOException If the new row fails to write to the DB. |
|
1306 | + */ |
|
1307 | + protected function create() { |
|
1308 | + |
|
1309 | + $type = $this->attributes['type']; |
|
1310 | + if (!in_array($type, \Elgg\Config::getEntityTypes())) { |
|
1311 | + throw new \InvalidParameterException('Entity type must be one of the allowed types: ' |
|
1312 | + . implode(', ', \Elgg\Config::getEntityTypes())); |
|
1313 | + } |
|
1314 | 1314 | |
1315 | - $subtype = $this->attributes['subtype']; |
|
1316 | - $subtype_id = add_subtype($type, $subtype); |
|
1317 | - $owner_guid = (int) $this->attributes['owner_guid']; |
|
1318 | - $access_id = (int) $this->attributes['access_id']; |
|
1319 | - $now = $this->getCurrentTime()->getTimestamp(); |
|
1320 | - $time_created = isset($this->attributes['time_created']) ? (int) $this->attributes['time_created'] : $now; |
|
1315 | + $subtype = $this->attributes['subtype']; |
|
1316 | + $subtype_id = add_subtype($type, $subtype); |
|
1317 | + $owner_guid = (int) $this->attributes['owner_guid']; |
|
1318 | + $access_id = (int) $this->attributes['access_id']; |
|
1319 | + $now = $this->getCurrentTime()->getTimestamp(); |
|
1320 | + $time_created = isset($this->attributes['time_created']) ? (int) $this->attributes['time_created'] : $now; |
|
1321 | 1321 | |
1322 | - $container_guid = $this->attributes['container_guid']; |
|
1323 | - if ($container_guid == 0) { |
|
1324 | - $container_guid = $owner_guid; |
|
1325 | - $this->attributes['container_guid'] = $container_guid; |
|
1326 | - } |
|
1327 | - $container_guid = (int) $container_guid; |
|
1328 | - |
|
1329 | - if ($access_id == ACCESS_DEFAULT) { |
|
1330 | - throw new \InvalidParameterException('ACCESS_DEFAULT is not a valid access level. See its documentation in elgglib.h'); |
|
1331 | - } |
|
1332 | - |
|
1333 | - $user_guid = elgg_get_logged_in_user_guid(); |
|
1334 | - |
|
1335 | - // If given an owner, verify it can be loaded |
|
1336 | - if ($owner_guid) { |
|
1337 | - $owner = $this->getOwnerEntity(); |
|
1338 | - if (!$owner) { |
|
1339 | - _elgg_services()->logger->error("User $user_guid tried to create a ($type, $subtype), but the given" |
|
1340 | - . " owner $owner_guid could not be loaded."); |
|
1341 | - return false; |
|
1342 | - } |
|
1343 | - |
|
1344 | - // If different owner than logged in, verify can write to container. |
|
1345 | - |
|
1346 | - if ($user_guid != $owner_guid && !$owner->canWriteToContainer($user_guid, $type, $subtype)) { |
|
1347 | - _elgg_services()->logger->error("User $user_guid tried to create a ($type, $subtype) with owner" |
|
1348 | - . " $owner_guid, but the user wasn't permitted to write to the owner's container."); |
|
1349 | - return false; |
|
1350 | - } |
|
1351 | - } |
|
1352 | - |
|
1353 | - // If given a container, verify it can be loaded and that the current user can write to it |
|
1354 | - if ($container_guid) { |
|
1355 | - $container = $this->getContainerEntity(); |
|
1356 | - if (!$container) { |
|
1357 | - _elgg_services()->logger->error("User $user_guid tried to create a ($type, $subtype), but the given" |
|
1358 | - . " container $container_guid could not be loaded."); |
|
1359 | - return false; |
|
1360 | - } |
|
1361 | - |
|
1362 | - if (!$container->canWriteToContainer($user_guid, $type, $subtype)) { |
|
1363 | - _elgg_services()->logger->error("User $user_guid tried to create a ($type, $subtype), but was not" |
|
1364 | - . " permitted to write to container $container_guid."); |
|
1365 | - return false; |
|
1366 | - } |
|
1367 | - } |
|
1368 | - |
|
1369 | - // Create primary table row |
|
1370 | - $guid = _elgg_services()->entityTable->insertRow((object) [ |
|
1371 | - 'type' => $type, |
|
1372 | - 'subtype_id' => $subtype_id, |
|
1373 | - 'owner_guid' => $owner_guid, |
|
1374 | - 'container_guid' => $container_guid, |
|
1375 | - 'access_id' => $access_id, |
|
1376 | - 'time_created' => $time_created, |
|
1377 | - 'time_updated' => $now, |
|
1378 | - 'last_action' => $now, |
|
1379 | - ], $this->attributes); |
|
1380 | - |
|
1381 | - if (!$guid) { |
|
1382 | - throw new \IOException("Unable to save new object's base entity information!"); |
|
1383 | - } |
|
1384 | - |
|
1385 | - // We are writing this new entity to cache to make sure subsequent calls |
|
1386 | - // to get_entity() load the entity from cache and not from the DB. This |
|
1387 | - // MUST come before the metadata and annotation writes below! |
|
1388 | - _elgg_services()->entityCache->set($this); |
|
1322 | + $container_guid = $this->attributes['container_guid']; |
|
1323 | + if ($container_guid == 0) { |
|
1324 | + $container_guid = $owner_guid; |
|
1325 | + $this->attributes['container_guid'] = $container_guid; |
|
1326 | + } |
|
1327 | + $container_guid = (int) $container_guid; |
|
1328 | + |
|
1329 | + if ($access_id == ACCESS_DEFAULT) { |
|
1330 | + throw new \InvalidParameterException('ACCESS_DEFAULT is not a valid access level. See its documentation in elgglib.h'); |
|
1331 | + } |
|
1332 | + |
|
1333 | + $user_guid = elgg_get_logged_in_user_guid(); |
|
1334 | + |
|
1335 | + // If given an owner, verify it can be loaded |
|
1336 | + if ($owner_guid) { |
|
1337 | + $owner = $this->getOwnerEntity(); |
|
1338 | + if (!$owner) { |
|
1339 | + _elgg_services()->logger->error("User $user_guid tried to create a ($type, $subtype), but the given" |
|
1340 | + . " owner $owner_guid could not be loaded."); |
|
1341 | + return false; |
|
1342 | + } |
|
1343 | + |
|
1344 | + // If different owner than logged in, verify can write to container. |
|
1345 | + |
|
1346 | + if ($user_guid != $owner_guid && !$owner->canWriteToContainer($user_guid, $type, $subtype)) { |
|
1347 | + _elgg_services()->logger->error("User $user_guid tried to create a ($type, $subtype) with owner" |
|
1348 | + . " $owner_guid, but the user wasn't permitted to write to the owner's container."); |
|
1349 | + return false; |
|
1350 | + } |
|
1351 | + } |
|
1352 | + |
|
1353 | + // If given a container, verify it can be loaded and that the current user can write to it |
|
1354 | + if ($container_guid) { |
|
1355 | + $container = $this->getContainerEntity(); |
|
1356 | + if (!$container) { |
|
1357 | + _elgg_services()->logger->error("User $user_guid tried to create a ($type, $subtype), but the given" |
|
1358 | + . " container $container_guid could not be loaded."); |
|
1359 | + return false; |
|
1360 | + } |
|
1361 | + |
|
1362 | + if (!$container->canWriteToContainer($user_guid, $type, $subtype)) { |
|
1363 | + _elgg_services()->logger->error("User $user_guid tried to create a ($type, $subtype), but was not" |
|
1364 | + . " permitted to write to container $container_guid."); |
|
1365 | + return false; |
|
1366 | + } |
|
1367 | + } |
|
1368 | + |
|
1369 | + // Create primary table row |
|
1370 | + $guid = _elgg_services()->entityTable->insertRow((object) [ |
|
1371 | + 'type' => $type, |
|
1372 | + 'subtype_id' => $subtype_id, |
|
1373 | + 'owner_guid' => $owner_guid, |
|
1374 | + 'container_guid' => $container_guid, |
|
1375 | + 'access_id' => $access_id, |
|
1376 | + 'time_created' => $time_created, |
|
1377 | + 'time_updated' => $now, |
|
1378 | + 'last_action' => $now, |
|
1379 | + ], $this->attributes); |
|
1380 | + |
|
1381 | + if (!$guid) { |
|
1382 | + throw new \IOException("Unable to save new object's base entity information!"); |
|
1383 | + } |
|
1384 | + |
|
1385 | + // We are writing this new entity to cache to make sure subsequent calls |
|
1386 | + // to get_entity() load the entity from cache and not from the DB. This |
|
1387 | + // MUST come before the metadata and annotation writes below! |
|
1388 | + _elgg_services()->entityCache->set($this); |
|
1389 | 1389 | |
1390 | - // for BC with 1.8, ->subtype always returns ID, ->getSubtype() the string |
|
1391 | - $this->attributes['subtype'] = (int) $subtype_id; |
|
1392 | - $this->attributes['guid'] = (int) $guid; |
|
1393 | - $this->attributes['time_created'] = (int) $time_created; |
|
1394 | - $this->attributes['time_updated'] = (int) $now; |
|
1395 | - $this->attributes['last_action'] = (int) $now; |
|
1396 | - $this->attributes['container_guid'] = (int) $container_guid; |
|
1397 | - |
|
1398 | - // Create secondary table row |
|
1399 | - $attrs = $this->getSecondaryTableColumns(); |
|
1400 | - |
|
1401 | - $column_names = implode(', ', $attrs); |
|
1402 | - $values = implode(', ', array_map(function ($attr) { |
|
1403 | - return ":$attr"; |
|
1404 | - }, $attrs)); |
|
1405 | - |
|
1406 | - $params = [ |
|
1407 | - ':guid' => $guid, |
|
1408 | - ]; |
|
1409 | - foreach ($attrs as $attr) { |
|
1410 | - $params[":$attr"] = ($attr === 'url') ? '' : (string) $this->attributes[$attr]; |
|
1411 | - } |
|
1412 | - |
|
1413 | - $db = $this->getDatabase(); |
|
1414 | - $query = " |
|
1390 | + // for BC with 1.8, ->subtype always returns ID, ->getSubtype() the string |
|
1391 | + $this->attributes['subtype'] = (int) $subtype_id; |
|
1392 | + $this->attributes['guid'] = (int) $guid; |
|
1393 | + $this->attributes['time_created'] = (int) $time_created; |
|
1394 | + $this->attributes['time_updated'] = (int) $now; |
|
1395 | + $this->attributes['last_action'] = (int) $now; |
|
1396 | + $this->attributes['container_guid'] = (int) $container_guid; |
|
1397 | + |
|
1398 | + // Create secondary table row |
|
1399 | + $attrs = $this->getSecondaryTableColumns(); |
|
1400 | + |
|
1401 | + $column_names = implode(', ', $attrs); |
|
1402 | + $values = implode(', ', array_map(function ($attr) { |
|
1403 | + return ":$attr"; |
|
1404 | + }, $attrs)); |
|
1405 | + |
|
1406 | + $params = [ |
|
1407 | + ':guid' => $guid, |
|
1408 | + ]; |
|
1409 | + foreach ($attrs as $attr) { |
|
1410 | + $params[":$attr"] = ($attr === 'url') ? '' : (string) $this->attributes[$attr]; |
|
1411 | + } |
|
1412 | + |
|
1413 | + $db = $this->getDatabase(); |
|
1414 | + $query = " |
|
1415 | 1415 | INSERT INTO {$db->prefix}{$this->type}s_entity |
1416 | 1416 | (guid, $column_names) VALUES (:guid, $values) |
1417 | 1417 | "; |
1418 | 1418 | |
1419 | - if ($db->insertData($query, $params) === false) { |
|
1420 | - // Uh oh, couldn't save secondary |
|
1421 | - $query = " |
|
1419 | + if ($db->insertData($query, $params) === false) { |
|
1420 | + // Uh oh, couldn't save secondary |
|
1421 | + $query = " |
|
1422 | 1422 | DELETE FROM {$db->prefix}entities |
1423 | 1423 | WHERE guid = :guid |
1424 | 1424 | "; |
1425 | - $params = [ |
|
1426 | - ':guid' => $guid, |
|
1427 | - ]; |
|
1428 | - $db->deleteData($query, $params); |
|
1429 | - |
|
1430 | - _elgg_services()->entityCache->remove($guid); |
|
1431 | - |
|
1432 | - throw new \IOException("Unable to save new object's secondary entity information!"); |
|
1433 | - } |
|
1434 | - |
|
1435 | - // Save any unsaved metadata |
|
1436 | - if (sizeof($this->temp_metadata) > 0) { |
|
1437 | - foreach ($this->temp_metadata as $name => $value) { |
|
1438 | - $this->$name = $value; |
|
1439 | - } |
|
1440 | - |
|
1441 | - $this->temp_metadata = []; |
|
1442 | - } |
|
1443 | - |
|
1444 | - // Save any unsaved annotations. |
|
1445 | - if (sizeof($this->temp_annotations) > 0) { |
|
1446 | - foreach ($this->temp_annotations as $name => $value) { |
|
1447 | - $this->annotate($name, $value); |
|
1448 | - } |
|
1449 | - |
|
1450 | - $this->temp_annotations = []; |
|
1451 | - } |
|
1452 | - |
|
1453 | - // Save any unsaved private settings. |
|
1454 | - if (sizeof($this->temp_private_settings) > 0) { |
|
1455 | - foreach ($this->temp_private_settings as $name => $value) { |
|
1456 | - $this->setPrivateSetting($name, $value); |
|
1457 | - } |
|
1458 | - |
|
1459 | - $this->temp_private_settings = []; |
|
1460 | - } |
|
1425 | + $params = [ |
|
1426 | + ':guid' => $guid, |
|
1427 | + ]; |
|
1428 | + $db->deleteData($query, $params); |
|
1429 | + |
|
1430 | + _elgg_services()->entityCache->remove($guid); |
|
1431 | + |
|
1432 | + throw new \IOException("Unable to save new object's secondary entity information!"); |
|
1433 | + } |
|
1434 | + |
|
1435 | + // Save any unsaved metadata |
|
1436 | + if (sizeof($this->temp_metadata) > 0) { |
|
1437 | + foreach ($this->temp_metadata as $name => $value) { |
|
1438 | + $this->$name = $value; |
|
1439 | + } |
|
1440 | + |
|
1441 | + $this->temp_metadata = []; |
|
1442 | + } |
|
1443 | + |
|
1444 | + // Save any unsaved annotations. |
|
1445 | + if (sizeof($this->temp_annotations) > 0) { |
|
1446 | + foreach ($this->temp_annotations as $name => $value) { |
|
1447 | + $this->annotate($name, $value); |
|
1448 | + } |
|
1449 | + |
|
1450 | + $this->temp_annotations = []; |
|
1451 | + } |
|
1452 | + |
|
1453 | + // Save any unsaved private settings. |
|
1454 | + if (sizeof($this->temp_private_settings) > 0) { |
|
1455 | + foreach ($this->temp_private_settings as $name => $value) { |
|
1456 | + $this->setPrivateSetting($name, $value); |
|
1457 | + } |
|
1458 | + |
|
1459 | + $this->temp_private_settings = []; |
|
1460 | + } |
|
1461 | 1461 | |
1462 | - return $guid; |
|
1463 | - } |
|
1464 | - |
|
1465 | - /** |
|
1466 | - * Update the entity in the database. |
|
1467 | - * |
|
1468 | - * @return bool Whether the update was successful. |
|
1469 | - * |
|
1470 | - * @throws InvalidParameterException |
|
1471 | - */ |
|
1472 | - protected function update() { |
|
1462 | + return $guid; |
|
1463 | + } |
|
1464 | + |
|
1465 | + /** |
|
1466 | + * Update the entity in the database. |
|
1467 | + * |
|
1468 | + * @return bool Whether the update was successful. |
|
1469 | + * |
|
1470 | + * @throws InvalidParameterException |
|
1471 | + */ |
|
1472 | + protected function update() { |
|
1473 | 1473 | |
1474 | - _elgg_services()->boot->invalidateCache(); |
|
1475 | - |
|
1476 | - if (!$this->canEdit()) { |
|
1477 | - return false; |
|
1478 | - } |
|
1479 | - |
|
1480 | - // give old update event a chance to stop the update |
|
1481 | - if (!_elgg_services()->hooks->getEvents()->trigger('update', $this->type, $this)) { |
|
1482 | - return false; |
|
1483 | - } |
|
1484 | - |
|
1485 | - // See #6225. We copy these after the update event in case a handler changed one of them. |
|
1486 | - $guid = (int) $this->guid; |
|
1487 | - $owner_guid = (int) $this->owner_guid; |
|
1488 | - $access_id = (int) $this->access_id; |
|
1489 | - $container_guid = (int) $this->container_guid; |
|
1490 | - $time_created = (int) $this->time_created; |
|
1491 | - $time = $this->getCurrentTime()->getTimestamp(); |
|
1492 | - |
|
1493 | - if ($access_id == ACCESS_DEFAULT) { |
|
1494 | - throw new \InvalidParameterException('ACCESS_DEFAULT is not a valid access level. See its documentation in elgglib.php'); |
|
1495 | - } |
|
1496 | - |
|
1497 | - // Update primary table |
|
1498 | - $ret = _elgg_services()->entityTable->updateRow($guid, (object) [ |
|
1499 | - 'owner_guid' => $owner_guid, |
|
1500 | - 'container_guid' => $container_guid, |
|
1501 | - 'access_id' => $access_id, |
|
1502 | - 'time_created' => $time_created, |
|
1503 | - 'time_updated' => $time, |
|
1504 | - 'guid' => $guid, |
|
1505 | - ]); |
|
1506 | - if ($ret === false) { |
|
1507 | - return false; |
|
1508 | - } |
|
1509 | - |
|
1510 | - $this->attributes['time_updated'] = $time; |
|
1511 | - |
|
1512 | - // Update secondary table |
|
1513 | - $attrs = $this->getSecondaryTableColumns(); |
|
1514 | - |
|
1515 | - $sets = array_map(function ($attr) { |
|
1516 | - return "$attr = :$attr"; |
|
1517 | - }, $attrs); |
|
1518 | - $sets = implode(', ', $sets); |
|
1519 | - |
|
1520 | - foreach ($attrs as $attr) { |
|
1521 | - $params[":$attr"] = ($attr === 'url') ? '' : (string) $this->attributes[$attr]; |
|
1522 | - } |
|
1523 | - $params[':guid'] = $this->guid; |
|
1524 | - |
|
1525 | - $db = $this->getDatabase(); |
|
1526 | - $query = " |
|
1474 | + _elgg_services()->boot->invalidateCache(); |
|
1475 | + |
|
1476 | + if (!$this->canEdit()) { |
|
1477 | + return false; |
|
1478 | + } |
|
1479 | + |
|
1480 | + // give old update event a chance to stop the update |
|
1481 | + if (!_elgg_services()->hooks->getEvents()->trigger('update', $this->type, $this)) { |
|
1482 | + return false; |
|
1483 | + } |
|
1484 | + |
|
1485 | + // See #6225. We copy these after the update event in case a handler changed one of them. |
|
1486 | + $guid = (int) $this->guid; |
|
1487 | + $owner_guid = (int) $this->owner_guid; |
|
1488 | + $access_id = (int) $this->access_id; |
|
1489 | + $container_guid = (int) $this->container_guid; |
|
1490 | + $time_created = (int) $this->time_created; |
|
1491 | + $time = $this->getCurrentTime()->getTimestamp(); |
|
1492 | + |
|
1493 | + if ($access_id == ACCESS_DEFAULT) { |
|
1494 | + throw new \InvalidParameterException('ACCESS_DEFAULT is not a valid access level. See its documentation in elgglib.php'); |
|
1495 | + } |
|
1496 | + |
|
1497 | + // Update primary table |
|
1498 | + $ret = _elgg_services()->entityTable->updateRow($guid, (object) [ |
|
1499 | + 'owner_guid' => $owner_guid, |
|
1500 | + 'container_guid' => $container_guid, |
|
1501 | + 'access_id' => $access_id, |
|
1502 | + 'time_created' => $time_created, |
|
1503 | + 'time_updated' => $time, |
|
1504 | + 'guid' => $guid, |
|
1505 | + ]); |
|
1506 | + if ($ret === false) { |
|
1507 | + return false; |
|
1508 | + } |
|
1509 | + |
|
1510 | + $this->attributes['time_updated'] = $time; |
|
1511 | + |
|
1512 | + // Update secondary table |
|
1513 | + $attrs = $this->getSecondaryTableColumns(); |
|
1514 | + |
|
1515 | + $sets = array_map(function ($attr) { |
|
1516 | + return "$attr = :$attr"; |
|
1517 | + }, $attrs); |
|
1518 | + $sets = implode(', ', $sets); |
|
1519 | + |
|
1520 | + foreach ($attrs as $attr) { |
|
1521 | + $params[":$attr"] = ($attr === 'url') ? '' : (string) $this->attributes[$attr]; |
|
1522 | + } |
|
1523 | + $params[':guid'] = $this->guid; |
|
1524 | + |
|
1525 | + $db = $this->getDatabase(); |
|
1526 | + $query = " |
|
1527 | 1527 | UPDATE {$db->prefix}{$this->type}s_entity |
1528 | 1528 | SET $sets |
1529 | 1529 | WHERE guid = :guid |
1530 | 1530 | "; |
1531 | 1531 | |
1532 | - if ($db->updateData($query, false, $params) === false) { |
|
1533 | - return false; |
|
1534 | - } |
|
1535 | - |
|
1536 | - elgg_trigger_after_event('update', $this->type, $this); |
|
1537 | - |
|
1538 | - // TODO(evan): Move this to \ElggObject? |
|
1539 | - if ($this instanceof \ElggObject) { |
|
1540 | - update_river_access_by_object($guid, $access_id); |
|
1541 | - } |
|
1542 | - |
|
1543 | - $this->orig_attributes = []; |
|
1544 | - |
|
1545 | - // Handle cases where there was no error BUT no rows were updated! |
|
1546 | - return true; |
|
1547 | - } |
|
1548 | - |
|
1549 | - /** |
|
1550 | - * Loads attributes from the entities table into the object. |
|
1551 | - * |
|
1552 | - * @param \stdClass $row Object of properties from database row(s) |
|
1553 | - * |
|
1554 | - * @return bool |
|
1555 | - */ |
|
1556 | - protected function load(\stdClass $row) { |
|
1557 | - $type = $this->type; |
|
1558 | - |
|
1559 | - $attr_loader = new \Elgg\AttributeLoader(get_class($this), $type, $this->attributes); |
|
1560 | - if ($type === 'user' || $this instanceof ElggPlugin) { |
|
1561 | - $attr_loader->requires_access_control = false; |
|
1562 | - } |
|
1563 | - $attr_loader->secondary_loader = "get_{$type}_entity_as_row"; |
|
1564 | - |
|
1565 | - $attrs = $attr_loader->getRequiredAttributes($row); |
|
1566 | - if (!$attrs) { |
|
1567 | - return false; |
|
1568 | - } |
|
1569 | - |
|
1570 | - $this->attributes = $attrs; |
|
1571 | - |
|
1572 | - foreach ($attr_loader->getAdditionalSelectValues() as $name => $value) { |
|
1573 | - $this->setVolatileData("select:$name", $value); |
|
1574 | - } |
|
1575 | - |
|
1576 | - _elgg_services()->entityCache->set($this); |
|
1577 | - |
|
1578 | - return true; |
|
1579 | - } |
|
1580 | - |
|
1581 | - /** |
|
1582 | - * Get the added columns (besides GUID) stored in the secondary table |
|
1583 | - * |
|
1584 | - * @return string[] |
|
1585 | - * @throws \InvalidArgumentException |
|
1586 | - */ |
|
1587 | - private function getSecondaryTableColumns() { |
|
1588 | - // Note: the title or name column must come first. See getDisplayName(). |
|
1589 | - if ($this instanceof ElggObject) { |
|
1590 | - return ['title', 'description']; |
|
1591 | - } |
|
1592 | - if ($this instanceof ElggUser) { |
|
1593 | - return ['name', 'username', 'password_hash', 'email', 'language']; |
|
1594 | - } |
|
1595 | - if ($this instanceof ElggGroup) { |
|
1596 | - return ['name', 'description']; |
|
1597 | - } |
|
1598 | - if ($this instanceof ElggSite) { |
|
1599 | - return ['name', 'description', 'url']; |
|
1600 | - } |
|
1601 | - throw new \InvalidArgumentException("Not a recognized type: " . get_class($this)); |
|
1602 | - } |
|
1603 | - |
|
1604 | - /** |
|
1605 | - * Get default values for the attributes not defined in \ElggEntity::initializeAttributes |
|
1606 | - * |
|
1607 | - * @param string $type Entity type |
|
1608 | - * |
|
1609 | - * @return array |
|
1610 | - * @access private |
|
1611 | - */ |
|
1612 | - public static function getExtraAttributeDefaults($type) { |
|
1613 | - switch ($type) { |
|
1614 | - case 'object': |
|
1615 | - return [ |
|
1616 | - 'title' => null, |
|
1617 | - 'description' => null, |
|
1618 | - ]; |
|
1619 | - case 'user': |
|
1620 | - return [ |
|
1621 | - 'name' => null, |
|
1622 | - 'username' => null, |
|
1623 | - 'password_hash' => null, |
|
1624 | - 'email' => null, |
|
1625 | - 'language' => null, |
|
1626 | - 'banned' => "no", |
|
1627 | - 'admin' => 'no', |
|
1628 | - 'prev_last_action' => null, |
|
1629 | - 'last_login' => null, |
|
1630 | - 'prev_last_login' => null, |
|
1631 | - ]; |
|
1632 | - case 'group': |
|
1633 | - return [ |
|
1634 | - 'name' => null, |
|
1635 | - 'description' => null, |
|
1636 | - ]; |
|
1637 | - case 'site': |
|
1638 | - return [ |
|
1639 | - 'name' => null, |
|
1640 | - 'description' => null, |
|
1641 | - 'url' => null, |
|
1642 | - ]; |
|
1643 | - } |
|
1644 | - throw new \InvalidArgumentException("Not a recognized type: $type"); |
|
1645 | - } |
|
1532 | + if ($db->updateData($query, false, $params) === false) { |
|
1533 | + return false; |
|
1534 | + } |
|
1535 | + |
|
1536 | + elgg_trigger_after_event('update', $this->type, $this); |
|
1537 | + |
|
1538 | + // TODO(evan): Move this to \ElggObject? |
|
1539 | + if ($this instanceof \ElggObject) { |
|
1540 | + update_river_access_by_object($guid, $access_id); |
|
1541 | + } |
|
1542 | + |
|
1543 | + $this->orig_attributes = []; |
|
1544 | + |
|
1545 | + // Handle cases where there was no error BUT no rows were updated! |
|
1546 | + return true; |
|
1547 | + } |
|
1548 | + |
|
1549 | + /** |
|
1550 | + * Loads attributes from the entities table into the object. |
|
1551 | + * |
|
1552 | + * @param \stdClass $row Object of properties from database row(s) |
|
1553 | + * |
|
1554 | + * @return bool |
|
1555 | + */ |
|
1556 | + protected function load(\stdClass $row) { |
|
1557 | + $type = $this->type; |
|
1558 | + |
|
1559 | + $attr_loader = new \Elgg\AttributeLoader(get_class($this), $type, $this->attributes); |
|
1560 | + if ($type === 'user' || $this instanceof ElggPlugin) { |
|
1561 | + $attr_loader->requires_access_control = false; |
|
1562 | + } |
|
1563 | + $attr_loader->secondary_loader = "get_{$type}_entity_as_row"; |
|
1564 | + |
|
1565 | + $attrs = $attr_loader->getRequiredAttributes($row); |
|
1566 | + if (!$attrs) { |
|
1567 | + return false; |
|
1568 | + } |
|
1569 | + |
|
1570 | + $this->attributes = $attrs; |
|
1571 | + |
|
1572 | + foreach ($attr_loader->getAdditionalSelectValues() as $name => $value) { |
|
1573 | + $this->setVolatileData("select:$name", $value); |
|
1574 | + } |
|
1575 | + |
|
1576 | + _elgg_services()->entityCache->set($this); |
|
1577 | + |
|
1578 | + return true; |
|
1579 | + } |
|
1580 | + |
|
1581 | + /** |
|
1582 | + * Get the added columns (besides GUID) stored in the secondary table |
|
1583 | + * |
|
1584 | + * @return string[] |
|
1585 | + * @throws \InvalidArgumentException |
|
1586 | + */ |
|
1587 | + private function getSecondaryTableColumns() { |
|
1588 | + // Note: the title or name column must come first. See getDisplayName(). |
|
1589 | + if ($this instanceof ElggObject) { |
|
1590 | + return ['title', 'description']; |
|
1591 | + } |
|
1592 | + if ($this instanceof ElggUser) { |
|
1593 | + return ['name', 'username', 'password_hash', 'email', 'language']; |
|
1594 | + } |
|
1595 | + if ($this instanceof ElggGroup) { |
|
1596 | + return ['name', 'description']; |
|
1597 | + } |
|
1598 | + if ($this instanceof ElggSite) { |
|
1599 | + return ['name', 'description', 'url']; |
|
1600 | + } |
|
1601 | + throw new \InvalidArgumentException("Not a recognized type: " . get_class($this)); |
|
1602 | + } |
|
1603 | + |
|
1604 | + /** |
|
1605 | + * Get default values for the attributes not defined in \ElggEntity::initializeAttributes |
|
1606 | + * |
|
1607 | + * @param string $type Entity type |
|
1608 | + * |
|
1609 | + * @return array |
|
1610 | + * @access private |
|
1611 | + */ |
|
1612 | + public static function getExtraAttributeDefaults($type) { |
|
1613 | + switch ($type) { |
|
1614 | + case 'object': |
|
1615 | + return [ |
|
1616 | + 'title' => null, |
|
1617 | + 'description' => null, |
|
1618 | + ]; |
|
1619 | + case 'user': |
|
1620 | + return [ |
|
1621 | + 'name' => null, |
|
1622 | + 'username' => null, |
|
1623 | + 'password_hash' => null, |
|
1624 | + 'email' => null, |
|
1625 | + 'language' => null, |
|
1626 | + 'banned' => "no", |
|
1627 | + 'admin' => 'no', |
|
1628 | + 'prev_last_action' => null, |
|
1629 | + 'last_login' => null, |
|
1630 | + 'prev_last_login' => null, |
|
1631 | + ]; |
|
1632 | + case 'group': |
|
1633 | + return [ |
|
1634 | + 'name' => null, |
|
1635 | + 'description' => null, |
|
1636 | + ]; |
|
1637 | + case 'site': |
|
1638 | + return [ |
|
1639 | + 'name' => null, |
|
1640 | + 'description' => null, |
|
1641 | + 'url' => null, |
|
1642 | + ]; |
|
1643 | + } |
|
1644 | + throw new \InvalidArgumentException("Not a recognized type: $type"); |
|
1645 | + } |
|
1646 | 1646 | |
1647 | - /** |
|
1648 | - * Load new data from database into existing entity. Overwrites data but |
|
1649 | - * does not change values not included in the latest data. |
|
1650 | - * |
|
1651 | - * @internal This is used when the same entity is selected twice during a |
|
1652 | - * request in case different select clauses were used to load different data |
|
1653 | - * into volatile data. |
|
1654 | - * |
|
1655 | - * @param \stdClass $row DB row with new entity data |
|
1656 | - * @return bool |
|
1657 | - * @access private |
|
1658 | - */ |
|
1659 | - public function refresh(\stdClass $row) { |
|
1660 | - if ($row instanceof \stdClass) { |
|
1661 | - return $this->load($row); |
|
1662 | - } |
|
1663 | - return false; |
|
1664 | - } |
|
1665 | - |
|
1666 | - /** |
|
1667 | - * Disable this entity. |
|
1668 | - * |
|
1669 | - * Disabled entities are not returned by getter functions. |
|
1670 | - * To enable an entity, use {@link \ElggEntity::enable()}. |
|
1671 | - * |
|
1672 | - * Recursively disabling an entity will disable all entities |
|
1673 | - * owned or contained by the parent entity. |
|
1674 | - * |
|
1675 | - * You can ignore the disabled field by using {@link access_show_hidden_entities()}. |
|
1676 | - * |
|
1677 | - * @note Internal: Disabling an entity sets the 'enabled' column to 'no'. |
|
1678 | - * |
|
1679 | - * @param string $reason Optional reason |
|
1680 | - * @param bool $recursive Recursively disable all contained entities? |
|
1681 | - * |
|
1682 | - * @return bool |
|
1683 | - * @see \ElggEntity::enable() |
|
1684 | - */ |
|
1685 | - public function disable($reason = "", $recursive = true) { |
|
1686 | - if (!$this->guid) { |
|
1687 | - return false; |
|
1688 | - } |
|
1647 | + /** |
|
1648 | + * Load new data from database into existing entity. Overwrites data but |
|
1649 | + * does not change values not included in the latest data. |
|
1650 | + * |
|
1651 | + * @internal This is used when the same entity is selected twice during a |
|
1652 | + * request in case different select clauses were used to load different data |
|
1653 | + * into volatile data. |
|
1654 | + * |
|
1655 | + * @param \stdClass $row DB row with new entity data |
|
1656 | + * @return bool |
|
1657 | + * @access private |
|
1658 | + */ |
|
1659 | + public function refresh(\stdClass $row) { |
|
1660 | + if ($row instanceof \stdClass) { |
|
1661 | + return $this->load($row); |
|
1662 | + } |
|
1663 | + return false; |
|
1664 | + } |
|
1665 | + |
|
1666 | + /** |
|
1667 | + * Disable this entity. |
|
1668 | + * |
|
1669 | + * Disabled entities are not returned by getter functions. |
|
1670 | + * To enable an entity, use {@link \ElggEntity::enable()}. |
|
1671 | + * |
|
1672 | + * Recursively disabling an entity will disable all entities |
|
1673 | + * owned or contained by the parent entity. |
|
1674 | + * |
|
1675 | + * You can ignore the disabled field by using {@link access_show_hidden_entities()}. |
|
1676 | + * |
|
1677 | + * @note Internal: Disabling an entity sets the 'enabled' column to 'no'. |
|
1678 | + * |
|
1679 | + * @param string $reason Optional reason |
|
1680 | + * @param bool $recursive Recursively disable all contained entities? |
|
1681 | + * |
|
1682 | + * @return bool |
|
1683 | + * @see \ElggEntity::enable() |
|
1684 | + */ |
|
1685 | + public function disable($reason = "", $recursive = true) { |
|
1686 | + if (!$this->guid) { |
|
1687 | + return false; |
|
1688 | + } |
|
1689 | 1689 | |
1690 | - if (!_elgg_services()->hooks->getEvents()->trigger('disable', $this->type, $this)) { |
|
1691 | - return false; |
|
1692 | - } |
|
1690 | + if (!_elgg_services()->hooks->getEvents()->trigger('disable', $this->type, $this)) { |
|
1691 | + return false; |
|
1692 | + } |
|
1693 | 1693 | |
1694 | - if (!$this->canEdit()) { |
|
1695 | - return false; |
|
1696 | - } |
|
1697 | - |
|
1698 | - if ($this instanceof ElggUser && $this->banned === 'no') { |
|
1699 | - // temporarily ban to prevent using the site during disable |
|
1700 | - _elgg_services()->usersTable->markBanned($this->guid, true); |
|
1701 | - $unban_after = true; |
|
1702 | - } else { |
|
1703 | - $unban_after = false; |
|
1704 | - } |
|
1705 | - |
|
1706 | - if ($reason) { |
|
1707 | - $this->disable_reason = $reason; |
|
1708 | - } |
|
1709 | - |
|
1710 | - $dbprefix = _elgg_config()->dbprefix; |
|
1694 | + if (!$this->canEdit()) { |
|
1695 | + return false; |
|
1696 | + } |
|
1697 | + |
|
1698 | + if ($this instanceof ElggUser && $this->banned === 'no') { |
|
1699 | + // temporarily ban to prevent using the site during disable |
|
1700 | + _elgg_services()->usersTable->markBanned($this->guid, true); |
|
1701 | + $unban_after = true; |
|
1702 | + } else { |
|
1703 | + $unban_after = false; |
|
1704 | + } |
|
1705 | + |
|
1706 | + if ($reason) { |
|
1707 | + $this->disable_reason = $reason; |
|
1708 | + } |
|
1709 | + |
|
1710 | + $dbprefix = _elgg_config()->dbprefix; |
|
1711 | 1711 | |
1712 | - $guid = (int) $this->guid; |
|
1712 | + $guid = (int) $this->guid; |
|
1713 | 1713 | |
1714 | - if ($recursive) { |
|
1715 | - // Only disable enabled subentities |
|
1716 | - $hidden = access_get_show_hidden_status(); |
|
1717 | - access_show_hidden_entities(false); |
|
1718 | - |
|
1719 | - $ia = elgg_set_ignore_access(true); |
|
1720 | - |
|
1721 | - $base_options = [ |
|
1722 | - 'wheres' => [ |
|
1723 | - "e.guid != $guid", |
|
1724 | - ], |
|
1725 | - 'limit' => false, |
|
1726 | - ]; |
|
1714 | + if ($recursive) { |
|
1715 | + // Only disable enabled subentities |
|
1716 | + $hidden = access_get_show_hidden_status(); |
|
1717 | + access_show_hidden_entities(false); |
|
1718 | + |
|
1719 | + $ia = elgg_set_ignore_access(true); |
|
1720 | + |
|
1721 | + $base_options = [ |
|
1722 | + 'wheres' => [ |
|
1723 | + "e.guid != $guid", |
|
1724 | + ], |
|
1725 | + 'limit' => false, |
|
1726 | + ]; |
|
1727 | 1727 | |
1728 | - foreach (['owner_guid', 'container_guid'] as $db_column) { |
|
1729 | - $options = $base_options; |
|
1730 | - $options[$db_column] = $guid; |
|
1728 | + foreach (['owner_guid', 'container_guid'] as $db_column) { |
|
1729 | + $options = $base_options; |
|
1730 | + $options[$db_column] = $guid; |
|
1731 | 1731 | |
1732 | - $subentities = new \ElggBatch('elgg_get_entities', $options); |
|
1733 | - $subentities->setIncrementOffset(false); |
|
1732 | + $subentities = new \ElggBatch('elgg_get_entities', $options); |
|
1733 | + $subentities->setIncrementOffset(false); |
|
1734 | 1734 | |
1735 | - foreach ($subentities as $subentity) { |
|
1736 | - /* @var $subentity \ElggEntity */ |
|
1737 | - if (!$subentity->isEnabled()) { |
|
1738 | - continue; |
|
1739 | - } |
|
1740 | - add_entity_relationship($subentity->guid, 'disabled_with', $guid); |
|
1741 | - $subentity->disable($reason); |
|
1742 | - } |
|
1743 | - } |
|
1744 | - |
|
1745 | - access_show_hidden_entities($hidden); |
|
1746 | - elgg_set_ignore_access($ia); |
|
1747 | - } |
|
1748 | - |
|
1749 | - $this->disableMetadata(); |
|
1750 | - $this->disableAnnotations(); |
|
1751 | - |
|
1752 | - _elgg_services()->entityCache->remove($guid); |
|
1753 | - _elgg_get_memcache('new_entity_cache')->delete($guid); |
|
1735 | + foreach ($subentities as $subentity) { |
|
1736 | + /* @var $subentity \ElggEntity */ |
|
1737 | + if (!$subentity->isEnabled()) { |
|
1738 | + continue; |
|
1739 | + } |
|
1740 | + add_entity_relationship($subentity->guid, 'disabled_with', $guid); |
|
1741 | + $subentity->disable($reason); |
|
1742 | + } |
|
1743 | + } |
|
1744 | + |
|
1745 | + access_show_hidden_entities($hidden); |
|
1746 | + elgg_set_ignore_access($ia); |
|
1747 | + } |
|
1748 | + |
|
1749 | + $this->disableMetadata(); |
|
1750 | + $this->disableAnnotations(); |
|
1751 | + |
|
1752 | + _elgg_services()->entityCache->remove($guid); |
|
1753 | + _elgg_get_memcache('new_entity_cache')->delete($guid); |
|
1754 | 1754 | |
1755 | - $sql = " |
|
1755 | + $sql = " |
|
1756 | 1756 | UPDATE {$dbprefix}entities |
1757 | 1757 | SET enabled = 'no' |
1758 | 1758 | WHERE guid = :guid |
1759 | 1759 | "; |
1760 | - $params = [ |
|
1761 | - ':guid' => $guid, |
|
1762 | - ]; |
|
1763 | - $disabled = $this->getDatabase()->updateData($sql, false, $params); |
|
1764 | - |
|
1765 | - if ($unban_after) { |
|
1766 | - _elgg_services()->usersTable->markBanned($this->guid, false); |
|
1767 | - } |
|
1768 | - |
|
1769 | - if ($disabled) { |
|
1770 | - $this->attributes['enabled'] = 'no'; |
|
1771 | - _elgg_services()->hooks->getEvents()->trigger('disable:after', $this->type, $this); |
|
1772 | - } |
|
1773 | - |
|
1774 | - return (bool) $disabled; |
|
1775 | - } |
|
1776 | - |
|
1777 | - /** |
|
1778 | - * Enable the entity |
|
1779 | - * |
|
1780 | - * @warning Disabled entities can't be loaded unless |
|
1781 | - * {@link access_show_hidden_entities(true)} has been called. |
|
1782 | - * |
|
1783 | - * @param bool $recursive Recursively enable all entities disabled with the entity? |
|
1784 | - * @see access_show_hiden_entities() |
|
1785 | - * @return bool |
|
1786 | - */ |
|
1787 | - public function enable($recursive = true) { |
|
1788 | - $guid = (int) $this->guid; |
|
1789 | - if (!$guid) { |
|
1790 | - return false; |
|
1791 | - } |
|
1760 | + $params = [ |
|
1761 | + ':guid' => $guid, |
|
1762 | + ]; |
|
1763 | + $disabled = $this->getDatabase()->updateData($sql, false, $params); |
|
1764 | + |
|
1765 | + if ($unban_after) { |
|
1766 | + _elgg_services()->usersTable->markBanned($this->guid, false); |
|
1767 | + } |
|
1768 | + |
|
1769 | + if ($disabled) { |
|
1770 | + $this->attributes['enabled'] = 'no'; |
|
1771 | + _elgg_services()->hooks->getEvents()->trigger('disable:after', $this->type, $this); |
|
1772 | + } |
|
1773 | + |
|
1774 | + return (bool) $disabled; |
|
1775 | + } |
|
1776 | + |
|
1777 | + /** |
|
1778 | + * Enable the entity |
|
1779 | + * |
|
1780 | + * @warning Disabled entities can't be loaded unless |
|
1781 | + * {@link access_show_hidden_entities(true)} has been called. |
|
1782 | + * |
|
1783 | + * @param bool $recursive Recursively enable all entities disabled with the entity? |
|
1784 | + * @see access_show_hiden_entities() |
|
1785 | + * @return bool |
|
1786 | + */ |
|
1787 | + public function enable($recursive = true) { |
|
1788 | + $guid = (int) $this->guid; |
|
1789 | + if (!$guid) { |
|
1790 | + return false; |
|
1791 | + } |
|
1792 | 1792 | |
1793 | - if (!_elgg_services()->hooks->getEvents()->trigger('enable', $this->type, $this)) { |
|
1794 | - return false; |
|
1795 | - } |
|
1793 | + if (!_elgg_services()->hooks->getEvents()->trigger('enable', $this->type, $this)) { |
|
1794 | + return false; |
|
1795 | + } |
|
1796 | 1796 | |
1797 | - if (!$this->canEdit()) { |
|
1798 | - return false; |
|
1799 | - } |
|
1797 | + if (!$this->canEdit()) { |
|
1798 | + return false; |
|
1799 | + } |
|
1800 | 1800 | |
1801 | - // Override access only visible entities |
|
1802 | - $old_access_status = access_get_show_hidden_status(); |
|
1803 | - access_show_hidden_entities(true); |
|
1801 | + // Override access only visible entities |
|
1802 | + $old_access_status = access_get_show_hidden_status(); |
|
1803 | + access_show_hidden_entities(true); |
|
1804 | 1804 | |
1805 | - $db = $this->getDatabase(); |
|
1806 | - $result = $db->updateData(" |
|
1805 | + $db = $this->getDatabase(); |
|
1806 | + $result = $db->updateData(" |
|
1807 | 1807 | UPDATE {$db->prefix}entities |
1808 | 1808 | SET enabled = 'yes' |
1809 | 1809 | WHERE guid = $guid |
1810 | 1810 | "); |
1811 | 1811 | |
1812 | - $this->deleteMetadata('disable_reason'); |
|
1813 | - $this->enableMetadata(); |
|
1814 | - $this->enableAnnotations(); |
|
1815 | - |
|
1816 | - if ($recursive) { |
|
1817 | - $disabled_with_it = elgg_get_entities_from_relationship([ |
|
1818 | - 'relationship' => 'disabled_with', |
|
1819 | - 'relationship_guid' => $guid, |
|
1820 | - 'inverse_relationship' => true, |
|
1821 | - 'limit' => 0, |
|
1822 | - ]); |
|
1823 | - |
|
1824 | - foreach ($disabled_with_it as $e) { |
|
1825 | - $e->enable(); |
|
1826 | - remove_entity_relationship($e->guid, 'disabled_with', $guid); |
|
1827 | - } |
|
1828 | - } |
|
1812 | + $this->deleteMetadata('disable_reason'); |
|
1813 | + $this->enableMetadata(); |
|
1814 | + $this->enableAnnotations(); |
|
1815 | + |
|
1816 | + if ($recursive) { |
|
1817 | + $disabled_with_it = elgg_get_entities_from_relationship([ |
|
1818 | + 'relationship' => 'disabled_with', |
|
1819 | + 'relationship_guid' => $guid, |
|
1820 | + 'inverse_relationship' => true, |
|
1821 | + 'limit' => 0, |
|
1822 | + ]); |
|
1823 | + |
|
1824 | + foreach ($disabled_with_it as $e) { |
|
1825 | + $e->enable(); |
|
1826 | + remove_entity_relationship($e->guid, 'disabled_with', $guid); |
|
1827 | + } |
|
1828 | + } |
|
1829 | 1829 | |
1830 | - access_show_hidden_entities($old_access_status); |
|
1830 | + access_show_hidden_entities($old_access_status); |
|
1831 | 1831 | |
1832 | - if ($result) { |
|
1833 | - $this->attributes['enabled'] = 'yes'; |
|
1834 | - _elgg_services()->hooks->getEvents()->trigger('enable:after', $this->type, $this); |
|
1835 | - } |
|
1836 | - |
|
1837 | - return $result; |
|
1838 | - } |
|
1839 | - |
|
1840 | - /** |
|
1841 | - * Is this entity enabled? |
|
1842 | - * |
|
1843 | - * @return boolean Whether this entity is enabled. |
|
1844 | - */ |
|
1845 | - public function isEnabled() { |
|
1846 | - return $this->enabled == 'yes'; |
|
1847 | - } |
|
1848 | - |
|
1849 | - /** |
|
1850 | - * Deletes the entity. |
|
1851 | - * |
|
1852 | - * Removes the entity and its metadata, annotations, relationships, |
|
1853 | - * river entries, and private data. |
|
1854 | - * |
|
1855 | - * Optionally can remove entities contained and owned by this entity. |
|
1856 | - * |
|
1857 | - * @warning If deleting recursively, this bypasses ownership of items contained by |
|
1858 | - * the entity. That means that if the container_guid = $this->guid, the item will |
|
1859 | - * be deleted regardless of who owns it. |
|
1860 | - * |
|
1861 | - * @param bool $recursive If true (default) then all entities which are |
|
1862 | - * owned or contained by $this will also be deleted. |
|
1863 | - * |
|
1864 | - * @return bool |
|
1865 | - */ |
|
1866 | - public function delete($recursive = true) { |
|
1867 | - |
|
1868 | - $guid = $this->guid; |
|
1869 | - if (!$guid) { |
|
1870 | - return false; |
|
1871 | - } |
|
1832 | + if ($result) { |
|
1833 | + $this->attributes['enabled'] = 'yes'; |
|
1834 | + _elgg_services()->hooks->getEvents()->trigger('enable:after', $this->type, $this); |
|
1835 | + } |
|
1836 | + |
|
1837 | + return $result; |
|
1838 | + } |
|
1839 | + |
|
1840 | + /** |
|
1841 | + * Is this entity enabled? |
|
1842 | + * |
|
1843 | + * @return boolean Whether this entity is enabled. |
|
1844 | + */ |
|
1845 | + public function isEnabled() { |
|
1846 | + return $this->enabled == 'yes'; |
|
1847 | + } |
|
1848 | + |
|
1849 | + /** |
|
1850 | + * Deletes the entity. |
|
1851 | + * |
|
1852 | + * Removes the entity and its metadata, annotations, relationships, |
|
1853 | + * river entries, and private data. |
|
1854 | + * |
|
1855 | + * Optionally can remove entities contained and owned by this entity. |
|
1856 | + * |
|
1857 | + * @warning If deleting recursively, this bypasses ownership of items contained by |
|
1858 | + * the entity. That means that if the container_guid = $this->guid, the item will |
|
1859 | + * be deleted regardless of who owns it. |
|
1860 | + * |
|
1861 | + * @param bool $recursive If true (default) then all entities which are |
|
1862 | + * owned or contained by $this will also be deleted. |
|
1863 | + * |
|
1864 | + * @return bool |
|
1865 | + */ |
|
1866 | + public function delete($recursive = true) { |
|
1867 | + |
|
1868 | + $guid = $this->guid; |
|
1869 | + if (!$guid) { |
|
1870 | + return false; |
|
1871 | + } |
|
1872 | 1872 | |
1873 | - // first check if we can delete this entity |
|
1874 | - // NOTE: in Elgg <= 1.10.3 this was after the delete event, |
|
1875 | - // which could potentially remove some content if the user didn't have access |
|
1876 | - if (!$this->canDelete()) { |
|
1877 | - return false; |
|
1878 | - } |
|
1879 | - |
|
1880 | - // now trigger an event to let others know this entity is about to be deleted |
|
1881 | - // so they can prevent it or take their own actions |
|
1882 | - if (!_elgg_services()->hooks->getEvents()->trigger('delete', $this->type, $this)) { |
|
1883 | - return false; |
|
1884 | - } |
|
1885 | - |
|
1886 | - if ($this instanceof ElggUser) { |
|
1887 | - // ban to prevent using the site during delete |
|
1888 | - _elgg_services()->usersTable->markBanned($this->guid, true); |
|
1889 | - } |
|
1890 | - |
|
1891 | - // Delete contained owned and otherwise releated objects (depth first) |
|
1892 | - if ($recursive) { |
|
1893 | - // Temporarily overriding access controls |
|
1894 | - $entity_disable_override = access_get_show_hidden_status(); |
|
1895 | - access_show_hidden_entities(true); |
|
1896 | - $ia = elgg_set_ignore_access(true); |
|
1897 | - |
|
1898 | - // @todo there was logic in the original code that ignored |
|
1899 | - // entities with owner or container guids of themselves. |
|
1900 | - // this should probably be prevented in \ElggEntity instead of checked for here |
|
1901 | - $base_options = [ |
|
1902 | - 'wheres' => [ |
|
1903 | - "e.guid != $guid", |
|
1904 | - ], |
|
1905 | - 'limit' => false, |
|
1906 | - ]; |
|
1873 | + // first check if we can delete this entity |
|
1874 | + // NOTE: in Elgg <= 1.10.3 this was after the delete event, |
|
1875 | + // which could potentially remove some content if the user didn't have access |
|
1876 | + if (!$this->canDelete()) { |
|
1877 | + return false; |
|
1878 | + } |
|
1879 | + |
|
1880 | + // now trigger an event to let others know this entity is about to be deleted |
|
1881 | + // so they can prevent it or take their own actions |
|
1882 | + if (!_elgg_services()->hooks->getEvents()->trigger('delete', $this->type, $this)) { |
|
1883 | + return false; |
|
1884 | + } |
|
1885 | + |
|
1886 | + if ($this instanceof ElggUser) { |
|
1887 | + // ban to prevent using the site during delete |
|
1888 | + _elgg_services()->usersTable->markBanned($this->guid, true); |
|
1889 | + } |
|
1890 | + |
|
1891 | + // Delete contained owned and otherwise releated objects (depth first) |
|
1892 | + if ($recursive) { |
|
1893 | + // Temporarily overriding access controls |
|
1894 | + $entity_disable_override = access_get_show_hidden_status(); |
|
1895 | + access_show_hidden_entities(true); |
|
1896 | + $ia = elgg_set_ignore_access(true); |
|
1897 | + |
|
1898 | + // @todo there was logic in the original code that ignored |
|
1899 | + // entities with owner or container guids of themselves. |
|
1900 | + // this should probably be prevented in \ElggEntity instead of checked for here |
|
1901 | + $base_options = [ |
|
1902 | + 'wheres' => [ |
|
1903 | + "e.guid != $guid", |
|
1904 | + ], |
|
1905 | + 'limit' => false, |
|
1906 | + ]; |
|
1907 | 1907 | |
1908 | - foreach (['owner_guid', 'container_guid'] as $db_column) { |
|
1909 | - $options = $base_options; |
|
1910 | - $options[$db_column] = $guid; |
|
1908 | + foreach (['owner_guid', 'container_guid'] as $db_column) { |
|
1909 | + $options = $base_options; |
|
1910 | + $options[$db_column] = $guid; |
|
1911 | 1911 | |
1912 | - $batch = new \ElggBatch('elgg_get_entities', $options); |
|
1913 | - $batch->setIncrementOffset(false); |
|
1912 | + $batch = new \ElggBatch('elgg_get_entities', $options); |
|
1913 | + $batch->setIncrementOffset(false); |
|
1914 | 1914 | |
1915 | - /* @var $e \ElggEntity */ |
|
1916 | - foreach ($batch as $e) { |
|
1917 | - $e->delete(true); |
|
1918 | - } |
|
1919 | - } |
|
1915 | + /* @var $e \ElggEntity */ |
|
1916 | + foreach ($batch as $e) { |
|
1917 | + $e->delete(true); |
|
1918 | + } |
|
1919 | + } |
|
1920 | 1920 | |
1921 | - access_show_hidden_entities($entity_disable_override); |
|
1922 | - elgg_set_ignore_access($ia); |
|
1923 | - } |
|
1921 | + access_show_hidden_entities($entity_disable_override); |
|
1922 | + elgg_set_ignore_access($ia); |
|
1923 | + } |
|
1924 | 1924 | |
1925 | - $entity_disable_override = access_get_show_hidden_status(); |
|
1926 | - access_show_hidden_entities(true); |
|
1927 | - $ia = elgg_set_ignore_access(true); |
|
1925 | + $entity_disable_override = access_get_show_hidden_status(); |
|
1926 | + access_show_hidden_entities(true); |
|
1927 | + $ia = elgg_set_ignore_access(true); |
|
1928 | 1928 | |
1929 | - // Now delete the entity itself |
|
1930 | - $this->deleteMetadata(); |
|
1931 | - $this->deleteOwnedMetadata(); |
|
1932 | - $this->deleteAnnotations(); |
|
1933 | - $this->deleteOwnedAnnotations(); |
|
1934 | - $this->deleteRelationships(); |
|
1935 | - $this->deleteAccessCollectionMemberships(); |
|
1936 | - $this->deleteOwnedAccessCollections(); |
|
1937 | - |
|
1938 | - access_show_hidden_entities($entity_disable_override); |
|
1939 | - elgg_set_ignore_access($ia); |
|
1940 | - |
|
1941 | - elgg_delete_river(['subject_guid' => $guid, 'limit' => false]); |
|
1942 | - elgg_delete_river(['object_guid' => $guid, 'limit' => false]); |
|
1943 | - elgg_delete_river(['target_guid' => $guid, 'limit' => false]); |
|
1929 | + // Now delete the entity itself |
|
1930 | + $this->deleteMetadata(); |
|
1931 | + $this->deleteOwnedMetadata(); |
|
1932 | + $this->deleteAnnotations(); |
|
1933 | + $this->deleteOwnedAnnotations(); |
|
1934 | + $this->deleteRelationships(); |
|
1935 | + $this->deleteAccessCollectionMemberships(); |
|
1936 | + $this->deleteOwnedAccessCollections(); |
|
1937 | + |
|
1938 | + access_show_hidden_entities($entity_disable_override); |
|
1939 | + elgg_set_ignore_access($ia); |
|
1940 | + |
|
1941 | + elgg_delete_river(['subject_guid' => $guid, 'limit' => false]); |
|
1942 | + elgg_delete_river(['object_guid' => $guid, 'limit' => false]); |
|
1943 | + elgg_delete_river(['target_guid' => $guid, 'limit' => false]); |
|
1944 | 1944 | |
1945 | - remove_all_private_settings($guid); |
|
1945 | + remove_all_private_settings($guid); |
|
1946 | 1946 | |
1947 | - _elgg_invalidate_cache_for_entity($guid); |
|
1948 | - _elgg_invalidate_memcache_for_entity($guid); |
|
1947 | + _elgg_invalidate_cache_for_entity($guid); |
|
1948 | + _elgg_invalidate_memcache_for_entity($guid); |
|
1949 | 1949 | |
1950 | - $dbprefix = _elgg_config()->dbprefix; |
|
1950 | + $dbprefix = _elgg_config()->dbprefix; |
|
1951 | 1951 | |
1952 | - $sql = " |
|
1952 | + $sql = " |
|
1953 | 1953 | DELETE FROM {$dbprefix}entities |
1954 | 1954 | WHERE guid = :guid |
1955 | 1955 | "; |
1956 | - $params = [ |
|
1957 | - ':guid' => $guid, |
|
1958 | - ]; |
|
1956 | + $params = [ |
|
1957 | + ':guid' => $guid, |
|
1958 | + ]; |
|
1959 | 1959 | |
1960 | - $deleted = $this->getDatabase()->deleteData($sql, $params); |
|
1960 | + $deleted = $this->getDatabase()->deleteData($sql, $params); |
|
1961 | 1961 | |
1962 | - if ($deleted && in_array($this->type, ['object', 'user', 'group', 'site'])) { |
|
1963 | - // delete from type-specific subtable |
|
1964 | - $sql = " |
|
1962 | + if ($deleted && in_array($this->type, ['object', 'user', 'group', 'site'])) { |
|
1963 | + // delete from type-specific subtable |
|
1964 | + $sql = " |
|
1965 | 1965 | DELETE FROM {$dbprefix}{$this->type}s_entity |
1966 | 1966 | WHERE guid = :guid |
1967 | 1967 | "; |
1968 | - $this->getDatabase()->deleteData($sql, $params); |
|
1969 | - } |
|
1968 | + $this->getDatabase()->deleteData($sql, $params); |
|
1969 | + } |
|
1970 | 1970 | |
1971 | - _elgg_clear_entity_files($this); |
|
1972 | - |
|
1973 | - return (bool) $deleted; |
|
1974 | - } |
|
1975 | - |
|
1976 | - /** |
|
1977 | - * {@inheritdoc} |
|
1978 | - */ |
|
1979 | - public function toObject() { |
|
1980 | - $object = $this->prepareObject(new \stdClass()); |
|
1981 | - $params = ['entity' => $this]; |
|
1982 | - $object = _elgg_services()->hooks->trigger('to:object', 'entity', $params, $object); |
|
1983 | - return $object; |
|
1984 | - } |
|
1985 | - |
|
1986 | - /** |
|
1987 | - * Prepare an object copy for toObject() |
|
1988 | - * |
|
1989 | - * @param \stdClass $object Object representation of the entity |
|
1990 | - * @return \stdClass |
|
1991 | - */ |
|
1992 | - protected function prepareObject($object) { |
|
1993 | - $object->guid = $this->guid; |
|
1994 | - $object->type = $this->getType(); |
|
1995 | - $object->subtype = $this->getSubtype(); |
|
1996 | - $object->owner_guid = $this->getOwnerGUID(); |
|
1997 | - $object->container_guid = $this->getContainerGUID(); |
|
1998 | - $object->time_created = date('c', $this->getTimeCreated()); |
|
1999 | - $object->time_updated = date('c', $this->getTimeUpdated()); |
|
2000 | - $object->url = $this->getURL(); |
|
2001 | - $object->read_access = (int) $this->access_id; |
|
2002 | - return $object; |
|
2003 | - } |
|
2004 | - |
|
2005 | - /* |
|
1971 | + _elgg_clear_entity_files($this); |
|
1972 | + |
|
1973 | + return (bool) $deleted; |
|
1974 | + } |
|
1975 | + |
|
1976 | + /** |
|
1977 | + * {@inheritdoc} |
|
1978 | + */ |
|
1979 | + public function toObject() { |
|
1980 | + $object = $this->prepareObject(new \stdClass()); |
|
1981 | + $params = ['entity' => $this]; |
|
1982 | + $object = _elgg_services()->hooks->trigger('to:object', 'entity', $params, $object); |
|
1983 | + return $object; |
|
1984 | + } |
|
1985 | + |
|
1986 | + /** |
|
1987 | + * Prepare an object copy for toObject() |
|
1988 | + * |
|
1989 | + * @param \stdClass $object Object representation of the entity |
|
1990 | + * @return \stdClass |
|
1991 | + */ |
|
1992 | + protected function prepareObject($object) { |
|
1993 | + $object->guid = $this->guid; |
|
1994 | + $object->type = $this->getType(); |
|
1995 | + $object->subtype = $this->getSubtype(); |
|
1996 | + $object->owner_guid = $this->getOwnerGUID(); |
|
1997 | + $object->container_guid = $this->getContainerGUID(); |
|
1998 | + $object->time_created = date('c', $this->getTimeCreated()); |
|
1999 | + $object->time_updated = date('c', $this->getTimeUpdated()); |
|
2000 | + $object->url = $this->getURL(); |
|
2001 | + $object->read_access = (int) $this->access_id; |
|
2002 | + return $object; |
|
2003 | + } |
|
2004 | + |
|
2005 | + /* |
|
2006 | 2006 | * LOCATABLE INTERFACE |
2007 | 2007 | */ |
2008 | 2008 | |
2009 | - /** |
|
2010 | - * Gets the 'location' metadata for the entity |
|
2011 | - * |
|
2012 | - * @return string The location |
|
2013 | - */ |
|
2014 | - public function getLocation() { |
|
2015 | - return $this->location; |
|
2016 | - } |
|
2017 | - |
|
2018 | - /** |
|
2019 | - * Sets the 'location' metadata for the entity |
|
2020 | - * |
|
2021 | - * @param string $location String representation of the location |
|
2022 | - * |
|
2023 | - * @return void |
|
2024 | - */ |
|
2025 | - public function setLocation($location) { |
|
2026 | - $this->location = $location; |
|
2027 | - } |
|
2028 | - |
|
2029 | - /** |
|
2030 | - * Set latitude and longitude metadata tags for a given entity. |
|
2031 | - * |
|
2032 | - * @param float $lat Latitude |
|
2033 | - * @param float $long Longitude |
|
2034 | - * |
|
2035 | - * @return void |
|
2036 | - * @todo Unimplemented |
|
2037 | - */ |
|
2038 | - public function setLatLong($lat, $long) { |
|
2039 | - $this->{"geo:lat"} = $lat; |
|
2040 | - $this->{"geo:long"} = $long; |
|
2041 | - } |
|
2042 | - |
|
2043 | - /** |
|
2044 | - * Return the entity's latitude. |
|
2045 | - * |
|
2046 | - * @return float |
|
2047 | - * @todo Unimplemented |
|
2048 | - */ |
|
2049 | - public function getLatitude() { |
|
2050 | - return (float) $this->{"geo:lat"}; |
|
2051 | - } |
|
2052 | - |
|
2053 | - /** |
|
2054 | - * Return the entity's longitude |
|
2055 | - * |
|
2056 | - * @return float |
|
2057 | - * @todo Unimplemented |
|
2058 | - */ |
|
2059 | - public function getLongitude() { |
|
2060 | - return (float) $this->{"geo:long"}; |
|
2061 | - } |
|
2062 | - |
|
2063 | - /* |
|
2009 | + /** |
|
2010 | + * Gets the 'location' metadata for the entity |
|
2011 | + * |
|
2012 | + * @return string The location |
|
2013 | + */ |
|
2014 | + public function getLocation() { |
|
2015 | + return $this->location; |
|
2016 | + } |
|
2017 | + |
|
2018 | + /** |
|
2019 | + * Sets the 'location' metadata for the entity |
|
2020 | + * |
|
2021 | + * @param string $location String representation of the location |
|
2022 | + * |
|
2023 | + * @return void |
|
2024 | + */ |
|
2025 | + public function setLocation($location) { |
|
2026 | + $this->location = $location; |
|
2027 | + } |
|
2028 | + |
|
2029 | + /** |
|
2030 | + * Set latitude and longitude metadata tags for a given entity. |
|
2031 | + * |
|
2032 | + * @param float $lat Latitude |
|
2033 | + * @param float $long Longitude |
|
2034 | + * |
|
2035 | + * @return void |
|
2036 | + * @todo Unimplemented |
|
2037 | + */ |
|
2038 | + public function setLatLong($lat, $long) { |
|
2039 | + $this->{"geo:lat"} = $lat; |
|
2040 | + $this->{"geo:long"} = $long; |
|
2041 | + } |
|
2042 | + |
|
2043 | + /** |
|
2044 | + * Return the entity's latitude. |
|
2045 | + * |
|
2046 | + * @return float |
|
2047 | + * @todo Unimplemented |
|
2048 | + */ |
|
2049 | + public function getLatitude() { |
|
2050 | + return (float) $this->{"geo:lat"}; |
|
2051 | + } |
|
2052 | + |
|
2053 | + /** |
|
2054 | + * Return the entity's longitude |
|
2055 | + * |
|
2056 | + * @return float |
|
2057 | + * @todo Unimplemented |
|
2058 | + */ |
|
2059 | + public function getLongitude() { |
|
2060 | + return (float) $this->{"geo:long"}; |
|
2061 | + } |
|
2062 | + |
|
2063 | + /* |
|
2064 | 2064 | * SYSTEM LOG INTERFACE |
2065 | 2065 | */ |
2066 | 2066 | |
2067 | - /** |
|
2068 | - * Return an identification for the object for storage in the system log. |
|
2069 | - * This id must be an integer. |
|
2070 | - * |
|
2071 | - * @return int |
|
2072 | - */ |
|
2073 | - public function getSystemLogID() { |
|
2074 | - return $this->getGUID(); |
|
2075 | - } |
|
2076 | - |
|
2077 | - /** |
|
2078 | - * For a given ID, return the object associated with it. |
|
2079 | - * This is used by the system log. It can be called on any Loggable object. |
|
2080 | - * |
|
2081 | - * @param int $id GUID. |
|
2082 | - * @return int GUID |
|
2083 | - */ |
|
2084 | - public function getObjectFromID($id) { |
|
2085 | - return get_entity($id); |
|
2086 | - } |
|
2087 | - |
|
2088 | - /** |
|
2089 | - * Returns tags for this entity. |
|
2090 | - * |
|
2091 | - * @warning Tags must be registered by {@link elgg_register_tag_metadata_name()}. |
|
2092 | - * |
|
2093 | - * @param array $tag_names Optionally restrict by tag metadata names. |
|
2094 | - * |
|
2095 | - * @return array |
|
2096 | - */ |
|
2097 | - public function getTags($tag_names = null) { |
|
2098 | - if ($tag_names && !is_array($tag_names)) { |
|
2099 | - $tag_names = [$tag_names]; |
|
2100 | - } |
|
2101 | - |
|
2102 | - $valid_tags = elgg_get_registered_tag_metadata_names(); |
|
2103 | - $entity_tags = []; |
|
2104 | - |
|
2105 | - foreach ($valid_tags as $tag_name) { |
|
2106 | - if (is_array($tag_names) && !in_array($tag_name, $tag_names)) { |
|
2107 | - continue; |
|
2108 | - } |
|
2109 | - |
|
2110 | - if ($tags = $this->$tag_name) { |
|
2111 | - // if a single tag, metadata returns a string. |
|
2112 | - // if multiple tags, metadata returns an array. |
|
2113 | - if (is_array($tags)) { |
|
2114 | - $entity_tags = array_merge($entity_tags, $tags); |
|
2115 | - } else { |
|
2116 | - $entity_tags[] = $tags; |
|
2117 | - } |
|
2118 | - } |
|
2119 | - } |
|
2120 | - |
|
2121 | - return $entity_tags; |
|
2122 | - } |
|
2067 | + /** |
|
2068 | + * Return an identification for the object for storage in the system log. |
|
2069 | + * This id must be an integer. |
|
2070 | + * |
|
2071 | + * @return int |
|
2072 | + */ |
|
2073 | + public function getSystemLogID() { |
|
2074 | + return $this->getGUID(); |
|
2075 | + } |
|
2076 | + |
|
2077 | + /** |
|
2078 | + * For a given ID, return the object associated with it. |
|
2079 | + * This is used by the system log. It can be called on any Loggable object. |
|
2080 | + * |
|
2081 | + * @param int $id GUID. |
|
2082 | + * @return int GUID |
|
2083 | + */ |
|
2084 | + public function getObjectFromID($id) { |
|
2085 | + return get_entity($id); |
|
2086 | + } |
|
2087 | + |
|
2088 | + /** |
|
2089 | + * Returns tags for this entity. |
|
2090 | + * |
|
2091 | + * @warning Tags must be registered by {@link elgg_register_tag_metadata_name()}. |
|
2092 | + * |
|
2093 | + * @param array $tag_names Optionally restrict by tag metadata names. |
|
2094 | + * |
|
2095 | + * @return array |
|
2096 | + */ |
|
2097 | + public function getTags($tag_names = null) { |
|
2098 | + if ($tag_names && !is_array($tag_names)) { |
|
2099 | + $tag_names = [$tag_names]; |
|
2100 | + } |
|
2101 | + |
|
2102 | + $valid_tags = elgg_get_registered_tag_metadata_names(); |
|
2103 | + $entity_tags = []; |
|
2104 | + |
|
2105 | + foreach ($valid_tags as $tag_name) { |
|
2106 | + if (is_array($tag_names) && !in_array($tag_name, $tag_names)) { |
|
2107 | + continue; |
|
2108 | + } |
|
2109 | + |
|
2110 | + if ($tags = $this->$tag_name) { |
|
2111 | + // if a single tag, metadata returns a string. |
|
2112 | + // if multiple tags, metadata returns an array. |
|
2113 | + if (is_array($tags)) { |
|
2114 | + $entity_tags = array_merge($entity_tags, $tags); |
|
2115 | + } else { |
|
2116 | + $entity_tags[] = $tags; |
|
2117 | + } |
|
2118 | + } |
|
2119 | + } |
|
2120 | + |
|
2121 | + return $entity_tags; |
|
2122 | + } |
|
2123 | 2123 | |
2124 | - /** |
|
2125 | - * Remove the membership of all access collections for this entity (if the entity is a user) |
|
2126 | - * |
|
2127 | - * @return bool |
|
2128 | - * @since 1.11 |
|
2129 | - */ |
|
2130 | - public function deleteAccessCollectionMemberships() { |
|
2124 | + /** |
|
2125 | + * Remove the membership of all access collections for this entity (if the entity is a user) |
|
2126 | + * |
|
2127 | + * @return bool |
|
2128 | + * @since 1.11 |
|
2129 | + */ |
|
2130 | + public function deleteAccessCollectionMemberships() { |
|
2131 | 2131 | |
2132 | - if (!$this->guid) { |
|
2133 | - return false; |
|
2134 | - } |
|
2132 | + if (!$this->guid) { |
|
2133 | + return false; |
|
2134 | + } |
|
2135 | 2135 | |
2136 | - if ($this->type !== 'user') { |
|
2137 | - return true; |
|
2138 | - } |
|
2136 | + if ($this->type !== 'user') { |
|
2137 | + return true; |
|
2138 | + } |
|
2139 | 2139 | |
2140 | - $ac = _elgg_services()->accessCollections; |
|
2140 | + $ac = _elgg_services()->accessCollections; |
|
2141 | 2141 | |
2142 | - $collections = $ac->getCollectionsByMember($this->guid); |
|
2143 | - if (empty($collections)) { |
|
2144 | - return true; |
|
2145 | - } |
|
2142 | + $collections = $ac->getCollectionsByMember($this->guid); |
|
2143 | + if (empty($collections)) { |
|
2144 | + return true; |
|
2145 | + } |
|
2146 | 2146 | |
2147 | - $result = true; |
|
2148 | - foreach ($collections as $collection) { |
|
2149 | - $result = $result & $ac->removeUser($this->guid, $collection->id); |
|
2150 | - } |
|
2147 | + $result = true; |
|
2148 | + foreach ($collections as $collection) { |
|
2149 | + $result = $result & $ac->removeUser($this->guid, $collection->id); |
|
2150 | + } |
|
2151 | 2151 | |
2152 | - return $result; |
|
2153 | - } |
|
2152 | + return $result; |
|
2153 | + } |
|
2154 | 2154 | |
2155 | - /** |
|
2156 | - * Remove all access collections owned by this entity |
|
2157 | - * |
|
2158 | - * @return bool |
|
2159 | - * @since 1.11 |
|
2160 | - */ |
|
2161 | - public function deleteOwnedAccessCollections() { |
|
2155 | + /** |
|
2156 | + * Remove all access collections owned by this entity |
|
2157 | + * |
|
2158 | + * @return bool |
|
2159 | + * @since 1.11 |
|
2160 | + */ |
|
2161 | + public function deleteOwnedAccessCollections() { |
|
2162 | 2162 | |
2163 | - if (!$this->guid) { |
|
2164 | - return false; |
|
2165 | - } |
|
2163 | + if (!$this->guid) { |
|
2164 | + return false; |
|
2165 | + } |
|
2166 | 2166 | |
2167 | - $ac = _elgg_services()->accessCollections; |
|
2167 | + $ac = _elgg_services()->accessCollections; |
|
2168 | 2168 | |
2169 | - $collections = $ac->getEntityCollections($this->guid); |
|
2170 | - if (empty($collections)) { |
|
2171 | - return true; |
|
2172 | - } |
|
2169 | + $collections = $ac->getEntityCollections($this->guid); |
|
2170 | + if (empty($collections)) { |
|
2171 | + return true; |
|
2172 | + } |
|
2173 | 2173 | |
2174 | - $result = true; |
|
2175 | - foreach ($collections as $collection) { |
|
2176 | - $result = $result & $ac->delete($collection->id); |
|
2177 | - } |
|
2174 | + $result = true; |
|
2175 | + foreach ($collections as $collection) { |
|
2176 | + $result = $result & $ac->delete($collection->id); |
|
2177 | + } |
|
2178 | 2178 | |
2179 | - return $result; |
|
2180 | - } |
|
2181 | - |
|
2182 | - /** |
|
2183 | - * Update the last_action column in the entities table. |
|
2184 | - * |
|
2185 | - * @warning This is different to time_updated. Time_updated is automatically set, |
|
2186 | - * while last_action is only set when explicitly called. |
|
2187 | - * |
|
2188 | - * @param int $posted Timestamp of last action |
|
2189 | - * @return int|false |
|
2190 | - * @access private |
|
2191 | - */ |
|
2192 | - public function updateLastAction($posted = null) { |
|
2193 | - $posted = _elgg_services()->entityTable->updateLastAction($this, $posted); |
|
2194 | - if ($posted) { |
|
2195 | - $this->attributes['last_action'] = $posted; |
|
2196 | - _elgg_services()->entityCache->set($this); |
|
2197 | - $this->storeInPersistedCache(_elgg_get_memcache('new_entity_cache')); |
|
2198 | - } |
|
2199 | - return $posted; |
|
2200 | - } |
|
2179 | + return $result; |
|
2180 | + } |
|
2181 | + |
|
2182 | + /** |
|
2183 | + * Update the last_action column in the entities table. |
|
2184 | + * |
|
2185 | + * @warning This is different to time_updated. Time_updated is automatically set, |
|
2186 | + * while last_action is only set when explicitly called. |
|
2187 | + * |
|
2188 | + * @param int $posted Timestamp of last action |
|
2189 | + * @return int|false |
|
2190 | + * @access private |
|
2191 | + */ |
|
2192 | + public function updateLastAction($posted = null) { |
|
2193 | + $posted = _elgg_services()->entityTable->updateLastAction($this, $posted); |
|
2194 | + if ($posted) { |
|
2195 | + $this->attributes['last_action'] = $posted; |
|
2196 | + _elgg_services()->entityCache->set($this); |
|
2197 | + $this->storeInPersistedCache(_elgg_get_memcache('new_entity_cache')); |
|
2198 | + } |
|
2199 | + return $posted; |
|
2200 | + } |
|
2201 | 2201 | } |
@@ -24,179 +24,179 @@ discard block |
||
24 | 24 | */ |
25 | 25 | class AccessCollections { |
26 | 26 | |
27 | - /** |
|
28 | - * @var Conf |
|
29 | - */ |
|
30 | - protected $config; |
|
31 | - |
|
32 | - /** |
|
33 | - * @var Database |
|
34 | - */ |
|
35 | - protected $db; |
|
36 | - |
|
37 | - /** |
|
38 | - * @vars \ElggStateVariableCache |
|
39 | - */ |
|
40 | - protected $access_cache; |
|
41 | - |
|
42 | - /** |
|
43 | - * @var PluginHooksService |
|
44 | - */ |
|
45 | - protected $hooks; |
|
46 | - |
|
47 | - /** |
|
48 | - * @var ElggSession |
|
49 | - */ |
|
50 | - protected $session; |
|
51 | - |
|
52 | - /** |
|
53 | - * @var EntityTable |
|
54 | - */ |
|
55 | - protected $entities; |
|
56 | - |
|
57 | - /** |
|
58 | - * @var UserCapabilities |
|
59 | - */ |
|
60 | - protected $capabilities; |
|
61 | - |
|
62 | - /** |
|
63 | - * @var Translator |
|
64 | - */ |
|
65 | - protected $translator; |
|
66 | - |
|
67 | - /** |
|
68 | - * @var string |
|
69 | - */ |
|
70 | - protected $table; |
|
71 | - |
|
72 | - /** |
|
73 | - * @var string |
|
74 | - */ |
|
75 | - protected $membership_table; |
|
76 | - |
|
77 | - /** |
|
78 | - * @var bool |
|
79 | - */ |
|
80 | - protected $init_complete = false; |
|
81 | - |
|
82 | - /** |
|
83 | - * Constructor |
|
84 | - * |
|
85 | - * @param Conf $config Config |
|
86 | - * @param Database $db Database |
|
87 | - * @param EntityTable $entities Entity table |
|
88 | - * @param UserCapabilities $capabilities User capabilities |
|
89 | - * @param ElggStaticVariableCache $cache Access cache |
|
90 | - * @param PluginHooksService $hooks Hooks |
|
91 | - * @param ElggSession $session Session |
|
92 | - * @param Translator $translator Translator |
|
93 | - */ |
|
94 | - public function __construct( |
|
95 | - Conf $config, |
|
96 | - Database $db, |
|
97 | - EntityTable $entities, |
|
98 | - UserCapabilities $capabilities, |
|
99 | - ElggStaticVariableCache $cache, |
|
100 | - PluginHooksService $hooks, |
|
101 | - ElggSession $session, |
|
102 | - Translator $translator) { |
|
103 | - $this->config = $config; |
|
104 | - $this->db = $db; |
|
105 | - $this->entities = $entities; |
|
106 | - $this->capabilities = $capabilities; |
|
107 | - $this->access_cache = $cache; |
|
108 | - $this->hooks = $hooks; |
|
109 | - $this->session = $session; |
|
110 | - $this->translator = $translator; |
|
111 | - |
|
112 | - $this->table = "{$this->db->prefix}access_collections"; |
|
113 | - $this->membership_table = "{$this->db->prefix}access_collection_membership"; |
|
114 | - } |
|
115 | - |
|
116 | - /** |
|
117 | - * Mark the access system as initialized |
|
118 | - * |
|
119 | - * @return void |
|
120 | - */ |
|
121 | - public function markInitComplete() { |
|
122 | - $this->init_complete = true; |
|
123 | - } |
|
124 | - |
|
125 | - /** |
|
126 | - * Returns a string of access_ids for $user_guid appropriate for inserting into an SQL IN clause. |
|
127 | - * |
|
128 | - * @see get_access_array() |
|
129 | - * |
|
130 | - * @param int $user_guid User ID; defaults to currently logged in user |
|
131 | - * @param bool $flush If set to true, will refresh the access list from the |
|
132 | - * database rather than using this function's cache. |
|
133 | - * |
|
134 | - * @return string A concatenated string of access collections suitable for using in an SQL IN clause |
|
135 | - * @access private |
|
136 | - */ |
|
137 | - public function getAccessList($user_guid = 0, $flush = false) { |
|
138 | - $access_array = $this->getAccessArray($user_guid, $flush); |
|
139 | - $access_ids = implode(',', $access_array); |
|
140 | - $list = "($access_ids)"; |
|
141 | - |
|
142 | - // for BC, populate the cache |
|
143 | - $hash = $user_guid . 'get_access_list'; |
|
144 | - $this->access_cache->add($hash, $list); |
|
145 | - |
|
146 | - return $list; |
|
147 | - } |
|
148 | - |
|
149 | - /** |
|
150 | - * Returns an array of access IDs a user is permitted to see. |
|
151 | - * |
|
152 | - * Can be overridden with the 'access:collections:read', 'user' plugin hook. |
|
153 | - * @warning A callback for that plugin hook needs to either not retrieve data |
|
154 | - * from the database that would use the access system (triggering the plugin again) |
|
155 | - * or ignore the second call. Otherwise, an infinite loop will be created. |
|
156 | - * |
|
157 | - * This returns a list of all the collection ids a user owns or belongs |
|
158 | - * to plus public and logged in access levels. If the user is an admin, it includes |
|
159 | - * the private access level. |
|
160 | - * |
|
161 | - * @internal this is only used in core for creating the SQL where clause when |
|
162 | - * retrieving content from the database. The friends access level is handled by |
|
163 | - * _elgg_get_access_where_sql(). |
|
164 | - * |
|
165 | - * @see get_write_access_array() for the access levels that a user can write to. |
|
166 | - * |
|
167 | - * @param int $user_guid User ID; defaults to currently logged in user |
|
168 | - * @param bool $flush If set to true, will refresh the access ids from the |
|
169 | - * database rather than using this function's cache. |
|
170 | - * |
|
171 | - * @return array An array of access collections ids |
|
172 | - */ |
|
173 | - public function getAccessArray($user_guid = 0, $flush = false) { |
|
174 | - $cache = $this->access_cache; |
|
175 | - |
|
176 | - if ($flush) { |
|
177 | - $cache->clear(); |
|
178 | - } |
|
179 | - |
|
180 | - if ($user_guid == 0) { |
|
181 | - $user_guid = $this->session->getLoggedInUserGuid(); |
|
182 | - } |
|
183 | - |
|
184 | - $user_guid = (int) $user_guid; |
|
185 | - |
|
186 | - $hash = $user_guid . 'get_access_array'; |
|
187 | - |
|
188 | - if ($cache[$hash]) { |
|
189 | - $access_array = $cache[$hash]; |
|
190 | - } else { |
|
191 | - // Public access is always visible |
|
192 | - $access_array = [ACCESS_PUBLIC]; |
|
193 | - |
|
194 | - // The following can only return sensible data for a known user. |
|
195 | - if ($user_guid) { |
|
196 | - $access_array[] = ACCESS_LOGGED_IN; |
|
197 | - |
|
198 | - // Get ACLs that user owns or is a member of |
|
199 | - $query = " |
|
27 | + /** |
|
28 | + * @var Conf |
|
29 | + */ |
|
30 | + protected $config; |
|
31 | + |
|
32 | + /** |
|
33 | + * @var Database |
|
34 | + */ |
|
35 | + protected $db; |
|
36 | + |
|
37 | + /** |
|
38 | + * @vars \ElggStateVariableCache |
|
39 | + */ |
|
40 | + protected $access_cache; |
|
41 | + |
|
42 | + /** |
|
43 | + * @var PluginHooksService |
|
44 | + */ |
|
45 | + protected $hooks; |
|
46 | + |
|
47 | + /** |
|
48 | + * @var ElggSession |
|
49 | + */ |
|
50 | + protected $session; |
|
51 | + |
|
52 | + /** |
|
53 | + * @var EntityTable |
|
54 | + */ |
|
55 | + protected $entities; |
|
56 | + |
|
57 | + /** |
|
58 | + * @var UserCapabilities |
|
59 | + */ |
|
60 | + protected $capabilities; |
|
61 | + |
|
62 | + /** |
|
63 | + * @var Translator |
|
64 | + */ |
|
65 | + protected $translator; |
|
66 | + |
|
67 | + /** |
|
68 | + * @var string |
|
69 | + */ |
|
70 | + protected $table; |
|
71 | + |
|
72 | + /** |
|
73 | + * @var string |
|
74 | + */ |
|
75 | + protected $membership_table; |
|
76 | + |
|
77 | + /** |
|
78 | + * @var bool |
|
79 | + */ |
|
80 | + protected $init_complete = false; |
|
81 | + |
|
82 | + /** |
|
83 | + * Constructor |
|
84 | + * |
|
85 | + * @param Conf $config Config |
|
86 | + * @param Database $db Database |
|
87 | + * @param EntityTable $entities Entity table |
|
88 | + * @param UserCapabilities $capabilities User capabilities |
|
89 | + * @param ElggStaticVariableCache $cache Access cache |
|
90 | + * @param PluginHooksService $hooks Hooks |
|
91 | + * @param ElggSession $session Session |
|
92 | + * @param Translator $translator Translator |
|
93 | + */ |
|
94 | + public function __construct( |
|
95 | + Conf $config, |
|
96 | + Database $db, |
|
97 | + EntityTable $entities, |
|
98 | + UserCapabilities $capabilities, |
|
99 | + ElggStaticVariableCache $cache, |
|
100 | + PluginHooksService $hooks, |
|
101 | + ElggSession $session, |
|
102 | + Translator $translator) { |
|
103 | + $this->config = $config; |
|
104 | + $this->db = $db; |
|
105 | + $this->entities = $entities; |
|
106 | + $this->capabilities = $capabilities; |
|
107 | + $this->access_cache = $cache; |
|
108 | + $this->hooks = $hooks; |
|
109 | + $this->session = $session; |
|
110 | + $this->translator = $translator; |
|
111 | + |
|
112 | + $this->table = "{$this->db->prefix}access_collections"; |
|
113 | + $this->membership_table = "{$this->db->prefix}access_collection_membership"; |
|
114 | + } |
|
115 | + |
|
116 | + /** |
|
117 | + * Mark the access system as initialized |
|
118 | + * |
|
119 | + * @return void |
|
120 | + */ |
|
121 | + public function markInitComplete() { |
|
122 | + $this->init_complete = true; |
|
123 | + } |
|
124 | + |
|
125 | + /** |
|
126 | + * Returns a string of access_ids for $user_guid appropriate for inserting into an SQL IN clause. |
|
127 | + * |
|
128 | + * @see get_access_array() |
|
129 | + * |
|
130 | + * @param int $user_guid User ID; defaults to currently logged in user |
|
131 | + * @param bool $flush If set to true, will refresh the access list from the |
|
132 | + * database rather than using this function's cache. |
|
133 | + * |
|
134 | + * @return string A concatenated string of access collections suitable for using in an SQL IN clause |
|
135 | + * @access private |
|
136 | + */ |
|
137 | + public function getAccessList($user_guid = 0, $flush = false) { |
|
138 | + $access_array = $this->getAccessArray($user_guid, $flush); |
|
139 | + $access_ids = implode(',', $access_array); |
|
140 | + $list = "($access_ids)"; |
|
141 | + |
|
142 | + // for BC, populate the cache |
|
143 | + $hash = $user_guid . 'get_access_list'; |
|
144 | + $this->access_cache->add($hash, $list); |
|
145 | + |
|
146 | + return $list; |
|
147 | + } |
|
148 | + |
|
149 | + /** |
|
150 | + * Returns an array of access IDs a user is permitted to see. |
|
151 | + * |
|
152 | + * Can be overridden with the 'access:collections:read', 'user' plugin hook. |
|
153 | + * @warning A callback for that plugin hook needs to either not retrieve data |
|
154 | + * from the database that would use the access system (triggering the plugin again) |
|
155 | + * or ignore the second call. Otherwise, an infinite loop will be created. |
|
156 | + * |
|
157 | + * This returns a list of all the collection ids a user owns or belongs |
|
158 | + * to plus public and logged in access levels. If the user is an admin, it includes |
|
159 | + * the private access level. |
|
160 | + * |
|
161 | + * @internal this is only used in core for creating the SQL where clause when |
|
162 | + * retrieving content from the database. The friends access level is handled by |
|
163 | + * _elgg_get_access_where_sql(). |
|
164 | + * |
|
165 | + * @see get_write_access_array() for the access levels that a user can write to. |
|
166 | + * |
|
167 | + * @param int $user_guid User ID; defaults to currently logged in user |
|
168 | + * @param bool $flush If set to true, will refresh the access ids from the |
|
169 | + * database rather than using this function's cache. |
|
170 | + * |
|
171 | + * @return array An array of access collections ids |
|
172 | + */ |
|
173 | + public function getAccessArray($user_guid = 0, $flush = false) { |
|
174 | + $cache = $this->access_cache; |
|
175 | + |
|
176 | + if ($flush) { |
|
177 | + $cache->clear(); |
|
178 | + } |
|
179 | + |
|
180 | + if ($user_guid == 0) { |
|
181 | + $user_guid = $this->session->getLoggedInUserGuid(); |
|
182 | + } |
|
183 | + |
|
184 | + $user_guid = (int) $user_guid; |
|
185 | + |
|
186 | + $hash = $user_guid . 'get_access_array'; |
|
187 | + |
|
188 | + if ($cache[$hash]) { |
|
189 | + $access_array = $cache[$hash]; |
|
190 | + } else { |
|
191 | + // Public access is always visible |
|
192 | + $access_array = [ACCESS_PUBLIC]; |
|
193 | + |
|
194 | + // The following can only return sensible data for a known user. |
|
195 | + if ($user_guid) { |
|
196 | + $access_array[] = ACCESS_LOGGED_IN; |
|
197 | + |
|
198 | + // Get ACLs that user owns or is a member of |
|
199 | + $query = " |
|
200 | 200 | SELECT ac.id |
201 | 201 | FROM {$this->table} ac |
202 | 202 | WHERE ac.owner_guid = :user_guid |
@@ -206,690 +206,690 @@ discard block |
||
206 | 206 | AND user_guid = :user_guid) |
207 | 207 | "; |
208 | 208 | |
209 | - $collections = $this->db->getData($query, null, [ |
|
210 | - ':user_guid' => $user_guid, |
|
211 | - ]); |
|
212 | - |
|
213 | - if ($collections) { |
|
214 | - foreach ($collections as $collection) { |
|
215 | - $access_array[] = (int) $collection->id; |
|
216 | - } |
|
217 | - } |
|
218 | - |
|
219 | - $ignore_access = $this->capabilities->canBypassPermissionsCheck($user_guid); |
|
220 | - |
|
221 | - if ($ignore_access == true) { |
|
222 | - $access_array[] = ACCESS_PRIVATE; |
|
223 | - } |
|
224 | - } |
|
225 | - |
|
226 | - if ($this->init_complete) { |
|
227 | - $cache[$hash] = $access_array; |
|
228 | - } |
|
229 | - } |
|
230 | - |
|
231 | - $options = [ |
|
232 | - 'user_id' => $user_guid, |
|
233 | - ]; |
|
234 | - |
|
235 | - // see the warning in the docs for this function about infinite loop potential |
|
236 | - return $this->hooks->trigger('access:collections:read', 'user', $options, $access_array); |
|
237 | - } |
|
238 | - |
|
239 | - /** |
|
240 | - * Returns the SQL where clause for enforcing read access to data. |
|
241 | - * |
|
242 | - * Note that if this code is executed in privileged mode it will return (1=1). |
|
243 | - * |
|
244 | - * Otherwise it returns a where clause to retrieve the data that a user has |
|
245 | - * permission to read. |
|
246 | - * |
|
247 | - * Plugin authors can hook into the 'get_sql', 'access' plugin hook to modify, |
|
248 | - * remove, or add to the where clauses. The plugin hook will pass an array with the current |
|
249 | - * ors and ands to the function in the form: |
|
250 | - * array( |
|
251 | - * 'ors' => array(), |
|
252 | - * 'ands' => array() |
|
253 | - * ) |
|
254 | - * |
|
255 | - * The results will be combined into an SQL where clause in the form: |
|
256 | - * ((or1 OR or2 OR orN) AND (and1 AND and2 AND andN)) |
|
257 | - * |
|
258 | - * @param array $options Array in format: |
|
259 | - * |
|
260 | - * table_alias => STR Optional table alias. This is based on the select and join clauses. |
|
261 | - * Default is 'e'. |
|
262 | - * |
|
263 | - * user_guid => INT Optional GUID for the user that we are retrieving data for. |
|
264 | - * Defaults to the logged in user if null. |
|
265 | - * Passing 0 will build a query for a logged out user (even if there is a logged in user) |
|
266 | - * |
|
267 | - * use_enabled_clause => BOOL Optional. Should we append the enabled clause? The default |
|
268 | - * is set by access_show_hidden_entities(). |
|
269 | - * |
|
270 | - * access_column => STR Optional access column name. Default is 'access_id'. |
|
271 | - * |
|
272 | - * owner_guid_column => STR Optional owner_guid column. Default is 'owner_guid'. |
|
273 | - * |
|
274 | - * guid_column => STR Optional guid_column. Default is 'guid'. |
|
275 | - * |
|
276 | - * @return string |
|
277 | - * @access private |
|
278 | - */ |
|
279 | - public function getWhereSql(array $options = []) { |
|
280 | - |
|
281 | - $defaults = [ |
|
282 | - 'table_alias' => 'e', |
|
283 | - 'user_guid' => $this->session->getLoggedInUserGuid(), |
|
284 | - 'use_enabled_clause' => !access_get_show_hidden_status(), |
|
285 | - 'access_column' => 'access_id', |
|
286 | - 'owner_guid_column' => 'owner_guid', |
|
287 | - 'guid_column' => 'guid', |
|
288 | - ]; |
|
289 | - |
|
290 | - foreach ($options as $key => $value) { |
|
291 | - if (is_null($value)) { |
|
292 | - // remove null values so we don't loose defaults in array_merge |
|
293 | - unset($options[$key]); |
|
294 | - } |
|
295 | - } |
|
296 | - |
|
297 | - $options = array_merge($defaults, $options); |
|
298 | - |
|
299 | - // just in case someone passes a . at the end |
|
300 | - $options['table_alias'] = rtrim($options['table_alias'], '.'); |
|
301 | - |
|
302 | - foreach (['table_alias', 'access_column', 'owner_guid_column', 'guid_column'] as $key) { |
|
303 | - $options[$key] = sanitize_string($options[$key]); |
|
304 | - } |
|
305 | - $options['user_guid'] = sanitize_int($options['user_guid'], false); |
|
306 | - |
|
307 | - // only add dot if we have an alias or table name |
|
308 | - $table_alias = $options['table_alias'] ? $options['table_alias'] . '.' : ''; |
|
309 | - |
|
310 | - if (!isset($options['ignore_access'])) { |
|
311 | - $options['ignore_access'] = $this->capabilities->canBypassPermissionsCheck($options['user_guid']); |
|
312 | - } |
|
313 | - |
|
314 | - $clauses = [ |
|
315 | - 'ors' => [], |
|
316 | - 'ands' => [] |
|
317 | - ]; |
|
318 | - |
|
319 | - $prefix = $this->db->prefix; |
|
320 | - |
|
321 | - if ($options['ignore_access']) { |
|
322 | - $clauses['ors']['ignore_access'] = '1 = 1'; |
|
323 | - } else if ($options['user_guid']) { |
|
324 | - // include content of user's friends |
|
325 | - $clauses['ors']['friends_access'] = "$table_alias{$options['access_column']} = " . ACCESS_FRIENDS . " |
|
209 | + $collections = $this->db->getData($query, null, [ |
|
210 | + ':user_guid' => $user_guid, |
|
211 | + ]); |
|
212 | + |
|
213 | + if ($collections) { |
|
214 | + foreach ($collections as $collection) { |
|
215 | + $access_array[] = (int) $collection->id; |
|
216 | + } |
|
217 | + } |
|
218 | + |
|
219 | + $ignore_access = $this->capabilities->canBypassPermissionsCheck($user_guid); |
|
220 | + |
|
221 | + if ($ignore_access == true) { |
|
222 | + $access_array[] = ACCESS_PRIVATE; |
|
223 | + } |
|
224 | + } |
|
225 | + |
|
226 | + if ($this->init_complete) { |
|
227 | + $cache[$hash] = $access_array; |
|
228 | + } |
|
229 | + } |
|
230 | + |
|
231 | + $options = [ |
|
232 | + 'user_id' => $user_guid, |
|
233 | + ]; |
|
234 | + |
|
235 | + // see the warning in the docs for this function about infinite loop potential |
|
236 | + return $this->hooks->trigger('access:collections:read', 'user', $options, $access_array); |
|
237 | + } |
|
238 | + |
|
239 | + /** |
|
240 | + * Returns the SQL where clause for enforcing read access to data. |
|
241 | + * |
|
242 | + * Note that if this code is executed in privileged mode it will return (1=1). |
|
243 | + * |
|
244 | + * Otherwise it returns a where clause to retrieve the data that a user has |
|
245 | + * permission to read. |
|
246 | + * |
|
247 | + * Plugin authors can hook into the 'get_sql', 'access' plugin hook to modify, |
|
248 | + * remove, or add to the where clauses. The plugin hook will pass an array with the current |
|
249 | + * ors and ands to the function in the form: |
|
250 | + * array( |
|
251 | + * 'ors' => array(), |
|
252 | + * 'ands' => array() |
|
253 | + * ) |
|
254 | + * |
|
255 | + * The results will be combined into an SQL where clause in the form: |
|
256 | + * ((or1 OR or2 OR orN) AND (and1 AND and2 AND andN)) |
|
257 | + * |
|
258 | + * @param array $options Array in format: |
|
259 | + * |
|
260 | + * table_alias => STR Optional table alias. This is based on the select and join clauses. |
|
261 | + * Default is 'e'. |
|
262 | + * |
|
263 | + * user_guid => INT Optional GUID for the user that we are retrieving data for. |
|
264 | + * Defaults to the logged in user if null. |
|
265 | + * Passing 0 will build a query for a logged out user (even if there is a logged in user) |
|
266 | + * |
|
267 | + * use_enabled_clause => BOOL Optional. Should we append the enabled clause? The default |
|
268 | + * is set by access_show_hidden_entities(). |
|
269 | + * |
|
270 | + * access_column => STR Optional access column name. Default is 'access_id'. |
|
271 | + * |
|
272 | + * owner_guid_column => STR Optional owner_guid column. Default is 'owner_guid'. |
|
273 | + * |
|
274 | + * guid_column => STR Optional guid_column. Default is 'guid'. |
|
275 | + * |
|
276 | + * @return string |
|
277 | + * @access private |
|
278 | + */ |
|
279 | + public function getWhereSql(array $options = []) { |
|
280 | + |
|
281 | + $defaults = [ |
|
282 | + 'table_alias' => 'e', |
|
283 | + 'user_guid' => $this->session->getLoggedInUserGuid(), |
|
284 | + 'use_enabled_clause' => !access_get_show_hidden_status(), |
|
285 | + 'access_column' => 'access_id', |
|
286 | + 'owner_guid_column' => 'owner_guid', |
|
287 | + 'guid_column' => 'guid', |
|
288 | + ]; |
|
289 | + |
|
290 | + foreach ($options as $key => $value) { |
|
291 | + if (is_null($value)) { |
|
292 | + // remove null values so we don't loose defaults in array_merge |
|
293 | + unset($options[$key]); |
|
294 | + } |
|
295 | + } |
|
296 | + |
|
297 | + $options = array_merge($defaults, $options); |
|
298 | + |
|
299 | + // just in case someone passes a . at the end |
|
300 | + $options['table_alias'] = rtrim($options['table_alias'], '.'); |
|
301 | + |
|
302 | + foreach (['table_alias', 'access_column', 'owner_guid_column', 'guid_column'] as $key) { |
|
303 | + $options[$key] = sanitize_string($options[$key]); |
|
304 | + } |
|
305 | + $options['user_guid'] = sanitize_int($options['user_guid'], false); |
|
306 | + |
|
307 | + // only add dot if we have an alias or table name |
|
308 | + $table_alias = $options['table_alias'] ? $options['table_alias'] . '.' : ''; |
|
309 | + |
|
310 | + if (!isset($options['ignore_access'])) { |
|
311 | + $options['ignore_access'] = $this->capabilities->canBypassPermissionsCheck($options['user_guid']); |
|
312 | + } |
|
313 | + |
|
314 | + $clauses = [ |
|
315 | + 'ors' => [], |
|
316 | + 'ands' => [] |
|
317 | + ]; |
|
318 | + |
|
319 | + $prefix = $this->db->prefix; |
|
320 | + |
|
321 | + if ($options['ignore_access']) { |
|
322 | + $clauses['ors']['ignore_access'] = '1 = 1'; |
|
323 | + } else if ($options['user_guid']) { |
|
324 | + // include content of user's friends |
|
325 | + $clauses['ors']['friends_access'] = "$table_alias{$options['access_column']} = " . ACCESS_FRIENDS . " |
|
326 | 326 | AND $table_alias{$options['owner_guid_column']} IN ( |
327 | 327 | SELECT guid_one FROM {$prefix}entity_relationships |
328 | 328 | WHERE relationship = 'friend' AND guid_two = {$options['user_guid']} |
329 | 329 | )"; |
330 | 330 | |
331 | - // include user's content |
|
332 | - $clauses['ors']['owner_access'] = "$table_alias{$options['owner_guid_column']} = {$options['user_guid']}"; |
|
333 | - } |
|
334 | - |
|
335 | - // include standard accesses (public, logged in, access collections) |
|
336 | - if (!$options['ignore_access']) { |
|
337 | - $access_list = $this->getAccessList($options['user_guid']); |
|
338 | - $clauses['ors']['acl_access'] = "$table_alias{$options['access_column']} IN {$access_list}"; |
|
339 | - } |
|
340 | - |
|
341 | - if ($options['use_enabled_clause']) { |
|
342 | - $clauses['ands']['use_enabled'] = "{$table_alias}enabled = 'yes'"; |
|
343 | - } |
|
344 | - |
|
345 | - $clauses = $this->hooks->trigger('get_sql', 'access', $options, $clauses); |
|
346 | - |
|
347 | - $clauses_str = ''; |
|
348 | - if (is_array($clauses['ors']) && $clauses['ors']) { |
|
349 | - $clauses_str = '(' . implode(' OR ', $clauses['ors']) . ')'; |
|
350 | - } |
|
351 | - |
|
352 | - if (is_array($clauses['ands']) && $clauses['ands']) { |
|
353 | - if ($clauses_str) { |
|
354 | - $clauses_str .= ' AND '; |
|
355 | - } |
|
356 | - $clauses_str .= '(' . implode(' AND ', $clauses['ands']) . ')'; |
|
357 | - } |
|
358 | - |
|
359 | - if (empty($clauses_str)) { |
|
360 | - $clauses_str = '1 = 1'; |
|
361 | - } |
|
331 | + // include user's content |
|
332 | + $clauses['ors']['owner_access'] = "$table_alias{$options['owner_guid_column']} = {$options['user_guid']}"; |
|
333 | + } |
|
334 | + |
|
335 | + // include standard accesses (public, logged in, access collections) |
|
336 | + if (!$options['ignore_access']) { |
|
337 | + $access_list = $this->getAccessList($options['user_guid']); |
|
338 | + $clauses['ors']['acl_access'] = "$table_alias{$options['access_column']} IN {$access_list}"; |
|
339 | + } |
|
340 | + |
|
341 | + if ($options['use_enabled_clause']) { |
|
342 | + $clauses['ands']['use_enabled'] = "{$table_alias}enabled = 'yes'"; |
|
343 | + } |
|
344 | + |
|
345 | + $clauses = $this->hooks->trigger('get_sql', 'access', $options, $clauses); |
|
346 | + |
|
347 | + $clauses_str = ''; |
|
348 | + if (is_array($clauses['ors']) && $clauses['ors']) { |
|
349 | + $clauses_str = '(' . implode(' OR ', $clauses['ors']) . ')'; |
|
350 | + } |
|
351 | + |
|
352 | + if (is_array($clauses['ands']) && $clauses['ands']) { |
|
353 | + if ($clauses_str) { |
|
354 | + $clauses_str .= ' AND '; |
|
355 | + } |
|
356 | + $clauses_str .= '(' . implode(' AND ', $clauses['ands']) . ')'; |
|
357 | + } |
|
358 | + |
|
359 | + if (empty($clauses_str)) { |
|
360 | + $clauses_str = '1 = 1'; |
|
361 | + } |
|
362 | 362 | |
363 | - return "($clauses_str)"; |
|
364 | - } |
|
365 | - |
|
366 | - /** |
|
367 | - * Can a user access an entity. |
|
368 | - * |
|
369 | - * @warning If a logged in user doesn't have access to an entity, the |
|
370 | - * core engine will not load that entity. |
|
371 | - * |
|
372 | - * @tip This is mostly useful for checking if a user other than the logged in |
|
373 | - * user has access to an entity that is currently loaded. |
|
374 | - * |
|
375 | - * @todo This function would be much more useful if we could pass the guid of the |
|
376 | - * entity to test access for. We need to be able to tell whether the entity exists |
|
377 | - * and whether the user has access to the entity. |
|
378 | - * |
|
379 | - * @param ElggEntity $entity The entity to check access for. |
|
380 | - * @param ElggUser $user Optionally user to check access for. Defaults to |
|
381 | - * logged in user (which is a useless default). |
|
382 | - * |
|
383 | - * @return bool |
|
384 | - */ |
|
385 | - public function hasAccessToEntity($entity, $user = null) { |
|
386 | - if (!$entity instanceof \ElggEntity) { |
|
387 | - return false; |
|
388 | - } |
|
389 | - |
|
390 | - if ($entity->access_id == ACCESS_PUBLIC) { |
|
391 | - // Public entities are always accessible |
|
392 | - return true; |
|
393 | - } |
|
394 | - |
|
395 | - $user_guid = isset($user) ? (int) $user->guid : elgg_get_logged_in_user_guid(); |
|
396 | - |
|
397 | - if ($user_guid && $user_guid == $entity->owner_guid) { |
|
398 | - // Owners have access to their own content |
|
399 | - return true; |
|
400 | - } |
|
401 | - |
|
402 | - if ($user_guid && $entity->access_id == ACCESS_LOGGED_IN) { |
|
403 | - // Existing users have access to entities with logged in access |
|
404 | - return true; |
|
405 | - } |
|
406 | - |
|
407 | - // See #7159. Must not allow ignore access to affect query |
|
408 | - $ia = elgg_set_ignore_access(false); |
|
409 | - |
|
410 | - $row = $this->entities->getRow($entity->guid, $user_guid); |
|
411 | - |
|
412 | - elgg_set_ignore_access($ia); |
|
413 | - |
|
414 | - return !empty($row); |
|
415 | - } |
|
416 | - |
|
417 | - /** |
|
418 | - * Returns an array of access permissions that the user is allowed to save content with. |
|
419 | - * Permissions returned are of the form (id => 'name'). |
|
420 | - * |
|
421 | - * Example return value in English: |
|
422 | - * array( |
|
423 | - * 0 => 'Private', |
|
424 | - * -2 => 'Friends', |
|
425 | - * 1 => 'Logged in users', |
|
426 | - * 2 => 'Public', |
|
427 | - * 34 => 'My favorite friends', |
|
428 | - * ); |
|
429 | - * |
|
430 | - * Plugin hook of 'access:collections:write', 'user' |
|
431 | - * |
|
432 | - * @warning this only returns access collections that the user owns plus the |
|
433 | - * standard access levels. It does not return access collections that the user |
|
434 | - * belongs to such as the access collection for a group. |
|
435 | - * |
|
436 | - * @param int $user_guid The user's GUID. |
|
437 | - * @param bool $flush If this is set to true, this will ignore a cached access array |
|
438 | - * @param array $input_params Some parameters passed into an input/access view |
|
439 | - * |
|
440 | - * @return array List of access permissions |
|
441 | - */ |
|
442 | - public function getWriteAccessArray($user_guid = 0, $flush = false, array $input_params = []) { |
|
443 | - $cache = $this->access_cache; |
|
444 | - |
|
445 | - if ($flush) { |
|
446 | - $cache->clear(); |
|
447 | - } |
|
448 | - |
|
449 | - if ($user_guid == 0) { |
|
450 | - $user_guid = $this->session->getLoggedInUserGuid(); |
|
451 | - } |
|
452 | - |
|
453 | - $user_guid = (int) $user_guid; |
|
454 | - |
|
455 | - $hash = $user_guid . 'get_write_access_array'; |
|
456 | - |
|
457 | - if ($cache[$hash]) { |
|
458 | - $access_array = $cache[$hash]; |
|
459 | - } else { |
|
460 | - // @todo is there such a thing as public write access? |
|
461 | - $access_array = [ |
|
462 | - ACCESS_PRIVATE => $this->getReadableAccessLevel(ACCESS_PRIVATE), |
|
463 | - ACCESS_LOGGED_IN => $this->getReadableAccessLevel(ACCESS_LOGGED_IN), |
|
464 | - ACCESS_PUBLIC => $this->getReadableAccessLevel(ACCESS_PUBLIC) |
|
465 | - ]; |
|
466 | - |
|
467 | - $collections = $this->getEntityCollections($user_guid); |
|
468 | - if ($collections) { |
|
469 | - foreach ($collections as $collection) { |
|
470 | - $access_array[$collection->id] = $collection->name; |
|
471 | - } |
|
472 | - } |
|
473 | - |
|
474 | - if ($this->init_complete) { |
|
475 | - $cache[$hash] = $access_array; |
|
476 | - } |
|
477 | - } |
|
478 | - |
|
479 | - $options = [ |
|
480 | - 'user_id' => $user_guid, |
|
481 | - 'input_params' => $input_params, |
|
482 | - ]; |
|
483 | - return $this->hooks->trigger('access:collections:write', 'user', $options, $access_array); |
|
484 | - } |
|
485 | - |
|
486 | - /** |
|
487 | - * Can the user change this access collection? |
|
488 | - * |
|
489 | - * Use the plugin hook of 'access:collections:write', 'user' to change this. |
|
490 | - * @see get_write_access_array() for details on the hook. |
|
491 | - * |
|
492 | - * Respects access control disabling for admin users and {@link elgg_set_ignore_access()} |
|
493 | - * |
|
494 | - * @see get_write_access_array() |
|
495 | - * |
|
496 | - * @param int $collection_id The collection id |
|
497 | - * @param mixed $user_guid The user GUID to check for. Defaults to logged in user. |
|
498 | - * @return bool |
|
499 | - */ |
|
500 | - public function canEdit($collection_id, $user_guid = null) { |
|
501 | - try { |
|
502 | - $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
503 | - } catch (UserFetchFailureException $e) { |
|
504 | - return false; |
|
505 | - } |
|
506 | - |
|
507 | - $collection = $this->get($collection_id); |
|
508 | - |
|
509 | - if (!$user || !$collection) { |
|
510 | - return false; |
|
511 | - } |
|
512 | - |
|
513 | - if ($this->capabilities->canBypassPermissionsCheck($user->guid)) { |
|
514 | - return true; |
|
515 | - } |
|
516 | - |
|
517 | - $write_access = $this->getWriteAccessArray($user->guid, true); |
|
518 | - return array_key_exists($collection_id, $write_access); |
|
519 | - } |
|
520 | - |
|
521 | - /** |
|
522 | - * Creates a new access collection. |
|
523 | - * |
|
524 | - * Access colletions allow plugins and users to create granular access |
|
525 | - * for entities. |
|
526 | - * |
|
527 | - * Triggers plugin hook 'access:collections:addcollection', 'collection' |
|
528 | - * |
|
529 | - * @internal Access collections are stored in the access_collections table. |
|
530 | - * Memberships to collections are in access_collections_membership. |
|
531 | - * |
|
532 | - * @param string $name The name of the collection. |
|
533 | - * @param int $owner_guid The GUID of the owner (default: currently logged in user). |
|
534 | - * |
|
535 | - * @return int|false The collection ID if successful and false on failure. |
|
536 | - */ |
|
537 | - public function create($name, $owner_guid = 0) { |
|
538 | - $name = trim($name); |
|
539 | - if (empty($name)) { |
|
540 | - return false; |
|
541 | - } |
|
542 | - |
|
543 | - if ($owner_guid == 0) { |
|
544 | - $owner_guid = $this->session->getLoggedInUserGuid(); |
|
545 | - } |
|
546 | - |
|
547 | - $query = " |
|
363 | + return "($clauses_str)"; |
|
364 | + } |
|
365 | + |
|
366 | + /** |
|
367 | + * Can a user access an entity. |
|
368 | + * |
|
369 | + * @warning If a logged in user doesn't have access to an entity, the |
|
370 | + * core engine will not load that entity. |
|
371 | + * |
|
372 | + * @tip This is mostly useful for checking if a user other than the logged in |
|
373 | + * user has access to an entity that is currently loaded. |
|
374 | + * |
|
375 | + * @todo This function would be much more useful if we could pass the guid of the |
|
376 | + * entity to test access for. We need to be able to tell whether the entity exists |
|
377 | + * and whether the user has access to the entity. |
|
378 | + * |
|
379 | + * @param ElggEntity $entity The entity to check access for. |
|
380 | + * @param ElggUser $user Optionally user to check access for. Defaults to |
|
381 | + * logged in user (which is a useless default). |
|
382 | + * |
|
383 | + * @return bool |
|
384 | + */ |
|
385 | + public function hasAccessToEntity($entity, $user = null) { |
|
386 | + if (!$entity instanceof \ElggEntity) { |
|
387 | + return false; |
|
388 | + } |
|
389 | + |
|
390 | + if ($entity->access_id == ACCESS_PUBLIC) { |
|
391 | + // Public entities are always accessible |
|
392 | + return true; |
|
393 | + } |
|
394 | + |
|
395 | + $user_guid = isset($user) ? (int) $user->guid : elgg_get_logged_in_user_guid(); |
|
396 | + |
|
397 | + if ($user_guid && $user_guid == $entity->owner_guid) { |
|
398 | + // Owners have access to their own content |
|
399 | + return true; |
|
400 | + } |
|
401 | + |
|
402 | + if ($user_guid && $entity->access_id == ACCESS_LOGGED_IN) { |
|
403 | + // Existing users have access to entities with logged in access |
|
404 | + return true; |
|
405 | + } |
|
406 | + |
|
407 | + // See #7159. Must not allow ignore access to affect query |
|
408 | + $ia = elgg_set_ignore_access(false); |
|
409 | + |
|
410 | + $row = $this->entities->getRow($entity->guid, $user_guid); |
|
411 | + |
|
412 | + elgg_set_ignore_access($ia); |
|
413 | + |
|
414 | + return !empty($row); |
|
415 | + } |
|
416 | + |
|
417 | + /** |
|
418 | + * Returns an array of access permissions that the user is allowed to save content with. |
|
419 | + * Permissions returned are of the form (id => 'name'). |
|
420 | + * |
|
421 | + * Example return value in English: |
|
422 | + * array( |
|
423 | + * 0 => 'Private', |
|
424 | + * -2 => 'Friends', |
|
425 | + * 1 => 'Logged in users', |
|
426 | + * 2 => 'Public', |
|
427 | + * 34 => 'My favorite friends', |
|
428 | + * ); |
|
429 | + * |
|
430 | + * Plugin hook of 'access:collections:write', 'user' |
|
431 | + * |
|
432 | + * @warning this only returns access collections that the user owns plus the |
|
433 | + * standard access levels. It does not return access collections that the user |
|
434 | + * belongs to such as the access collection for a group. |
|
435 | + * |
|
436 | + * @param int $user_guid The user's GUID. |
|
437 | + * @param bool $flush If this is set to true, this will ignore a cached access array |
|
438 | + * @param array $input_params Some parameters passed into an input/access view |
|
439 | + * |
|
440 | + * @return array List of access permissions |
|
441 | + */ |
|
442 | + public function getWriteAccessArray($user_guid = 0, $flush = false, array $input_params = []) { |
|
443 | + $cache = $this->access_cache; |
|
444 | + |
|
445 | + if ($flush) { |
|
446 | + $cache->clear(); |
|
447 | + } |
|
448 | + |
|
449 | + if ($user_guid == 0) { |
|
450 | + $user_guid = $this->session->getLoggedInUserGuid(); |
|
451 | + } |
|
452 | + |
|
453 | + $user_guid = (int) $user_guid; |
|
454 | + |
|
455 | + $hash = $user_guid . 'get_write_access_array'; |
|
456 | + |
|
457 | + if ($cache[$hash]) { |
|
458 | + $access_array = $cache[$hash]; |
|
459 | + } else { |
|
460 | + // @todo is there such a thing as public write access? |
|
461 | + $access_array = [ |
|
462 | + ACCESS_PRIVATE => $this->getReadableAccessLevel(ACCESS_PRIVATE), |
|
463 | + ACCESS_LOGGED_IN => $this->getReadableAccessLevel(ACCESS_LOGGED_IN), |
|
464 | + ACCESS_PUBLIC => $this->getReadableAccessLevel(ACCESS_PUBLIC) |
|
465 | + ]; |
|
466 | + |
|
467 | + $collections = $this->getEntityCollections($user_guid); |
|
468 | + if ($collections) { |
|
469 | + foreach ($collections as $collection) { |
|
470 | + $access_array[$collection->id] = $collection->name; |
|
471 | + } |
|
472 | + } |
|
473 | + |
|
474 | + if ($this->init_complete) { |
|
475 | + $cache[$hash] = $access_array; |
|
476 | + } |
|
477 | + } |
|
478 | + |
|
479 | + $options = [ |
|
480 | + 'user_id' => $user_guid, |
|
481 | + 'input_params' => $input_params, |
|
482 | + ]; |
|
483 | + return $this->hooks->trigger('access:collections:write', 'user', $options, $access_array); |
|
484 | + } |
|
485 | + |
|
486 | + /** |
|
487 | + * Can the user change this access collection? |
|
488 | + * |
|
489 | + * Use the plugin hook of 'access:collections:write', 'user' to change this. |
|
490 | + * @see get_write_access_array() for details on the hook. |
|
491 | + * |
|
492 | + * Respects access control disabling for admin users and {@link elgg_set_ignore_access()} |
|
493 | + * |
|
494 | + * @see get_write_access_array() |
|
495 | + * |
|
496 | + * @param int $collection_id The collection id |
|
497 | + * @param mixed $user_guid The user GUID to check for. Defaults to logged in user. |
|
498 | + * @return bool |
|
499 | + */ |
|
500 | + public function canEdit($collection_id, $user_guid = null) { |
|
501 | + try { |
|
502 | + $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
503 | + } catch (UserFetchFailureException $e) { |
|
504 | + return false; |
|
505 | + } |
|
506 | + |
|
507 | + $collection = $this->get($collection_id); |
|
508 | + |
|
509 | + if (!$user || !$collection) { |
|
510 | + return false; |
|
511 | + } |
|
512 | + |
|
513 | + if ($this->capabilities->canBypassPermissionsCheck($user->guid)) { |
|
514 | + return true; |
|
515 | + } |
|
516 | + |
|
517 | + $write_access = $this->getWriteAccessArray($user->guid, true); |
|
518 | + return array_key_exists($collection_id, $write_access); |
|
519 | + } |
|
520 | + |
|
521 | + /** |
|
522 | + * Creates a new access collection. |
|
523 | + * |
|
524 | + * Access colletions allow plugins and users to create granular access |
|
525 | + * for entities. |
|
526 | + * |
|
527 | + * Triggers plugin hook 'access:collections:addcollection', 'collection' |
|
528 | + * |
|
529 | + * @internal Access collections are stored in the access_collections table. |
|
530 | + * Memberships to collections are in access_collections_membership. |
|
531 | + * |
|
532 | + * @param string $name The name of the collection. |
|
533 | + * @param int $owner_guid The GUID of the owner (default: currently logged in user). |
|
534 | + * |
|
535 | + * @return int|false The collection ID if successful and false on failure. |
|
536 | + */ |
|
537 | + public function create($name, $owner_guid = 0) { |
|
538 | + $name = trim($name); |
|
539 | + if (empty($name)) { |
|
540 | + return false; |
|
541 | + } |
|
542 | + |
|
543 | + if ($owner_guid == 0) { |
|
544 | + $owner_guid = $this->session->getLoggedInUserGuid(); |
|
545 | + } |
|
546 | + |
|
547 | + $query = " |
|
548 | 548 | INSERT INTO {$this->table} |
549 | 549 | SET name = :name, |
550 | 550 | owner_guid = :owner_guid |
551 | 551 | "; |
552 | 552 | |
553 | - $params = [ |
|
554 | - ':name' => $name, |
|
555 | - ':owner_guid' => (int) $owner_guid, |
|
556 | - ]; |
|
557 | - |
|
558 | - $id = $this->db->insertData($query, $params); |
|
559 | - if (!$id) { |
|
560 | - return false; |
|
561 | - } |
|
562 | - |
|
563 | - $this->access_cache->clear(); |
|
564 | - |
|
565 | - $hook_params = [ |
|
566 | - 'collection_id' => $id, |
|
567 | - 'name' => $name, |
|
568 | - 'owner_guid' => $owner_guid, |
|
569 | - ]; |
|
570 | - |
|
571 | - if (!$this->hooks->trigger('access:collections:addcollection', 'collection', $hook_params, true)) { |
|
572 | - $this->delete($id); |
|
573 | - return false; |
|
574 | - } |
|
575 | - |
|
576 | - return $id; |
|
577 | - } |
|
578 | - |
|
579 | - /** |
|
580 | - * Renames an access collection |
|
581 | - * |
|
582 | - * @param int $collection_id ID of the collection |
|
583 | - * @param string $name The name of the collection |
|
584 | - * @return bool |
|
585 | - */ |
|
586 | - public function rename($collection_id, $name) { |
|
587 | - |
|
588 | - $query = " |
|
553 | + $params = [ |
|
554 | + ':name' => $name, |
|
555 | + ':owner_guid' => (int) $owner_guid, |
|
556 | + ]; |
|
557 | + |
|
558 | + $id = $this->db->insertData($query, $params); |
|
559 | + if (!$id) { |
|
560 | + return false; |
|
561 | + } |
|
562 | + |
|
563 | + $this->access_cache->clear(); |
|
564 | + |
|
565 | + $hook_params = [ |
|
566 | + 'collection_id' => $id, |
|
567 | + 'name' => $name, |
|
568 | + 'owner_guid' => $owner_guid, |
|
569 | + ]; |
|
570 | + |
|
571 | + if (!$this->hooks->trigger('access:collections:addcollection', 'collection', $hook_params, true)) { |
|
572 | + $this->delete($id); |
|
573 | + return false; |
|
574 | + } |
|
575 | + |
|
576 | + return $id; |
|
577 | + } |
|
578 | + |
|
579 | + /** |
|
580 | + * Renames an access collection |
|
581 | + * |
|
582 | + * @param int $collection_id ID of the collection |
|
583 | + * @param string $name The name of the collection |
|
584 | + * @return bool |
|
585 | + */ |
|
586 | + public function rename($collection_id, $name) { |
|
587 | + |
|
588 | + $query = " |
|
589 | 589 | UPDATE {$this->table} |
590 | 590 | SET name = :name |
591 | 591 | WHERE id = :id |
592 | 592 | "; |
593 | 593 | |
594 | - $params = [ |
|
595 | - ':name' => $name, |
|
596 | - ':id' => (int) $collection_id, |
|
597 | - ]; |
|
598 | - |
|
599 | - if ($this->db->insertData($query, $params)) { |
|
600 | - $this->access_cache->clear(); |
|
601 | - return (int) $collection_id; |
|
602 | - } |
|
603 | - |
|
604 | - return false; |
|
605 | - } |
|
606 | - |
|
607 | - |
|
608 | - /** |
|
609 | - * Updates the membership in an access collection. |
|
610 | - * |
|
611 | - * @warning Expects a full list of all members that should |
|
612 | - * be part of the access collection |
|
613 | - * |
|
614 | - * @note This will run all hooks associated with adding or removing |
|
615 | - * members to access collections. |
|
616 | - * |
|
617 | - * @param int $collection_id ID of the collection. |
|
618 | - * @param array $new_members Array of member entities or GUIDs |
|
619 | - * @return bool |
|
620 | - */ |
|
621 | - public function update($collection_id, array $new_members = []) { |
|
622 | - $acl = $this->get($collection_id); |
|
623 | - |
|
624 | - if (!$acl) { |
|
625 | - return false; |
|
626 | - } |
|
594 | + $params = [ |
|
595 | + ':name' => $name, |
|
596 | + ':id' => (int) $collection_id, |
|
597 | + ]; |
|
598 | + |
|
599 | + if ($this->db->insertData($query, $params)) { |
|
600 | + $this->access_cache->clear(); |
|
601 | + return (int) $collection_id; |
|
602 | + } |
|
603 | + |
|
604 | + return false; |
|
605 | + } |
|
606 | + |
|
607 | + |
|
608 | + /** |
|
609 | + * Updates the membership in an access collection. |
|
610 | + * |
|
611 | + * @warning Expects a full list of all members that should |
|
612 | + * be part of the access collection |
|
613 | + * |
|
614 | + * @note This will run all hooks associated with adding or removing |
|
615 | + * members to access collections. |
|
616 | + * |
|
617 | + * @param int $collection_id ID of the collection. |
|
618 | + * @param array $new_members Array of member entities or GUIDs |
|
619 | + * @return bool |
|
620 | + */ |
|
621 | + public function update($collection_id, array $new_members = []) { |
|
622 | + $acl = $this->get($collection_id); |
|
623 | + |
|
624 | + if (!$acl) { |
|
625 | + return false; |
|
626 | + } |
|
627 | 627 | |
628 | - $to_guid = function($elem) { |
|
629 | - if (empty($elem)) { |
|
630 | - return 0; |
|
631 | - } |
|
632 | - if (is_object($elem)) { |
|
633 | - return (int) $elem->guid; |
|
634 | - } |
|
635 | - return (int) $elem; |
|
636 | - }; |
|
628 | + $to_guid = function($elem) { |
|
629 | + if (empty($elem)) { |
|
630 | + return 0; |
|
631 | + } |
|
632 | + if (is_object($elem)) { |
|
633 | + return (int) $elem->guid; |
|
634 | + } |
|
635 | + return (int) $elem; |
|
636 | + }; |
|
637 | 637 | |
638 | - $current_members = []; |
|
639 | - $new_members = array_map($to_guid, $new_members); |
|
638 | + $current_members = []; |
|
639 | + $new_members = array_map($to_guid, $new_members); |
|
640 | 640 | |
641 | - $current_members_batch = $this->getMembers($collection_id, [ |
|
642 | - 'batch' => true, |
|
643 | - 'limit' => 0, |
|
644 | - 'callback' => false, |
|
645 | - ]); |
|
641 | + $current_members_batch = $this->getMembers($collection_id, [ |
|
642 | + 'batch' => true, |
|
643 | + 'limit' => 0, |
|
644 | + 'callback' => false, |
|
645 | + ]); |
|
646 | 646 | |
647 | - foreach ($current_members_batch as $row) { |
|
648 | - $current_members[] = $to_guid($row); |
|
649 | - } |
|
647 | + foreach ($current_members_batch as $row) { |
|
648 | + $current_members[] = $to_guid($row); |
|
649 | + } |
|
650 | 650 | |
651 | - $remove_members = array_diff($current_members, $new_members); |
|
652 | - $add_members = array_diff($new_members, $current_members); |
|
651 | + $remove_members = array_diff($current_members, $new_members); |
|
652 | + $add_members = array_diff($new_members, $current_members); |
|
653 | 653 | |
654 | - $result = true; |
|
654 | + $result = true; |
|
655 | 655 | |
656 | - foreach ($add_members as $guid) { |
|
657 | - $result = $result && $this->addUser($guid, $collection_id); |
|
658 | - } |
|
656 | + foreach ($add_members as $guid) { |
|
657 | + $result = $result && $this->addUser($guid, $collection_id); |
|
658 | + } |
|
659 | 659 | |
660 | - foreach ($remove_members as $guid) { |
|
661 | - $result = $result && $this->removeUser($guid, $collection_id); |
|
662 | - } |
|
660 | + foreach ($remove_members as $guid) { |
|
661 | + $result = $result && $this->removeUser($guid, $collection_id); |
|
662 | + } |
|
663 | 663 | |
664 | - $this->access_cache->clear(); |
|
664 | + $this->access_cache->clear(); |
|
665 | 665 | |
666 | - return $result; |
|
667 | - } |
|
666 | + return $result; |
|
667 | + } |
|
668 | 668 | |
669 | - /** |
|
670 | - * Deletes a collection and its membership information |
|
671 | - * |
|
672 | - * @param int $collection_id ID of the collection |
|
673 | - * @return bool |
|
674 | - */ |
|
675 | - public function delete($collection_id) { |
|
676 | - $collection_id = (int) $collection_id; |
|
669 | + /** |
|
670 | + * Deletes a collection and its membership information |
|
671 | + * |
|
672 | + * @param int $collection_id ID of the collection |
|
673 | + * @return bool |
|
674 | + */ |
|
675 | + public function delete($collection_id) { |
|
676 | + $collection_id = (int) $collection_id; |
|
677 | 677 | |
678 | - $params = [ |
|
679 | - 'collection_id' => $collection_id, |
|
680 | - ]; |
|
678 | + $params = [ |
|
679 | + 'collection_id' => $collection_id, |
|
680 | + ]; |
|
681 | 681 | |
682 | - if (!$this->hooks->trigger('access:collections:deletecollection', 'collection', $params, true)) { |
|
683 | - return false; |
|
684 | - } |
|
682 | + if (!$this->hooks->trigger('access:collections:deletecollection', 'collection', $params, true)) { |
|
683 | + return false; |
|
684 | + } |
|
685 | 685 | |
686 | - // Deleting membership doesn't affect result of deleting ACL. |
|
687 | - $query = " |
|
686 | + // Deleting membership doesn't affect result of deleting ACL. |
|
687 | + $query = " |
|
688 | 688 | DELETE FROM {$this->membership_table} |
689 | 689 | WHERE access_collection_id = :access_collection_id |
690 | 690 | "; |
691 | - $this->db->deleteData($query, [ |
|
692 | - ':access_collection_id' => $collection_id, |
|
693 | - ]); |
|
691 | + $this->db->deleteData($query, [ |
|
692 | + ':access_collection_id' => $collection_id, |
|
693 | + ]); |
|
694 | 694 | |
695 | - $query = " |
|
695 | + $query = " |
|
696 | 696 | DELETE FROM {$this->table} |
697 | 697 | WHERE id = :id |
698 | 698 | "; |
699 | - $result = $this->db->deleteData($query, [ |
|
700 | - ':id' => $collection_id, |
|
701 | - ]); |
|
699 | + $result = $this->db->deleteData($query, [ |
|
700 | + ':id' => $collection_id, |
|
701 | + ]); |
|
702 | 702 | |
703 | - $this->access_cache->clear(); |
|
703 | + $this->access_cache->clear(); |
|
704 | 704 | |
705 | - return (bool) $result; |
|
706 | - } |
|
707 | - |
|
708 | - /** |
|
709 | - * Transforms a database row to an instance of ElggAccessCollection |
|
710 | - * |
|
711 | - * @param \stdClass $row Database row |
|
712 | - * @return \ElggAccessCollection |
|
713 | - */ |
|
714 | - public function rowToElggAccessCollection(\stdClass $row) { |
|
715 | - return new \ElggAccessCollection($row); |
|
716 | - } |
|
717 | - |
|
718 | - /** |
|
719 | - * Get a specified access collection |
|
720 | - * |
|
721 | - * @note This doesn't return the members of an access collection, |
|
722 | - * just the database row of the actual collection. |
|
723 | - * |
|
724 | - * @see get_members_of_access_collection() |
|
725 | - * |
|
726 | - * @param int $collection_id The collection ID |
|
727 | - * @return \ElggAccessCollection|false |
|
728 | - */ |
|
729 | - public function get($collection_id) { |
|
730 | - |
|
731 | - $callback = [$this, 'rowToElggAccessCollection']; |
|
732 | - |
|
733 | - $query = " |
|
705 | + return (bool) $result; |
|
706 | + } |
|
707 | + |
|
708 | + /** |
|
709 | + * Transforms a database row to an instance of ElggAccessCollection |
|
710 | + * |
|
711 | + * @param \stdClass $row Database row |
|
712 | + * @return \ElggAccessCollection |
|
713 | + */ |
|
714 | + public function rowToElggAccessCollection(\stdClass $row) { |
|
715 | + return new \ElggAccessCollection($row); |
|
716 | + } |
|
717 | + |
|
718 | + /** |
|
719 | + * Get a specified access collection |
|
720 | + * |
|
721 | + * @note This doesn't return the members of an access collection, |
|
722 | + * just the database row of the actual collection. |
|
723 | + * |
|
724 | + * @see get_members_of_access_collection() |
|
725 | + * |
|
726 | + * @param int $collection_id The collection ID |
|
727 | + * @return \ElggAccessCollection|false |
|
728 | + */ |
|
729 | + public function get($collection_id) { |
|
730 | + |
|
731 | + $callback = [$this, 'rowToElggAccessCollection']; |
|
732 | + |
|
733 | + $query = " |
|
734 | 734 | SELECT * FROM {$this->table} |
735 | 735 | WHERE id = :id |
736 | 736 | "; |
737 | 737 | |
738 | - return $this->db->getDataRow($query, $callback, [ |
|
739 | - ':id' => (int) $collection_id, |
|
740 | - ]); |
|
741 | - } |
|
742 | - |
|
743 | - /** |
|
744 | - * Check if user is already in the collection |
|
745 | - * |
|
746 | - * @param int $user_guid GUID of the user |
|
747 | - * @param int $collection_id ID of the collection |
|
748 | - * @return bool |
|
749 | - */ |
|
750 | - public function hasUser($user_guid, $collection_id) { |
|
751 | - $options = [ |
|
752 | - 'guids' => (int) $user_guid, |
|
753 | - 'count' => true, |
|
754 | - ]; |
|
755 | - return (bool) $this->getMembers($collection_id, $options); |
|
756 | - } |
|
757 | - |
|
758 | - /** |
|
759 | - * Adds a user to an access collection. |
|
760 | - * |
|
761 | - * Triggers the 'access:collections:add_user', 'collection' plugin hook. |
|
762 | - * |
|
763 | - * @param int $user_guid GUID of the user to add |
|
764 | - * @param int $collection_id ID of the collection to add them to |
|
765 | - * @return bool |
|
766 | - */ |
|
767 | - public function addUser($user_guid, $collection_id) { |
|
768 | - |
|
769 | - $collection = $this->get($collection_id); |
|
770 | - |
|
771 | - if (!$collection) { |
|
772 | - return false; |
|
773 | - } |
|
774 | - |
|
775 | - if (!$this->entities->exists($user_guid)) { |
|
776 | - return false; |
|
777 | - } |
|
778 | - |
|
779 | - $hook_params = [ |
|
780 | - 'collection_id' => $collection->id, |
|
781 | - 'user_guid' => (int) $user_guid |
|
782 | - ]; |
|
783 | - |
|
784 | - $result = $this->hooks->trigger('access:collections:add_user', 'collection', $hook_params, true); |
|
785 | - if ($result == false) { |
|
786 | - return false; |
|
787 | - } |
|
788 | - |
|
789 | - // if someone tries to insert the same data twice, we do a no-op on duplicate key |
|
790 | - $query = " |
|
738 | + return $this->db->getDataRow($query, $callback, [ |
|
739 | + ':id' => (int) $collection_id, |
|
740 | + ]); |
|
741 | + } |
|
742 | + |
|
743 | + /** |
|
744 | + * Check if user is already in the collection |
|
745 | + * |
|
746 | + * @param int $user_guid GUID of the user |
|
747 | + * @param int $collection_id ID of the collection |
|
748 | + * @return bool |
|
749 | + */ |
|
750 | + public function hasUser($user_guid, $collection_id) { |
|
751 | + $options = [ |
|
752 | + 'guids' => (int) $user_guid, |
|
753 | + 'count' => true, |
|
754 | + ]; |
|
755 | + return (bool) $this->getMembers($collection_id, $options); |
|
756 | + } |
|
757 | + |
|
758 | + /** |
|
759 | + * Adds a user to an access collection. |
|
760 | + * |
|
761 | + * Triggers the 'access:collections:add_user', 'collection' plugin hook. |
|
762 | + * |
|
763 | + * @param int $user_guid GUID of the user to add |
|
764 | + * @param int $collection_id ID of the collection to add them to |
|
765 | + * @return bool |
|
766 | + */ |
|
767 | + public function addUser($user_guid, $collection_id) { |
|
768 | + |
|
769 | + $collection = $this->get($collection_id); |
|
770 | + |
|
771 | + if (!$collection) { |
|
772 | + return false; |
|
773 | + } |
|
774 | + |
|
775 | + if (!$this->entities->exists($user_guid)) { |
|
776 | + return false; |
|
777 | + } |
|
778 | + |
|
779 | + $hook_params = [ |
|
780 | + 'collection_id' => $collection->id, |
|
781 | + 'user_guid' => (int) $user_guid |
|
782 | + ]; |
|
783 | + |
|
784 | + $result = $this->hooks->trigger('access:collections:add_user', 'collection', $hook_params, true); |
|
785 | + if ($result == false) { |
|
786 | + return false; |
|
787 | + } |
|
788 | + |
|
789 | + // if someone tries to insert the same data twice, we do a no-op on duplicate key |
|
790 | + $query = " |
|
791 | 791 | INSERT INTO {$this->membership_table} |
792 | 792 | SET access_collection_id = :access_collection_id, |
793 | 793 | user_guid = :user_guid |
794 | 794 | ON DUPLICATE KEY UPDATE user_guid = user_guid |
795 | 795 | "; |
796 | 796 | |
797 | - $result = $this->db->insertData($query, [ |
|
798 | - ':access_collection_id' => (int) $collection->id, |
|
799 | - ':user_guid' => (int) $user_guid, |
|
800 | - ]); |
|
797 | + $result = $this->db->insertData($query, [ |
|
798 | + ':access_collection_id' => (int) $collection->id, |
|
799 | + ':user_guid' => (int) $user_guid, |
|
800 | + ]); |
|
801 | 801 | |
802 | - $this->access_cache->clear(); |
|
802 | + $this->access_cache->clear(); |
|
803 | 803 | |
804 | - return $result !== false; |
|
805 | - } |
|
806 | - |
|
807 | - /** |
|
808 | - * Removes a user from an access collection. |
|
809 | - * |
|
810 | - * Triggers the 'access:collections:remove_user', 'collection' plugin hook. |
|
811 | - * |
|
812 | - * @param int $user_guid GUID of the user |
|
813 | - * @param int $collection_id ID of the collection |
|
814 | - * @return bool |
|
815 | - */ |
|
816 | - public function removeUser($user_guid, $collection_id) { |
|
817 | - |
|
818 | - $params = [ |
|
819 | - 'collection_id' => (int) $collection_id, |
|
820 | - 'user_guid' => (int) $user_guid, |
|
821 | - ]; |
|
822 | - |
|
823 | - if (!$this->hooks->trigger('access:collections:remove_user', 'collection', $params, true)) { |
|
824 | - return false; |
|
825 | - } |
|
826 | - |
|
827 | - $query = " |
|
804 | + return $result !== false; |
|
805 | + } |
|
806 | + |
|
807 | + /** |
|
808 | + * Removes a user from an access collection. |
|
809 | + * |
|
810 | + * Triggers the 'access:collections:remove_user', 'collection' plugin hook. |
|
811 | + * |
|
812 | + * @param int $user_guid GUID of the user |
|
813 | + * @param int $collection_id ID of the collection |
|
814 | + * @return bool |
|
815 | + */ |
|
816 | + public function removeUser($user_guid, $collection_id) { |
|
817 | + |
|
818 | + $params = [ |
|
819 | + 'collection_id' => (int) $collection_id, |
|
820 | + 'user_guid' => (int) $user_guid, |
|
821 | + ]; |
|
822 | + |
|
823 | + if (!$this->hooks->trigger('access:collections:remove_user', 'collection', $params, true)) { |
|
824 | + return false; |
|
825 | + } |
|
826 | + |
|
827 | + $query = " |
|
828 | 828 | DELETE FROM {$this->membership_table} |
829 | 829 | WHERE access_collection_id = :access_collection_id |
830 | 830 | AND user_guid = :user_guid |
831 | 831 | "; |
832 | 832 | |
833 | - $this->access_cache->clear(); |
|
833 | + $this->access_cache->clear(); |
|
834 | 834 | |
835 | - return (bool) $this->db->deleteData($query, [ |
|
836 | - ':access_collection_id' => (int) $collection_id, |
|
837 | - ':user_guid' => (int) $user_guid, |
|
838 | - ]); |
|
839 | - } |
|
835 | + return (bool) $this->db->deleteData($query, [ |
|
836 | + ':access_collection_id' => (int) $collection_id, |
|
837 | + ':user_guid' => (int) $user_guid, |
|
838 | + ]); |
|
839 | + } |
|
840 | 840 | |
841 | - /** |
|
842 | - * Returns access collections owned by the user |
|
843 | - * |
|
844 | - * @param int $owner_guid GUID of the owner |
|
845 | - * @return ElggAccessCollection[]|false |
|
846 | - */ |
|
847 | - public function getEntityCollections($owner_guid) { |
|
841 | + /** |
|
842 | + * Returns access collections owned by the user |
|
843 | + * |
|
844 | + * @param int $owner_guid GUID of the owner |
|
845 | + * @return ElggAccessCollection[]|false |
|
846 | + */ |
|
847 | + public function getEntityCollections($owner_guid) { |
|
848 | 848 | |
849 | - $callback = [$this, 'rowToElggAccessCollection']; |
|
849 | + $callback = [$this, 'rowToElggAccessCollection']; |
|
850 | 850 | |
851 | - $query = " |
|
851 | + $query = " |
|
852 | 852 | SELECT * FROM {$this->table} |
853 | 853 | WHERE owner_guid = :owner_guid |
854 | 854 | ORDER BY name ASC |
855 | 855 | "; |
856 | 856 | |
857 | - $params = [ |
|
858 | - ':owner_guid' => (int) $owner_guid, |
|
859 | - ]; |
|
857 | + $params = [ |
|
858 | + ':owner_guid' => (int) $owner_guid, |
|
859 | + ]; |
|
860 | 860 | |
861 | - return $this->db->getData($query, $callback, $params); |
|
862 | - } |
|
861 | + return $this->db->getData($query, $callback, $params); |
|
862 | + } |
|
863 | 863 | |
864 | - /** |
|
865 | - * Get members of an access collection |
|
866 | - * |
|
867 | - * @param int $collection_id The collection's ID |
|
868 | - * @param array $options Ege* options |
|
869 | - * @return ElggEntity[]|false |
|
870 | - */ |
|
871 | - public function getMembers($collection_id, array $options = []) { |
|
864 | + /** |
|
865 | + * Get members of an access collection |
|
866 | + * |
|
867 | + * @param int $collection_id The collection's ID |
|
868 | + * @param array $options Ege* options |
|
869 | + * @return ElggEntity[]|false |
|
870 | + */ |
|
871 | + public function getMembers($collection_id, array $options = []) { |
|
872 | 872 | |
873 | - $options['joins'][] = "JOIN {$this->membership_table} acm"; |
|
873 | + $options['joins'][] = "JOIN {$this->membership_table} acm"; |
|
874 | 874 | |
875 | - $collection_id = (int) $collection_id; |
|
876 | - $options['wheres'][] = "e.guid = acm.user_guid AND acm.access_collection_id = {$collection_id}"; |
|
875 | + $collection_id = (int) $collection_id; |
|
876 | + $options['wheres'][] = "e.guid = acm.user_guid AND acm.access_collection_id = {$collection_id}"; |
|
877 | 877 | |
878 | - return $this->entities->getEntities($options); |
|
879 | - } |
|
878 | + return $this->entities->getEntities($options); |
|
879 | + } |
|
880 | 880 | |
881 | - /** |
|
882 | - * Return an array of collections that the entity is member of |
|
883 | - * |
|
884 | - * @param int $member_guid GUID of th member |
|
885 | - * |
|
886 | - * @return ElggAccessCollection[]|false |
|
887 | - */ |
|
888 | - public function getCollectionsByMember($member_guid) { |
|
881 | + /** |
|
882 | + * Return an array of collections that the entity is member of |
|
883 | + * |
|
884 | + * @param int $member_guid GUID of th member |
|
885 | + * |
|
886 | + * @return ElggAccessCollection[]|false |
|
887 | + */ |
|
888 | + public function getCollectionsByMember($member_guid) { |
|
889 | 889 | |
890 | - $callback = [$this, 'rowToElggAccessCollection']; |
|
890 | + $callback = [$this, 'rowToElggAccessCollection']; |
|
891 | 891 | |
892 | - $query = " |
|
892 | + $query = " |
|
893 | 893 | SELECT ac.* FROM {$this->table} ac |
894 | 894 | JOIN {$this->membership_table} acm |
895 | 895 | ON ac.id = acm.access_collection_id |
@@ -897,58 +897,58 @@ discard block |
||
897 | 897 | ORDER BY name ASC |
898 | 898 | "; |
899 | 899 | |
900 | - return $this->db->getData($query, $callback, [ |
|
901 | - ':member_guid' => (int) $member_guid, |
|
902 | - ]); |
|
903 | - } |
|
904 | - |
|
905 | - /** |
|
906 | - * Return the name of an ACCESS_* constant or an access collection, |
|
907 | - * but only if the logged in user owns the access collection or is an admin. |
|
908 | - * Ownership requirement prevents us from exposing names of access collections |
|
909 | - * that current user has been added to by other members and may contain |
|
910 | - * sensitive classification of the current user (e.g. close friends vs acquaintances). |
|
911 | - * |
|
912 | - * Returns a string in the language of the user for global access levels, e.g.'Public, 'Friends', 'Logged in', 'Private'; |
|
913 | - * or a name of the owned access collection, e.g. 'My work colleagues'; |
|
914 | - * or a name of the group or other access collection, e.g. 'Group: Elgg technical support'; |
|
915 | - * or 'Limited' if the user access is restricted to read-only, e.g. a friends collection the user was added to |
|
916 | - * |
|
917 | - * @param int $entity_access_id The entity's access id |
|
918 | - * |
|
919 | - * @return string |
|
920 | - * @since 1.11 |
|
921 | - */ |
|
922 | - public function getReadableAccessLevel($entity_access_id) { |
|
923 | - $access = (int) $entity_access_id; |
|
924 | - |
|
925 | - $translator = $this->translator; |
|
926 | - |
|
927 | - // Check if entity access id is a defined global constant |
|
928 | - $access_array = [ |
|
929 | - ACCESS_PRIVATE => $translator->translate("PRIVATE"), |
|
930 | - ACCESS_FRIENDS => $translator->translate("access:friends:label"), |
|
931 | - ACCESS_LOGGED_IN => $translator->translate("LOGGED_IN"), |
|
932 | - ACCESS_PUBLIC => $translator->translate("PUBLIC"), |
|
933 | - ]; |
|
934 | - |
|
935 | - if (array_key_exists($access, $access_array)) { |
|
936 | - return $access_array[$access]; |
|
937 | - } |
|
938 | - |
|
939 | - // Entity access id is probably a custom access collection |
|
940 | - // Check if the user has write access to it and can see it's label |
|
941 | - // Admins should always be able to see the readable version |
|
942 | - $collection = $this->get($access); |
|
943 | - |
|
944 | - $user_guid = $this->session->getLoggedInUserGuid(); |
|
900 | + return $this->db->getData($query, $callback, [ |
|
901 | + ':member_guid' => (int) $member_guid, |
|
902 | + ]); |
|
903 | + } |
|
904 | + |
|
905 | + /** |
|
906 | + * Return the name of an ACCESS_* constant or an access collection, |
|
907 | + * but only if the logged in user owns the access collection or is an admin. |
|
908 | + * Ownership requirement prevents us from exposing names of access collections |
|
909 | + * that current user has been added to by other members and may contain |
|
910 | + * sensitive classification of the current user (e.g. close friends vs acquaintances). |
|
911 | + * |
|
912 | + * Returns a string in the language of the user for global access levels, e.g.'Public, 'Friends', 'Logged in', 'Private'; |
|
913 | + * or a name of the owned access collection, e.g. 'My work colleagues'; |
|
914 | + * or a name of the group or other access collection, e.g. 'Group: Elgg technical support'; |
|
915 | + * or 'Limited' if the user access is restricted to read-only, e.g. a friends collection the user was added to |
|
916 | + * |
|
917 | + * @param int $entity_access_id The entity's access id |
|
918 | + * |
|
919 | + * @return string |
|
920 | + * @since 1.11 |
|
921 | + */ |
|
922 | + public function getReadableAccessLevel($entity_access_id) { |
|
923 | + $access = (int) $entity_access_id; |
|
924 | + |
|
925 | + $translator = $this->translator; |
|
926 | + |
|
927 | + // Check if entity access id is a defined global constant |
|
928 | + $access_array = [ |
|
929 | + ACCESS_PRIVATE => $translator->translate("PRIVATE"), |
|
930 | + ACCESS_FRIENDS => $translator->translate("access:friends:label"), |
|
931 | + ACCESS_LOGGED_IN => $translator->translate("LOGGED_IN"), |
|
932 | + ACCESS_PUBLIC => $translator->translate("PUBLIC"), |
|
933 | + ]; |
|
934 | + |
|
935 | + if (array_key_exists($access, $access_array)) { |
|
936 | + return $access_array[$access]; |
|
937 | + } |
|
938 | + |
|
939 | + // Entity access id is probably a custom access collection |
|
940 | + // Check if the user has write access to it and can see it's label |
|
941 | + // Admins should always be able to see the readable version |
|
942 | + $collection = $this->get($access); |
|
943 | + |
|
944 | + $user_guid = $this->session->getLoggedInUserGuid(); |
|
945 | 945 | |
946 | - if (!$collection || !$user_guid) { |
|
947 | - // return 'Limited' if there is no logged in user or collection can not be loaded |
|
948 | - return $translator->translate('access:limited:label'); |
|
949 | - } |
|
946 | + if (!$collection || !$user_guid) { |
|
947 | + // return 'Limited' if there is no logged in user or collection can not be loaded |
|
948 | + return $translator->translate('access:limited:label'); |
|
949 | + } |
|
950 | 950 | |
951 | - return $collection->getDisplayName(); |
|
952 | - } |
|
951 | + return $collection->getDisplayName(); |
|
952 | + } |
|
953 | 953 | |
954 | 954 | } |
@@ -140,7 +140,7 @@ discard block |
||
140 | 140 | $list = "($access_ids)"; |
141 | 141 | |
142 | 142 | // for BC, populate the cache |
143 | - $hash = $user_guid . 'get_access_list'; |
|
143 | + $hash = $user_guid.'get_access_list'; |
|
144 | 144 | $this->access_cache->add($hash, $list); |
145 | 145 | |
146 | 146 | return $list; |
@@ -183,7 +183,7 @@ discard block |
||
183 | 183 | |
184 | 184 | $user_guid = (int) $user_guid; |
185 | 185 | |
186 | - $hash = $user_guid . 'get_access_array'; |
|
186 | + $hash = $user_guid.'get_access_array'; |
|
187 | 187 | |
188 | 188 | if ($cache[$hash]) { |
189 | 189 | $access_array = $cache[$hash]; |
@@ -305,7 +305,7 @@ discard block |
||
305 | 305 | $options['user_guid'] = sanitize_int($options['user_guid'], false); |
306 | 306 | |
307 | 307 | // only add dot if we have an alias or table name |
308 | - $table_alias = $options['table_alias'] ? $options['table_alias'] . '.' : ''; |
|
308 | + $table_alias = $options['table_alias'] ? $options['table_alias'].'.' : ''; |
|
309 | 309 | |
310 | 310 | if (!isset($options['ignore_access'])) { |
311 | 311 | $options['ignore_access'] = $this->capabilities->canBypassPermissionsCheck($options['user_guid']); |
@@ -322,7 +322,7 @@ discard block |
||
322 | 322 | $clauses['ors']['ignore_access'] = '1 = 1'; |
323 | 323 | } else if ($options['user_guid']) { |
324 | 324 | // include content of user's friends |
325 | - $clauses['ors']['friends_access'] = "$table_alias{$options['access_column']} = " . ACCESS_FRIENDS . " |
|
325 | + $clauses['ors']['friends_access'] = "$table_alias{$options['access_column']} = ".ACCESS_FRIENDS." |
|
326 | 326 | AND $table_alias{$options['owner_guid_column']} IN ( |
327 | 327 | SELECT guid_one FROM {$prefix}entity_relationships |
328 | 328 | WHERE relationship = 'friend' AND guid_two = {$options['user_guid']} |
@@ -346,14 +346,14 @@ discard block |
||
346 | 346 | |
347 | 347 | $clauses_str = ''; |
348 | 348 | if (is_array($clauses['ors']) && $clauses['ors']) { |
349 | - $clauses_str = '(' . implode(' OR ', $clauses['ors']) . ')'; |
|
349 | + $clauses_str = '('.implode(' OR ', $clauses['ors']).')'; |
|
350 | 350 | } |
351 | 351 | |
352 | 352 | if (is_array($clauses['ands']) && $clauses['ands']) { |
353 | 353 | if ($clauses_str) { |
354 | 354 | $clauses_str .= ' AND '; |
355 | 355 | } |
356 | - $clauses_str .= '(' . implode(' AND ', $clauses['ands']) . ')'; |
|
356 | + $clauses_str .= '('.implode(' AND ', $clauses['ands']).')'; |
|
357 | 357 | } |
358 | 358 | |
359 | 359 | if (empty($clauses_str)) { |
@@ -452,7 +452,7 @@ discard block |
||
452 | 452 | |
453 | 453 | $user_guid = (int) $user_guid; |
454 | 454 | |
455 | - $hash = $user_guid . 'get_write_access_array'; |
|
455 | + $hash = $user_guid.'get_write_access_array'; |
|
456 | 456 | |
457 | 457 | if ($cache[$hash]) { |
458 | 458 | $access_array = $cache[$hash]; |
@@ -1,19 +1,19 @@ discard block |
||
1 | 1 | <?php |
2 | 2 | |
3 | 3 | function elgg_friends_plugin_init() { |
4 | - elgg_register_plugin_hook_handler('access:collections:write', 'user', '_elgg_friends_write_access', 1); |
|
5 | - elgg_register_plugin_hook_handler('filter_tabs', 'all', '_elgg_friends_filter_tabs', 1); |
|
4 | + elgg_register_plugin_hook_handler('access:collections:write', 'user', '_elgg_friends_write_access', 1); |
|
5 | + elgg_register_plugin_hook_handler('filter_tabs', 'all', '_elgg_friends_filter_tabs', 1); |
|
6 | 6 | |
7 | - elgg_register_event_handler('create', 'relationship', '_elgg_send_friend_notification'); |
|
7 | + elgg_register_event_handler('create', 'relationship', '_elgg_send_friend_notification'); |
|
8 | 8 | |
9 | - elgg_register_page_handler('friends', '_elgg_friends_page_handler'); |
|
10 | - elgg_register_page_handler('friendsof', '_elgg_friends_page_handler'); |
|
9 | + elgg_register_page_handler('friends', '_elgg_friends_page_handler'); |
|
10 | + elgg_register_page_handler('friendsof', '_elgg_friends_page_handler'); |
|
11 | 11 | |
12 | - elgg_register_plugin_hook_handler('entity:url', 'object', '_elgg_friends_widget_urls'); |
|
12 | + elgg_register_plugin_hook_handler('entity:url', 'object', '_elgg_friends_widget_urls'); |
|
13 | 13 | |
14 | - elgg_register_plugin_hook_handler('register', 'menu:page', '_elgg_friends_page_menu'); |
|
15 | - elgg_register_plugin_hook_handler('register', 'menu:topbar', '_elgg_friends_topbar_menu'); |
|
16 | - elgg_register_plugin_hook_handler('register', 'menu:user_hover', '_elgg_friends_setup_user_hover_menu'); |
|
14 | + elgg_register_plugin_hook_handler('register', 'menu:page', '_elgg_friends_page_menu'); |
|
15 | + elgg_register_plugin_hook_handler('register', 'menu:topbar', '_elgg_friends_topbar_menu'); |
|
16 | + elgg_register_plugin_hook_handler('register', 'menu:user_hover', '_elgg_friends_setup_user_hover_menu'); |
|
17 | 17 | } |
18 | 18 | |
19 | 19 | elgg_register_event_handler('init', 'system', 'elgg_friends_plugin_init'); |
@@ -24,37 +24,37 @@ discard block |
||
24 | 24 | * @access private |
25 | 25 | */ |
26 | 26 | function _elgg_friends_setup_user_hover_menu($hook, $type, $return, $params) { |
27 | - $user = $params['entity']; |
|
28 | - /* @var \ElggUser $user */ |
|
29 | - |
|
30 | - if (elgg_is_logged_in()) { |
|
31 | - if (elgg_get_logged_in_user_guid() != $user->guid) { |
|
32 | - $isFriend = $user->isFriend(); |
|
33 | - |
|
34 | - // Always emit both to make it super easy to toggle with ajax |
|
35 | - $return[] = \ElggMenuItem::factory([ |
|
36 | - 'name' => 'remove_friend', |
|
37 | - 'href' => "action/friends/remove?friend={$user->guid}", |
|
38 | - 'is_action' => true, |
|
39 | - 'text' => elgg_echo('friend:remove'), |
|
40 | - 'icon' => 'user-times', |
|
41 | - 'section' => 'action', |
|
42 | - 'item_class' => $isFriend ? '' : 'hidden', |
|
43 | - ]); |
|
44 | - |
|
45 | - $return[] = \ElggMenuItem::factory([ |
|
46 | - 'name' => 'add_friend', |
|
47 | - 'href' => "action/friends/add?friend={$user->guid}", |
|
48 | - 'is_action' => true, |
|
49 | - 'text' => elgg_echo('friend:add'), |
|
50 | - 'icon' => 'user-plus', |
|
51 | - 'section' => 'action', |
|
52 | - 'item_class' => $isFriend ? 'hidden' : '', |
|
53 | - ]); |
|
54 | - } |
|
55 | - } |
|
56 | - |
|
57 | - return $return; |
|
27 | + $user = $params['entity']; |
|
28 | + /* @var \ElggUser $user */ |
|
29 | + |
|
30 | + if (elgg_is_logged_in()) { |
|
31 | + if (elgg_get_logged_in_user_guid() != $user->guid) { |
|
32 | + $isFriend = $user->isFriend(); |
|
33 | + |
|
34 | + // Always emit both to make it super easy to toggle with ajax |
|
35 | + $return[] = \ElggMenuItem::factory([ |
|
36 | + 'name' => 'remove_friend', |
|
37 | + 'href' => "action/friends/remove?friend={$user->guid}", |
|
38 | + 'is_action' => true, |
|
39 | + 'text' => elgg_echo('friend:remove'), |
|
40 | + 'icon' => 'user-times', |
|
41 | + 'section' => 'action', |
|
42 | + 'item_class' => $isFriend ? '' : 'hidden', |
|
43 | + ]); |
|
44 | + |
|
45 | + $return[] = \ElggMenuItem::factory([ |
|
46 | + 'name' => 'add_friend', |
|
47 | + 'href' => "action/friends/add?friend={$user->guid}", |
|
48 | + 'is_action' => true, |
|
49 | + 'text' => elgg_echo('friend:add'), |
|
50 | + 'icon' => 'user-plus', |
|
51 | + 'section' => 'action', |
|
52 | + 'item_class' => $isFriend ? 'hidden' : '', |
|
53 | + ]); |
|
54 | + } |
|
55 | + } |
|
56 | + |
|
57 | + return $return; |
|
58 | 58 | } |
59 | 59 | |
60 | 60 | /** |
@@ -67,27 +67,27 @@ discard block |
||
67 | 67 | * @access private |
68 | 68 | */ |
69 | 69 | function _elgg_friends_page_handler($segments, $handler) { |
70 | - elgg_set_context('friends'); // needed because pagehandler friendsof is also using this handler |
|
71 | - |
|
72 | - if (isset($segments[0]) && $user = get_user_by_username($segments[0])) { |
|
73 | - elgg_set_page_owner_guid($user->getGUID()); |
|
74 | - } |
|
75 | - |
|
76 | - if (!elgg_get_page_owner_guid()) { |
|
77 | - return false; |
|
78 | - } |
|
79 | - |
|
80 | - switch ($handler) { |
|
81 | - case 'friends': |
|
82 | - echo elgg_view_resource("friends/index"); |
|
83 | - break; |
|
84 | - case 'friendsof': |
|
85 | - echo elgg_view_resource("friends/of"); |
|
86 | - break; |
|
87 | - default: |
|
88 | - return false; |
|
89 | - } |
|
90 | - return true; |
|
70 | + elgg_set_context('friends'); // needed because pagehandler friendsof is also using this handler |
|
71 | + |
|
72 | + if (isset($segments[0]) && $user = get_user_by_username($segments[0])) { |
|
73 | + elgg_set_page_owner_guid($user->getGUID()); |
|
74 | + } |
|
75 | + |
|
76 | + if (!elgg_get_page_owner_guid()) { |
|
77 | + return false; |
|
78 | + } |
|
79 | + |
|
80 | + switch ($handler) { |
|
81 | + case 'friends': |
|
82 | + echo elgg_view_resource("friends/index"); |
|
83 | + break; |
|
84 | + case 'friendsof': |
|
85 | + echo elgg_view_resource("friends/of"); |
|
86 | + break; |
|
87 | + default: |
|
88 | + return false; |
|
89 | + } |
|
90 | + return true; |
|
91 | 91 | } |
92 | 92 | |
93 | 93 | /** |
@@ -105,21 +105,21 @@ discard block |
||
105 | 105 | */ |
106 | 106 | function _elgg_friends_topbar_menu($hook, $type, $return, $params) { |
107 | 107 | |
108 | - $viewer = elgg_get_logged_in_user_entity(); |
|
109 | - if (!$viewer) { |
|
110 | - return; |
|
111 | - } |
|
108 | + $viewer = elgg_get_logged_in_user_entity(); |
|
109 | + if (!$viewer) { |
|
110 | + return; |
|
111 | + } |
|
112 | 112 | |
113 | - $return[] = \ElggMenuItem::factory([ |
|
114 | - 'name' => 'friends', |
|
115 | - 'href' => "friends/{$viewer->username}", |
|
116 | - 'text' => elgg_echo('friends'), |
|
117 | - 'icon' => 'users', |
|
118 | - 'title' => elgg_echo('friends'), |
|
119 | - 'priority' => 300, |
|
120 | - ]); |
|
113 | + $return[] = \ElggMenuItem::factory([ |
|
114 | + 'name' => 'friends', |
|
115 | + 'href' => "friends/{$viewer->username}", |
|
116 | + 'text' => elgg_echo('friends'), |
|
117 | + 'icon' => 'users', |
|
118 | + 'title' => elgg_echo('friends'), |
|
119 | + 'priority' => 300, |
|
120 | + ]); |
|
121 | 121 | |
122 | - return $return; |
|
122 | + return $return; |
|
123 | 123 | } |
124 | 124 | |
125 | 125 | /** |
@@ -137,26 +137,26 @@ discard block |
||
137 | 137 | */ |
138 | 138 | function _elgg_friends_page_menu($hook, $type, $return, $params) { |
139 | 139 | |
140 | - $owner = elgg_get_page_owner_entity(); |
|
141 | - if (!$owner instanceof ElggUser) { |
|
142 | - return; |
|
143 | - } |
|
144 | - |
|
145 | - $return[] = \ElggMenuItem::factory([ |
|
146 | - 'name' => 'friends', |
|
147 | - 'text' => elgg_echo('friends'), |
|
148 | - 'href' => 'friends/' . $owner->username, |
|
149 | - 'contexts' => ['friends'], |
|
150 | - ]); |
|
151 | - |
|
152 | - $return[] = \ElggMenuItem::factory([ |
|
153 | - 'name' => 'friends:of', |
|
154 | - 'text' => elgg_echo('friends:of'), |
|
155 | - 'href' => 'friendsof/' . $owner->username, |
|
156 | - 'contexts' => ['friends'], |
|
157 | - ]); |
|
158 | - |
|
159 | - return $return; |
|
140 | + $owner = elgg_get_page_owner_entity(); |
|
141 | + if (!$owner instanceof ElggUser) { |
|
142 | + return; |
|
143 | + } |
|
144 | + |
|
145 | + $return[] = \ElggMenuItem::factory([ |
|
146 | + 'name' => 'friends', |
|
147 | + 'text' => elgg_echo('friends'), |
|
148 | + 'href' => 'friends/' . $owner->username, |
|
149 | + 'contexts' => ['friends'], |
|
150 | + ]); |
|
151 | + |
|
152 | + $return[] = \ElggMenuItem::factory([ |
|
153 | + 'name' => 'friends:of', |
|
154 | + 'text' => elgg_echo('friends:of'), |
|
155 | + 'href' => 'friendsof/' . $owner->username, |
|
156 | + 'contexts' => ['friends'], |
|
157 | + ]); |
|
158 | + |
|
159 | + return $return; |
|
160 | 160 | } |
161 | 161 | |
162 | 162 | /** |
@@ -170,40 +170,40 @@ discard block |
||
170 | 170 | * @access private |
171 | 171 | */ |
172 | 172 | function _elgg_send_friend_notification($event, $type, $object) { |
173 | - if ($object->relationship != 'friend') { |
|
174 | - return true; |
|
175 | - } |
|
176 | - |
|
177 | - $user_one = get_entity($object->guid_one); |
|
178 | - /* @var \ElggUser $user_one */ |
|
179 | - |
|
180 | - $user_two = get_entity($object->guid_two); |
|
181 | - /* @var ElggUser $user_two */ |
|
182 | - |
|
183 | - if (!$user_one instanceof ElggUser || !$user_two instanceof ElggUser) { |
|
184 | - return; |
|
185 | - } |
|
186 | - |
|
187 | - // Notification subject |
|
188 | - $subject = elgg_echo('friend:newfriend:subject', [ |
|
189 | - $user_one->name |
|
190 | - ], $user_two->language); |
|
191 | - |
|
192 | - // Notification body |
|
193 | - $body = elgg_echo("friend:newfriend:body", [ |
|
194 | - $user_one->name, |
|
195 | - $user_one->getURL() |
|
196 | - ], $user_two->language); |
|
197 | - |
|
198 | - // Notification params |
|
199 | - $params = [ |
|
200 | - 'action' => 'add_friend', |
|
201 | - 'object' => $user_one, |
|
202 | - 'friend' => $user_two, |
|
203 | - 'url' => $user_two->getURL(), |
|
204 | - ]; |
|
205 | - |
|
206 | - return notify_user($user_two->guid, $object->guid_one, $subject, $body, $params); |
|
173 | + if ($object->relationship != 'friend') { |
|
174 | + return true; |
|
175 | + } |
|
176 | + |
|
177 | + $user_one = get_entity($object->guid_one); |
|
178 | + /* @var \ElggUser $user_one */ |
|
179 | + |
|
180 | + $user_two = get_entity($object->guid_two); |
|
181 | + /* @var ElggUser $user_two */ |
|
182 | + |
|
183 | + if (!$user_one instanceof ElggUser || !$user_two instanceof ElggUser) { |
|
184 | + return; |
|
185 | + } |
|
186 | + |
|
187 | + // Notification subject |
|
188 | + $subject = elgg_echo('friend:newfriend:subject', [ |
|
189 | + $user_one->name |
|
190 | + ], $user_two->language); |
|
191 | + |
|
192 | + // Notification body |
|
193 | + $body = elgg_echo("friend:newfriend:body", [ |
|
194 | + $user_one->name, |
|
195 | + $user_one->getURL() |
|
196 | + ], $user_two->language); |
|
197 | + |
|
198 | + // Notification params |
|
199 | + $params = [ |
|
200 | + 'action' => 'add_friend', |
|
201 | + 'object' => $user_one, |
|
202 | + 'friend' => $user_two, |
|
203 | + 'url' => $user_two->getURL(), |
|
204 | + ]; |
|
205 | + |
|
206 | + return notify_user($user_two->guid, $object->guid_one, $subject, $body, $params); |
|
207 | 207 | } |
208 | 208 | |
209 | 209 | /** |
@@ -218,24 +218,24 @@ discard block |
||
218 | 218 | */ |
219 | 219 | function _elgg_friends_write_access($hook, $type, $access_array, $params) { |
220 | 220 | |
221 | - // rebuild array, putting friends 1st or 2nd |
|
222 | - $ret = []; |
|
221 | + // rebuild array, putting friends 1st or 2nd |
|
222 | + $ret = []; |
|
223 | 223 | |
224 | - // private exists, it goes first |
|
225 | - if (isset($access_array[ACCESS_PRIVATE])) { |
|
226 | - $ret[ACCESS_PRIVATE] = $access_array[ACCESS_PRIVATE]; |
|
227 | - unset($access_array[ACCESS_PRIVATE]); |
|
228 | - } |
|
224 | + // private exists, it goes first |
|
225 | + if (isset($access_array[ACCESS_PRIVATE])) { |
|
226 | + $ret[ACCESS_PRIVATE] = $access_array[ACCESS_PRIVATE]; |
|
227 | + unset($access_array[ACCESS_PRIVATE]); |
|
228 | + } |
|
229 | 229 | |
230 | - // friends |
|
231 | - $ret[ACCESS_FRIENDS] = get_readable_access_level(ACCESS_FRIENDS); |
|
230 | + // friends |
|
231 | + $ret[ACCESS_FRIENDS] = get_readable_access_level(ACCESS_FRIENDS); |
|
232 | 232 | |
233 | - // rest |
|
234 | - foreach ($access_array as $key => $value) { |
|
235 | - $ret[$key] = $value; |
|
236 | - } |
|
233 | + // rest |
|
234 | + foreach ($access_array as $key => $value) { |
|
235 | + $ret[$key] = $value; |
|
236 | + } |
|
237 | 237 | |
238 | - return $ret; |
|
238 | + return $ret; |
|
239 | 239 | } |
240 | 240 | |
241 | 241 | /** |
@@ -250,22 +250,22 @@ discard block |
||
250 | 250 | */ |
251 | 251 | function _elgg_friends_filter_tabs($hook, $type, $items, $params) { |
252 | 252 | |
253 | - $user = elgg_extract('user', $params); |
|
254 | - if (!$user instanceof ElggUser) { |
|
255 | - return; |
|
256 | - } |
|
257 | - |
|
258 | - $vars = elgg_extract('vars', $params); |
|
259 | - $selected = elgg_extract('selected', $params); |
|
260 | - |
|
261 | - $items[] = ElggMenuItem::factory([ |
|
262 | - 'name' => 'friend', |
|
263 | - 'text' => elgg_echo('friends'), |
|
264 | - 'href' => (isset($vars['friend_link'])) ? $vars['friend_link'] : "$type/friends/{$user->username}", |
|
265 | - 'selected' => ($selected == 'friends'), |
|
266 | - 'priority' => 400, |
|
267 | - ]); |
|
268 | - return $items; |
|
253 | + $user = elgg_extract('user', $params); |
|
254 | + if (!$user instanceof ElggUser) { |
|
255 | + return; |
|
256 | + } |
|
257 | + |
|
258 | + $vars = elgg_extract('vars', $params); |
|
259 | + $selected = elgg_extract('selected', $params); |
|
260 | + |
|
261 | + $items[] = ElggMenuItem::factory([ |
|
262 | + 'name' => 'friend', |
|
263 | + 'text' => elgg_echo('friends'), |
|
264 | + 'href' => (isset($vars['friend_link'])) ? $vars['friend_link'] : "$type/friends/{$user->username}", |
|
265 | + 'selected' => ($selected == 'friends'), |
|
266 | + 'priority' => 400, |
|
267 | + ]); |
|
268 | + return $items; |
|
269 | 269 | } |
270 | 270 | |
271 | 271 | |
@@ -280,19 +280,19 @@ discard block |
||
280 | 280 | * @access private |
281 | 281 | */ |
282 | 282 | function _elgg_friends_widget_urls($hook, $type, $result, $params) { |
283 | - $widget = elgg_extract('entity', $params); |
|
284 | - if (!($widget instanceof \ElggWidget)) { |
|
285 | - return; |
|
286 | - } |
|
283 | + $widget = elgg_extract('entity', $params); |
|
284 | + if (!($widget instanceof \ElggWidget)) { |
|
285 | + return; |
|
286 | + } |
|
287 | 287 | |
288 | - if ($widget->handler !== 'friends') { |
|
289 | - return; |
|
290 | - } |
|
288 | + if ($widget->handler !== 'friends') { |
|
289 | + return; |
|
290 | + } |
|
291 | 291 | |
292 | - $owner = $widget->getOwnerEntity(); |
|
293 | - if (!($owner instanceof \ElggUser)) { |
|
294 | - return; |
|
295 | - } |
|
292 | + $owner = $widget->getOwnerEntity(); |
|
293 | + if (!($owner instanceof \ElggUser)) { |
|
294 | + return; |
|
295 | + } |
|
296 | 296 | |
297 | - return "friends/{$owner->username}"; |
|
297 | + return "friends/{$owner->username}"; |
|
298 | 298 | } |