1 | <?php |
||
2 | |||
3 | use Elgg\Application; |
||
4 | use Elgg\Includer; |
||
5 | |||
6 | /** |
||
7 | * Stores site-side plugin settings as private data. |
||
8 | * |
||
9 | * This class is currently a stub, allowing a plugin to |
||
10 | * save settings in an object's private settings for each site. |
||
11 | */ |
||
12 | class ElggPlugin extends ElggObject { |
||
13 | |||
14 | /** |
||
15 | * @var ElggPluginPackage |
||
16 | */ |
||
17 | protected $package; |
||
18 | |||
19 | /** |
||
20 | * @var ElggPluginManifest |
||
21 | */ |
||
22 | protected $manifest; |
||
23 | |||
24 | /** |
||
25 | * @var string |
||
26 | */ |
||
27 | protected $path; |
||
28 | |||
29 | /** |
||
30 | * Data from static config file. null if not yet read. |
||
31 | * |
||
32 | * @var array|null |
||
33 | */ |
||
34 | protected $static_config; |
||
35 | |||
36 | /** |
||
37 | * @var string |
||
38 | */ |
||
39 | protected $errorMsg = ''; |
||
40 | |||
41 | /** |
||
42 | * {@inheritdoc} |
||
43 | */ |
||
44 | 309 | protected function initializeAttributes() { |
|
45 | 309 | parent::initializeAttributes(); |
|
46 | |||
47 | 309 | $this->attributes['subtype'] = "plugin"; |
|
48 | 309 | } |
|
49 | |||
50 | /** |
||
51 | * Load a plugin object from its ID |
||
52 | * Create a new plugin entity if doesn't exist |
||
53 | * |
||
54 | * @param string $plugin_id Plugin ID |
||
55 | * @param string $path Path, defaults to /mod |
||
56 | * |
||
57 | * @return ElggPlugin |
||
58 | * @throws PluginException |
||
59 | */ |
||
60 | 291 | public static function fromId($plugin_id, $path = null) { |
|
61 | 291 | if (empty($plugin_id)) { |
|
62 | 1 | throw new PluginException('Plugin ID must be set'); |
|
63 | } |
||
64 | |||
65 | 290 | $plugin = elgg_get_plugin_from_id($plugin_id); |
|
66 | |||
67 | 290 | if (!$plugin) { |
|
68 | 5 | $ia = elgg_set_ignore_access(true); |
|
69 | 5 | $plugin = new ElggPlugin(); |
|
70 | 5 | $plugin->title = $plugin_id; |
|
71 | 5 | $plugin->save(); |
|
72 | |||
73 | 5 | elgg_set_ignore_access($ia); |
|
74 | } |
||
75 | |||
76 | 290 | if (!$path) { |
|
77 | 284 | $path = elgg_get_plugins_path(); |
|
78 | } |
||
79 | |||
80 | 290 | $path = rtrim($path, '/'); |
|
81 | 290 | $plugin->setPath($path . '/' . $plugin_id); |
|
82 | |||
83 | 290 | return $plugin; |
|
84 | } |
||
85 | |||
86 | /** |
||
87 | * {@inheritdoc} |
||
88 | */ |
||
89 | 7 | public function save() { |
|
90 | |||
91 | 7 | $site = elgg_get_site_entity(); |
|
92 | |||
93 | 7 | $this->attributes['owner_guid'] = $site->guid; |
|
94 | 7 | $this->attributes['container_guid'] = $site->guid; |
|
95 | 7 | $this->attributes['access_id'] = ACCESS_PUBLIC; |
|
96 | |||
97 | 7 | $new = !$this->guid; |
|
98 | 7 | $priority = null; |
|
99 | 7 | if ($new) { |
|
100 | 7 | $name = _elgg_services()->plugins->namespacePrivateSetting('internal', 'priority'); |
|
101 | 7 | $priority = elgg_extract($name, $this->temp_private_settings, 'new'); |
|
102 | 2 | } else if (!$this->getPriority()) { |
|
103 | $priority = 'last'; |
||
104 | } |
||
105 | |||
106 | 7 | $guid = parent::save(); |
|
107 | 7 | if ($guid && $priority) { |
|
108 | 7 | $this->setPriority($new ? 'new' : 'last'); |
|
109 | } |
||
110 | |||
111 | 7 | return $guid; |
|
112 | } |
||
113 | |||
114 | /** |
||
115 | * Returns the ID (dir name) of this plugin |
||
116 | * |
||
117 | * @return string |
||
118 | */ |
||
119 | 314 | public function getID() { |
|
120 | 314 | return $this->title; |
|
121 | } |
||
122 | |||
123 | /** |
||
124 | * Returns the manifest's name if available, otherwise the ID. |
||
125 | * |
||
126 | * @return string |
||
127 | * @since 3.0 |
||
128 | */ |
||
129 | 2 | public function getDisplayName() { |
|
130 | 2 | $manifest = $this->getManifest(); |
|
131 | 2 | if ($manifest) { |
|
132 | 1 | return $manifest->getName(); |
|
133 | } |
||
134 | |||
135 | 1 | return $this->getID(); |
|
136 | } |
||
137 | |||
138 | /** |
||
139 | * Set path |
||
140 | * |
||
141 | * @param string $path Path to plugin directory |
||
142 | * |
||
143 | * @return void |
||
144 | * @access private |
||
145 | */ |
||
146 | 290 | public function setPath($path) { |
|
147 | 290 | $this->path = $path; |
|
148 | 290 | } |
|
149 | |||
150 | /** |
||
151 | * Returns the plugin's full path with trailing slash. |
||
152 | * |
||
153 | * @return string |
||
154 | */ |
||
155 | 295 | public function getPath() { |
|
156 | 295 | if (isset($this->path)) { |
|
157 | 283 | $path = $this->path; |
|
158 | } else { |
||
159 | 14 | $path = elgg_get_plugins_path() . $this->getID(); |
|
160 | } |
||
161 | |||
162 | 295 | return \Elgg\Project\Paths::sanitize($path, true); |
|
163 | } |
||
164 | |||
165 | /** |
||
166 | * Get a value from the plugins's static config file. |
||
167 | * |
||
168 | * @note If the system cache is on, Elgg APIs should not call this on every request. |
||
169 | * |
||
170 | * @param string $key Config key |
||
171 | * @param mixed $default Value returned if missing |
||
172 | * |
||
173 | * @return mixed |
||
174 | * @access private |
||
175 | * @internal For Elgg internal use only |
||
176 | */ |
||
177 | 99 | public function getStaticConfig($key, $default = null) { |
|
178 | 99 | if ($this->static_config === null) { |
|
179 | 86 | $this->static_config = []; |
|
180 | |||
181 | try { |
||
182 | 86 | if ($this->canReadFile(ElggPluginPackage::STATIC_CONFIG_FILENAME)) { |
|
183 | 86 | $this->static_config = $this->includeFile(ElggPluginPackage::STATIC_CONFIG_FILENAME); |
|
184 | } |
||
185 | } catch (PluginException $ex) { |
||
186 | elgg_log($ex->getMessage(), 'WARNING'); |
||
187 | } |
||
188 | } |
||
189 | |||
190 | 99 | if (isset($this->static_config[$key])) { |
|
191 | 73 | return $this->static_config[$key]; |
|
192 | } else { |
||
193 | 96 | return $default; |
|
194 | } |
||
195 | } |
||
196 | |||
197 | /** |
||
198 | * Returns an array of available markdown files for this plugin |
||
199 | * |
||
200 | * @return array |
||
201 | */ |
||
202 | 1 | public function getAvailableTextFiles() { |
|
203 | 1 | $filenames = $this->getPackage()->getTextFilenames(); |
|
204 | |||
205 | 1 | $files = []; |
|
206 | 1 | foreach ($filenames as $filename) { |
|
207 | 1 | if ($this->canReadFile($filename)) { |
|
208 | 1 | $files[$filename] = "{$this->getPath()}{$filename}"; |
|
209 | } |
||
210 | } |
||
211 | |||
212 | 1 | return $files; |
|
213 | } |
||
214 | |||
215 | // Load Priority |
||
216 | |||
217 | /** |
||
218 | * Gets the plugin's load priority. |
||
219 | * |
||
220 | * @return int|null |
||
221 | */ |
||
222 | 8 | public function getPriority() { |
|
223 | 8 | $name = _elgg_services()->plugins->namespacePrivateSetting('internal', 'priority'); |
|
224 | |||
225 | 8 | $priority = $this->getSetting($name); |
|
226 | 8 | if (isset($priority)) { |
|
227 | 5 | return (int) $priority; |
|
228 | } |
||
229 | |||
230 | 7 | return null; |
|
231 | } |
||
232 | |||
233 | /** |
||
234 | * Sets the priority of the plugin |
||
235 | * Returns the new priority or false on error |
||
236 | * |
||
237 | * @param mixed $priority The priority to set |
||
238 | * One of +1, -1, first, last, or a number. |
||
239 | * If given a number, this will displace all plugins at that number |
||
240 | * and set their priorities +1 |
||
241 | * |
||
242 | * @return int|false |
||
243 | * @throws DatabaseException |
||
244 | */ |
||
245 | 7 | public function setPriority($priority) { |
|
246 | 7 | $priority = $this->normalizePriority($priority); |
|
247 | |||
248 | 7 | return _elgg_services()->plugins->setPriority($this, $priority); |
|
249 | } |
||
250 | |||
251 | /** |
||
252 | * Normalize and validate new priority |
||
253 | * |
||
254 | * @param mixed $priority Priority to normalize |
||
255 | * |
||
256 | * @return int |
||
257 | * @access private |
||
258 | */ |
||
259 | 7 | public function normalizePriority($priority) { |
|
260 | // if no priority assume a priority of 1 |
||
261 | 7 | $old_priority = $this->getPriority(); |
|
262 | 7 | $old_priority = $old_priority ? : 1; |
|
263 | 7 | $max_priority = _elgg_get_max_plugin_priority(); |
|
264 | |||
265 | // can't use switch here because it's not strict and php evaluates +1 == 1 |
||
266 | 7 | if ($priority === '+1') { |
|
267 | 1 | $priority = $old_priority + 1; |
|
268 | 7 | } else if ($priority === '-1') { |
|
269 | 1 | $priority = $old_priority - 1; |
|
270 | 7 | } else if ($priority === 'first') { |
|
271 | 1 | $priority = 1; |
|
272 | 7 | } else if ($priority === 'last') { |
|
273 | 1 | $priority = $max_priority; |
|
274 | 7 | } else if ($priority === 'new') { |
|
275 | 7 | $max_priority++; |
|
276 | 7 | $priority = $max_priority; |
|
277 | } |
||
278 | |||
279 | 7 | return min($max_priority, max(1, (int) $priority)); |
|
280 | } |
||
281 | |||
282 | // Plugin settings |
||
283 | |||
284 | /** |
||
285 | * Returns a plugin setting |
||
286 | * |
||
287 | * @param string $name The setting name |
||
288 | * @param mixed $default The default value to return if none is set |
||
289 | * |
||
290 | * @return mixed |
||
291 | */ |
||
292 | 40 | public function getSetting($name, $default = null) { |
|
293 | 40 | $values = $this->getAllSettings(); |
|
294 | 40 | return elgg_extract($name, $values, $default); |
|
295 | } |
||
296 | |||
297 | /** |
||
298 | * Returns an array of all settings saved for this plugin. |
||
299 | * |
||
300 | * @note Unlike user settings, plugin settings are not namespaced. |
||
301 | * |
||
302 | * @return array An array of key/value pairs. |
||
303 | */ |
||
304 | 40 | public function getAllSettings() { |
|
305 | |||
306 | try { |
||
307 | 40 | $defaults = []; |
|
308 | 40 | if ($this->isActive()) { |
|
309 | // only load settings from static config for active plugins to prevent issues |
||
310 | // with internal plugin references ie. classes and language keys |
||
311 | 15 | $defaults = $this->getStaticConfig('settings', []); |
|
312 | } |
||
313 | |||
314 | 40 | if (!$this->guid) { |
|
315 | 1 | $settings = $this->temp_private_settings; |
|
316 | } else { |
||
317 | 39 | $settings = _elgg_services()->plugins->getAllSettings($this); |
|
318 | } |
||
319 | |||
320 | 40 | return array_merge($defaults, $settings); |
|
321 | } catch (DatabaseException $ex) { |
||
322 | return []; |
||
323 | } |
||
324 | } |
||
325 | |||
326 | /** |
||
327 | * Set a plugin setting for the plugin |
||
328 | * |
||
329 | * @param string $name The name to set |
||
330 | * @param string $value The value to set |
||
331 | * |
||
332 | * @return bool |
||
333 | */ |
||
334 | 4 | public function setSetting($name, $value) { |
|
335 | |||
336 | 4 | $value = elgg_trigger_plugin_hook('setting', 'plugin', [ |
|
337 | 4 | 'plugin_id' => $this->getID(), |
|
338 | 4 | 'plugin' => $this, |
|
339 | 4 | 'name' => $name, |
|
340 | 4 | 'value' => $value, |
|
341 | 4 | ], $value); |
|
342 | |||
343 | 4 | if (is_array($value)) { |
|
344 | 1 | elgg_log('Plugin settings cannot store arrays.', 'ERROR'); |
|
345 | |||
346 | 1 | return false; |
|
347 | } |
||
348 | |||
349 | 4 | return $this->setPrivateSetting($name, $value); |
|
350 | } |
||
351 | |||
352 | /** |
||
353 | * Removes a plugin setting name and value |
||
354 | * |
||
355 | * @param string $name The setting name to remove |
||
356 | * |
||
357 | * @return bool |
||
358 | */ |
||
359 | 1 | public function unsetSetting($name) { |
|
360 | 1 | return $this->removePrivateSetting($name); |
|
361 | } |
||
362 | |||
363 | /** |
||
364 | * Removes all settings for this plugin |
||
365 | * @return bool |
||
366 | */ |
||
367 | 1 | public function unsetAllSettings() { |
|
368 | 1 | $settings = $this->getAllSettings(); |
|
369 | |||
370 | 1 | foreach ($settings as $name => $value) { |
|
371 | 1 | if (strpos($name, 'elgg:internal:') === 0) { |
|
372 | 1 | continue; |
|
373 | } |
||
374 | 1 | $this->unsetSetting($name); |
|
375 | } |
||
376 | |||
377 | 1 | return true; |
|
378 | } |
||
379 | |||
380 | |||
381 | // User settings |
||
382 | |||
383 | /** |
||
384 | * Returns a user's setting for this plugin |
||
385 | * |
||
386 | * @param string $name The setting name |
||
387 | * @param int $user_guid The user GUID |
||
388 | * @param mixed $default The default value to return if none is set |
||
389 | * |
||
390 | * @return mixed The setting string value, the default value or false if there is no user |
||
391 | * @throws DatabaseException |
||
392 | */ |
||
393 | 1 | public function getUserSetting($name, $user_guid = 0, $default = null) { |
|
394 | 1 | $values = $this->getAllUserSettings($user_guid); |
|
395 | 1 | if ($values === false) { |
|
396 | return false; |
||
397 | } |
||
398 | |||
399 | 1 | return elgg_extract($name, $values, $default); |
|
400 | } |
||
401 | |||
402 | /** |
||
403 | * Returns an array of all user settings saved for this plugin for the user. |
||
404 | * |
||
405 | * @note Plugin settings are saved with a prefix. This removes that prefix. |
||
406 | * |
||
407 | * @param int $user_guid The user GUID. Defaults to logged in. |
||
408 | * |
||
409 | * @return array An array of key/value pairs |
||
410 | * @throws DatabaseException |
||
411 | */ |
||
412 | 1 | public function getAllUserSettings($user_guid = 0) { |
|
413 | |||
414 | 1 | $user = _elgg_services()->entityTable->getUserForPermissionsCheck($user_guid); |
|
415 | 1 | if (!$user instanceof ElggUser) { |
|
416 | return []; |
||
417 | } |
||
418 | |||
419 | 1 | $defaults = $this->getStaticConfig('user_settings', []); |
|
420 | |||
421 | 1 | $settings = _elgg_services()->plugins->getAllUserSettings($this, $user); |
|
422 | |||
423 | 1 | return array_merge($defaults, $settings); |
|
424 | } |
||
425 | |||
426 | /** |
||
427 | * Sets a user setting for a plugin |
||
428 | * |
||
429 | * @param string $name The setting name |
||
430 | * @param string $value The setting value |
||
431 | * @param int $user_guid The user GUID |
||
432 | * |
||
433 | * @return mixed The new setting ID or false |
||
434 | */ |
||
435 | 1 | public function setUserSetting($name, $value, $user_guid = 0) { |
|
436 | 1 | $user = _elgg_services()->entityTable->getUserForPermissionsCheck($user_guid); |
|
437 | 1 | if (!$user instanceof ElggUser) { |
|
438 | return false; |
||
439 | } |
||
440 | |||
441 | 1 | $value = _elgg_services()->hooks->trigger('usersetting', 'plugin', [ |
|
442 | 1 | 'user' => $user, |
|
443 | 1 | 'plugin' => $this, |
|
444 | 1 | 'plugin_id' => $this->getID(), |
|
445 | 1 | 'name' => $name, |
|
446 | 1 | 'value' => $value |
|
447 | 1 | ], $value); |
|
448 | |||
449 | 1 | if (is_array($value)) { |
|
450 | 1 | elgg_log('Plugin user settings cannot store arrays.', 'ERROR'); |
|
451 | |||
452 | 1 | return false; |
|
453 | } |
||
454 | |||
455 | 1 | $name = _elgg_services()->plugins->namespacePrivateSetting('user_setting', $name, $this->getID()); |
|
456 | |||
457 | 1 | return $user->setPrivateSetting($name, $value); |
|
458 | } |
||
459 | |||
460 | /** |
||
461 | * Removes a user setting name and value. |
||
462 | * |
||
463 | * @param string $name The user setting name |
||
464 | * @param int $user_guid The user GUID |
||
465 | * |
||
466 | * @return bool |
||
467 | */ |
||
468 | 1 | public function unsetUserSetting($name, $user_guid = 0) { |
|
469 | 1 | $user = _elgg_services()->entityTable->getUserForPermissionsCheck($user_guid); |
|
470 | |||
471 | 1 | if (!$user instanceof ElggUser) { |
|
472 | return false; |
||
473 | } |
||
474 | |||
475 | 1 | $name = _elgg_services()->plugins->namespacePrivateSetting('user_setting', $name, $this->getID()); |
|
476 | |||
477 | 1 | return $user->removePrivateSetting($name); |
|
478 | } |
||
479 | |||
480 | /** |
||
481 | * Removes all plugin settings for a given user |
||
482 | * |
||
483 | * @param int $user_guid The user GUID to remove user settings. |
||
484 | * |
||
485 | * @return bool |
||
486 | * @throws DatabaseException |
||
487 | */ |
||
488 | 1 | public function unsetAllUserSettings($user_guid = 0) { |
|
489 | 1 | $user = _elgg_services()->entityTable->getUserForPermissionsCheck($user_guid); |
|
490 | |||
491 | 1 | if (!$user instanceof ElggUser) { |
|
492 | return false; |
||
493 | } |
||
494 | |||
495 | 1 | $settings = $this->getAllUserSettings($user_guid); |
|
496 | |||
497 | 1 | foreach ($settings as $name => $value) { |
|
498 | 1 | $name = _elgg_services()->plugins->namespacePrivateSetting('user_setting', $name, $this->getID()); |
|
499 | 1 | $user->removePrivateSetting($name); |
|
500 | } |
||
501 | |||
502 | 1 | return true; |
|
503 | } |
||
504 | |||
505 | /** |
||
506 | * Returns if the plugin is complete, meaning has all required files |
||
507 | * and Elgg can read them and they make sense. |
||
508 | * |
||
509 | * @return bool |
||
510 | */ |
||
511 | 1 | public function isValid() { |
|
512 | 1 | if (!$this->getID()) { |
|
513 | $this->errorMsg = _elgg_services()->translator->translate('ElggPlugin:MissingID', [$this->guid]); |
||
514 | |||
515 | return false; |
||
516 | } |
||
517 | |||
518 | 1 | if (!$this->getPackage() instanceof ElggPluginPackage) { |
|
519 | $this->errorMsg = _elgg_services()->translator->translate('ElggPlugin:NoPluginPackagePackage', [ |
||
520 | $this->getID(), |
||
521 | $this->guid |
||
522 | ]); |
||
523 | |||
524 | return false; |
||
525 | } |
||
526 | |||
527 | 1 | if (!$this->getPackage()->isValid()) { |
|
528 | $this->errorMsg = $this->getPackage()->getError(); |
||
529 | |||
530 | return false; |
||
531 | } |
||
532 | |||
533 | 1 | return true; |
|
534 | } |
||
535 | |||
536 | /** |
||
537 | * Is this plugin active? |
||
538 | * |
||
539 | * @return bool |
||
540 | */ |
||
541 | 78 | public function isActive() { |
|
542 | 78 | if (!$this->guid) { |
|
543 | 1 | return false; |
|
544 | } |
||
545 | |||
546 | 77 | $site = elgg_get_site_entity(); |
|
547 | |||
548 | 77 | if (!($site instanceof \ElggSite)) { |
|
549 | 13 | return false; |
|
550 | } |
||
551 | |||
552 | 77 | return check_entity_relationship($this->guid, 'active_plugin', $site->guid) instanceof ElggRelationship; |
|
553 | } |
||
554 | |||
555 | /** |
||
556 | * Checks if this plugin can be activated on the current |
||
557 | * Elgg installation. |
||
558 | * |
||
559 | * @return bool |
||
560 | */ |
||
561 | 3 | public function canActivate() { |
|
562 | 3 | if ($this->isActive()) { |
|
563 | return false; |
||
564 | } |
||
565 | |||
566 | 3 | if ($this->getPackage()) { |
|
567 | 3 | $result = $this->getPackage()->isValid() && $this->getPackage()->checkDependencies(); |
|
568 | 3 | if (!$result) { |
|
569 | $this->errorMsg = $this->getPackage()->getError(); |
||
570 | } |
||
571 | |||
572 | 3 | return $result; |
|
573 | } |
||
574 | |||
575 | return false; |
||
576 | } |
||
577 | |||
578 | |||
579 | // activating and deactivating |
||
580 | |||
581 | /** |
||
582 | * Actives the plugin for the current site. |
||
583 | * |
||
584 | * @return bool |
||
585 | * @throws PluginException |
||
586 | */ |
||
587 | 3 | public function activate() { |
|
588 | 3 | if ($this->isActive()) { |
|
589 | return false; |
||
590 | } |
||
591 | |||
592 | 3 | if (!$this->canActivate()) { |
|
593 | return false; |
||
594 | } |
||
595 | |||
596 | // Check this before setting status because the file could potentially throw |
||
597 | 3 | if (!$this->isStaticConfigValid()) { |
|
598 | return false; |
||
599 | } |
||
600 | |||
601 | 3 | if (!$this->setStatus(true)) { |
|
602 | return false; |
||
603 | } |
||
604 | |||
605 | // perform tasks and emit events |
||
606 | // emit an event. returning false will make this not be activated. |
||
607 | // we need to do this after it's been fully activated |
||
608 | // or the deactivate will be confused. |
||
609 | $params = [ |
||
610 | 3 | 'plugin_id' => $this->getID(), |
|
611 | 3 | 'plugin_entity' => $this, |
|
612 | ]; |
||
613 | |||
614 | 3 | $return = _elgg_services()->hooks->getEvents()->trigger('activate', 'plugin', $params); |
|
615 | |||
616 | // if there are any on_enable functions, start the plugin now and run them |
||
617 | // Note: this will not run re-run the init hooks! |
||
618 | 3 | if ($return) { |
|
619 | 3 | $this->activateEntities(); |
|
620 | |||
621 | 3 | if ($this->canReadFile('activate.php')) { |
|
622 | _elgg_services()->hooks->getEvents()->trigger('cache:flush', 'system'); |
||
623 | |||
624 | $flags = ELGG_PLUGIN_INCLUDE_START | |
||
625 | ELGG_PLUGIN_REGISTER_CLASSES | |
||
626 | ELGG_PLUGIN_REGISTER_LANGUAGES | |
||
627 | ELGG_PLUGIN_REGISTER_VIEWS | |
||
628 | ELGG_PLUGIN_REGISTER_WIDGETS | |
||
629 | ELGG_PLUGIN_REGISTER_ACTIONS | |
||
630 | ELGG_PLUGIN_REGISTER_ROUTES; |
||
631 | |||
632 | $this->start($flags); |
||
633 | |||
634 | $return = $this->includeFile('activate.php'); |
||
635 | } |
||
636 | } |
||
637 | |||
638 | 3 | if ($return === false) { |
|
639 | $this->deactivate(); |
||
640 | } |
||
641 | |||
642 | 3 | _elgg_services()->plugins->setBootPlugins(null); |
|
643 | |||
644 | 3 | _elgg_services()->logger->notice("Plugin {$this->getID()} has been activated"); |
|
645 | |||
646 | 3 | return $return; |
|
647 | } |
||
648 | |||
649 | /** |
||
650 | * Checks if this plugin can be deactivated on the current |
||
651 | * Elgg installation. Validates that this plugin has no |
||
652 | * active dependants. |
||
653 | * |
||
654 | * @return bool |
||
655 | */ |
||
656 | 1 | public function canDeactivate() { |
|
657 | 1 | if (!$this->isActive()) { |
|
658 | return false; |
||
659 | } |
||
660 | |||
661 | 1 | $dependents = []; |
|
662 | |||
663 | 1 | $active_plugins = elgg_get_plugins(); |
|
664 | |||
665 | 1 | foreach ($active_plugins as $plugin) { |
|
666 | 1 | $manifest = $plugin->getManifest(); |
|
667 | 1 | if (!$manifest) { |
|
668 | return true; |
||
669 | } |
||
670 | 1 | $requires = $manifest->getRequires(); |
|
671 | |||
672 | 1 | foreach ($requires as $required) { |
|
673 | 1 | if ($required['type'] == 'plugin' && $required['name'] == $this->getID()) { |
|
674 | // there are active dependents |
||
675 | 1 | $dependents[$manifest->getPluginID()] = $plugin; |
|
676 | } |
||
677 | } |
||
678 | } |
||
679 | |||
680 | 1 | if (!empty($dependents)) { |
|
681 | $list = array_map(function (\ElggPlugin $plugin) { |
||
682 | $css_id = preg_replace('/[^a-z0-9-]/i', '-', $plugin->getManifest()->getID()); |
||
683 | |||
684 | return elgg_view('output/url', [ |
||
685 | 'text' => $plugin->getDisplayName(), |
||
686 | 'href' => "#$css_id", |
||
687 | ]); |
||
688 | }, $dependents); |
||
689 | $name = $this->getDisplayName(); |
||
690 | $list = implode(', ', $list); |
||
691 | $this->errorMsg = elgg_echo('ElggPlugin:Dependencies:ActiveDependent', [$name, $list]); |
||
692 | |||
693 | return false; |
||
694 | } |
||
695 | |||
696 | 1 | return true; |
|
697 | } |
||
698 | |||
699 | /** |
||
700 | * Deactivates the plugin. |
||
701 | * |
||
702 | * @return bool |
||
703 | * @throws PluginException |
||
704 | */ |
||
705 | 1 | public function deactivate() { |
|
706 | 1 | if (!$this->isActive()) { |
|
707 | return false; |
||
708 | } |
||
709 | |||
710 | 1 | if (!$this->canDeactivate()) { |
|
711 | return false; |
||
712 | } |
||
713 | |||
714 | // emit an event. returning false will cause this to not be deactivated. |
||
715 | $params = [ |
||
716 | 1 | 'plugin_id' => $this->getID(), |
|
717 | 1 | 'plugin_entity' => $this, |
|
718 | ]; |
||
719 | |||
720 | 1 | $return = _elgg_services()->hooks->getEvents()->trigger('deactivate', 'plugin', $params); |
|
721 | 1 | if ($return === false) { |
|
722 | return false; |
||
723 | } |
||
724 | |||
725 | // run any deactivate code |
||
726 | 1 | if ($this->canReadFile('deactivate.php')) { |
|
727 | // allows you to prevent disabling a plugin by returning false in a deactivate.php file |
||
728 | if ($this->includeFile('deactivate.php') === false) { |
||
729 | return false; |
||
730 | } |
||
731 | } |
||
732 | |||
733 | 1 | $this->deactivateEntities(); |
|
734 | |||
735 | 1 | _elgg_services()->hooks->getEvents()->trigger('cache:flush', 'system'); |
|
736 | |||
737 | 1 | _elgg_services()->logger->notice("Plugin {$this->getID()} has been deactivated"); |
|
738 | |||
739 | 1 | _elgg_services()->plugins->setBootPlugins(null); |
|
740 | |||
741 | 1 | return $this->setStatus(false); |
|
742 | } |
||
743 | |||
744 | /** |
||
745 | * Start the plugin. |
||
746 | * |
||
747 | * @param int $flags Start flags for the plugin. See the constants in lib/plugins.php for details. |
||
748 | * |
||
749 | * @return true |
||
750 | * @throws PluginException |
||
751 | * @throws InvalidParameterException |
||
752 | */ |
||
753 | 101 | public function start($flags) { |
|
754 | |||
755 | 101 | if (!($flags & ELGG_PLUGIN_IGNORE_MANIFEST)) { |
|
756 | // Detect plugins errors early and throw so that plugins service can disable the plugin |
||
757 | 34 | if (!$this->getManifest()) { |
|
758 | throw new PluginException($this->getError()); |
||
759 | } |
||
760 | } |
||
761 | |||
762 | // include classes |
||
763 | 101 | if ($flags & ELGG_PLUGIN_REGISTER_CLASSES) { |
|
764 | 101 | $this->registerClasses(); |
|
765 | |||
766 | 101 | $autoload_file = 'vendor/autoload.php'; |
|
767 | 101 | if ($this->canReadFile($autoload_file)) { |
|
768 | Application::requireSetupFileOnce("{$this->getPath()}{$autoload_file}"); |
||
769 | } |
||
770 | } |
||
771 | |||
772 | // include languages |
||
773 | 101 | if ($flags & ELGG_PLUGIN_REGISTER_LANGUAGES) { |
|
774 | // should be loaded before the first function that touches the static config (elgg-plugin.php) |
||
775 | // so translations can be used... for example in registering widgets |
||
776 | 24 | $this->registerLanguages(); |
|
777 | } |
||
778 | |||
779 | // include start file if it exists |
||
780 | 101 | if ($flags & ELGG_PLUGIN_INCLUDE_START) { |
|
781 | 95 | $this->activateEntities(); |
|
782 | |||
783 | 95 | if ($this->canReadFile('start.php')) { |
|
784 | 95 | $result = Application::requireSetupFileOnce("{$this->getPath()}start.php"); |
|
785 | 95 | if ($result instanceof \Closure) { |
|
786 | $result(); |
||
787 | } |
||
788 | } |
||
789 | |||
790 | 95 | $this->registerEntities(); |
|
791 | } |
||
792 | |||
793 | // include views |
||
794 | 101 | if ($flags & ELGG_PLUGIN_REGISTER_VIEWS) { |
|
795 | 85 | $this->registerViews(); |
|
796 | } |
||
797 | |||
798 | // include actions |
||
799 | 101 | if ($flags & ELGG_PLUGIN_REGISTER_ACTIONS) { |
|
800 | 34 | $this->registerActions(); |
|
801 | } |
||
802 | |||
803 | // include routes |
||
804 | 101 | if ($flags & ELGG_PLUGIN_REGISTER_ROUTES) { |
|
805 | 13 | $this->registerRoutes(); |
|
806 | } |
||
807 | |||
808 | // include widgets |
||
809 | 101 | if ($flags & ELGG_PLUGIN_REGISTER_WIDGETS) { |
|
810 | // should load after views because those are used during registration |
||
811 | 34 | $this->registerWidgets(); |
|
812 | } |
||
813 | |||
814 | 101 | return true; |
|
815 | } |
||
816 | |||
817 | /** |
||
818 | * Includes one of the plugins files |
||
819 | * |
||
820 | * @param string $filename The name of the file |
||
821 | * |
||
822 | * @throws PluginException |
||
823 | * @return mixed The return value of the included file (or 1 if there is none) |
||
824 | */ |
||
825 | 85 | protected function includeFile($filename) { |
|
826 | 85 | $filepath = "{$this->getPath()}{$filename}"; |
|
827 | |||
828 | 85 | if (!$this->canReadFile($filename)) { |
|
829 | $msg = _elgg_services()->translator->translate('ElggPlugin:Exception:CannotIncludeFile', |
||
830 | [$filename, $this->getID(), $this->guid, $this->getPath()]); |
||
831 | throw new PluginException($msg); |
||
832 | } |
||
833 | |||
834 | try { |
||
835 | 85 | $ret = Includer::includeFile($filepath); |
|
836 | } catch (Exception $e) { |
||
837 | $msg = _elgg_services()->translator->translate('ElggPlugin:Exception:IncludeFileThrew', |
||
838 | [$filename, $this->getID(), $this->guid, $this->getPath()]); |
||
839 | throw new PluginException($msg, 0, $e); |
||
840 | } |
||
841 | |||
842 | 85 | return $ret; |
|
843 | } |
||
844 | |||
845 | /** |
||
846 | * Checks whether a plugin file with the given name exists |
||
847 | * |
||
848 | * @param string $filename The name of the file |
||
849 | * |
||
850 | * @return bool |
||
851 | */ |
||
852 | 105 | protected function canReadFile($filename) { |
|
853 | 105 | $path = "{$this->getPath()}{$filename}"; |
|
854 | |||
855 | 105 | return is_file($path) && is_readable($path); |
|
856 | } |
||
857 | |||
858 | /** |
||
859 | * If a static config file is present, is it a serializable array? |
||
860 | * |
||
861 | * @return bool |
||
862 | * @throws PluginException |
||
863 | */ |
||
864 | 3 | private function isStaticConfigValid() { |
|
865 | 3 | if (!$this->canReadFile(ElggPluginPackage::STATIC_CONFIG_FILENAME)) { |
|
866 | return true; |
||
867 | } |
||
868 | |||
869 | 3 | ob_start(); |
|
870 | 3 | $value = $this->includeFile(ElggPluginPackage::STATIC_CONFIG_FILENAME); |
|
871 | 3 | if (ob_get_clean() !== '') { |
|
872 | $this->errorMsg = _elgg_services()->translator->translate('ElggPlugin:activate:ConfigSentOutput'); |
||
873 | |||
874 | return false; |
||
875 | } |
||
876 | |||
877 | // make sure can serialize |
||
878 | 3 | $value = @unserialize(serialize($value)); |
|
879 | 3 | if (!is_array($value)) { |
|
880 | $this->errorMsg = _elgg_services()->translator->translate('ElggPlugin:activate:BadConfigFormat'); |
||
881 | |||
882 | return false; |
||
883 | } |
||
884 | |||
885 | 3 | return true; |
|
886 | } |
||
887 | |||
888 | /** |
||
889 | * Registers the plugin's views |
||
890 | * |
||
891 | * @throws PluginException |
||
892 | * @return void |
||
893 | */ |
||
894 | 85 | protected function registerViews() { |
|
895 | 85 | $views = _elgg_services()->views; |
|
896 | |||
897 | // Declared views first |
||
898 | 85 | $file = "{$this->getPath()}views.php"; |
|
899 | 85 | if (is_file($file)) { |
|
900 | $spec = Includer::includeFile($file); |
||
901 | if (is_array($spec)) { |
||
902 | $views->mergeViewsSpec($spec); |
||
903 | } |
||
904 | } |
||
905 | |||
906 | 85 | $spec = $this->getStaticConfig('views'); |
|
907 | 85 | if ($spec) { |
|
908 | 5 | $views->mergeViewsSpec($spec); |
|
909 | } |
||
910 | |||
911 | // Allow /views directory files to override |
||
912 | 85 | if (!$views->registerPluginViews($this->getPath(), $failed_dir)) { |
|
913 | $key = 'ElggPlugin:Exception:CannotRegisterViews'; |
||
914 | $args = [$this->getID(), $this->guid, $failed_dir]; |
||
915 | $msg = _elgg_services()->translator->translate($key, $args); |
||
916 | throw new PluginException($msg); |
||
917 | } |
||
918 | 85 | } |
|
919 | |||
920 | /** |
||
921 | * Registers the plugin's entities |
||
922 | * |
||
923 | * @return void |
||
924 | */ |
||
925 | 95 | protected function registerEntities() { |
|
926 | |||
927 | 95 | $spec = (array) $this->getStaticConfig('entities', []); |
|
928 | 95 | if (empty($spec)) { |
|
929 | 50 | return; |
|
930 | } |
||
931 | |||
932 | 58 | foreach ($spec as $entity) { |
|
933 | 58 | if (isset($entity['type'], $entity['subtype'], $entity['searchable']) && $entity['searchable']) { |
|
934 | 58 | elgg_register_entity_type($entity['type'], $entity['subtype']); |
|
935 | } |
||
936 | } |
||
937 | 58 | } |
|
938 | |||
939 | /** |
||
940 | * Registers the plugin's actions provided in the plugin config file |
||
941 | * |
||
942 | * @return void |
||
943 | */ |
||
944 | 34 | protected function registerActions() { |
|
945 | 34 | self::addActionsFromStaticConfig($this->getStaticConfig('actions', []), $this->getPath()); |
|
946 | 34 | } |
|
947 | |||
948 | /** |
||
949 | * Register a plugin's actions provided in the config file |
||
950 | * |
||
951 | * @todo move to a static config service |
||
952 | * |
||
953 | * @param array $spec 'actions' section of static config |
||
954 | * @param string $root_path Plugin path |
||
955 | * |
||
956 | * @return void |
||
957 | * @access private |
||
958 | * @internal |
||
959 | */ |
||
960 | 34 | public static function addActionsFromStaticConfig(array $spec, $root_path) { |
|
961 | 34 | $actions = _elgg_services()->actions; |
|
962 | 34 | $root_path = rtrim($root_path, '/\\'); |
|
963 | |||
964 | 34 | foreach ($spec as $action => $action_spec) { |
|
965 | 33 | if (!is_array($action_spec)) { |
|
966 | continue; |
||
967 | } |
||
968 | |||
969 | $options = [ |
||
970 | 33 | 'access' => 'logged_in', |
|
971 | 'filename' => '', // assuming core action is registered |
||
972 | ]; |
||
973 | |||
974 | 33 | $options = array_merge($options, $action_spec); |
|
975 | |||
976 | 33 | $filename = "$root_path/actions/{$action}.php"; |
|
977 | 33 | if (is_file($filename)) { |
|
978 | 33 | $options['filename'] = $filename; |
|
979 | } |
||
980 | |||
981 | 33 | $actions->register($action, $options['filename'], $options['access']); |
|
982 | } |
||
983 | 34 | } |
|
984 | |||
985 | /** |
||
986 | * Registers the plugin's routes provided in the plugin config file |
||
987 | * |
||
988 | * @throws PluginException |
||
989 | * @return void |
||
990 | */ |
||
991 | 13 | protected function registerRoutes() { |
|
992 | 13 | $router = _elgg_services()->router; |
|
993 | |||
994 | 13 | $spec = (array) $this->getStaticConfig('routes', []); |
|
995 | |||
996 | 13 | foreach ($spec as $name => $route_spec) { |
|
997 | 13 | if (!is_array($route_spec)) { |
|
998 | continue; |
||
999 | } |
||
1000 | |||
1001 | 13 | $router->registerRoute($name, $route_spec); |
|
1002 | } |
||
1003 | 13 | } |
|
1004 | |||
1005 | /** |
||
1006 | * Registers the plugin's widgets provided in the plugin config file |
||
1007 | * |
||
1008 | * @return void |
||
1009 | * @throws \InvalidParameterException |
||
1010 | */ |
||
1011 | 34 | protected function registerWidgets() { |
|
1012 | 34 | $widgets = _elgg_services()->widgets; |
|
1013 | |||
1014 | 34 | $spec = (array) $this->getStaticConfig('widgets', []); |
|
1015 | 34 | foreach ($spec as $widget_id => $widget_definition) { |
|
1016 | 24 | if (!is_array($widget_definition)) { |
|
1017 | continue; |
||
1018 | } |
||
1019 | 24 | if (!isset($widget_definition['id'])) { |
|
1020 | 24 | $widget_definition['id'] = $widget_id; |
|
1021 | } |
||
1022 | |||
1023 | 24 | $definition = \Elgg\WidgetDefinition::factory($widget_definition); |
|
1024 | |||
1025 | 24 | $widgets->registerType($definition); |
|
1026 | } |
||
1027 | 34 | } |
|
1028 | |||
1029 | /** |
||
1030 | * Registers the plugin's languages |
||
1031 | * |
||
1032 | * @return true |
||
1033 | */ |
||
1034 | 24 | protected function registerLanguages() { |
|
1035 | 24 | return _elgg_services()->translator->registerPluginTranslations($this->getPath()); |
|
1036 | } |
||
1037 | |||
1038 | /** |
||
1039 | * Registers the plugin's classes |
||
1040 | * |
||
1041 | * @return true |
||
1042 | */ |
||
1043 | 101 | protected function registerClasses() { |
|
1044 | 101 | $classes_path = "{$this->getPath()}classes"; |
|
1045 | |||
1046 | 101 | if (is_dir($classes_path)) { |
|
1047 | 77 | _elgg_services()->autoloadManager->addClasses($classes_path); |
|
1048 | } |
||
1049 | |||
1050 | 101 | return true; |
|
1051 | } |
||
1052 | |||
1053 | /** |
||
1054 | * Activates the plugin's entities |
||
1055 | * |
||
1056 | * @return void |
||
1057 | */ |
||
1058 | 97 | protected function activateEntities() { |
|
1059 | 97 | $spec = (array) $this->getStaticConfig('entities', []); |
|
1060 | 97 | if (empty($spec)) { |
|
1061 | 50 | return; |
|
1062 | } |
||
1063 | |||
1064 | 60 | foreach ($spec as $entity) { |
|
1065 | 60 | if (isset($entity['type'], $entity['subtype'], $entity['class'])) { |
|
1066 | 60 | elgg_set_entity_class($entity['type'], $entity['subtype'], $entity['class']); |
|
1067 | } |
||
1068 | } |
||
1069 | 60 | } |
|
1070 | |||
1071 | /** |
||
1072 | * Deactivates the plugin's entities |
||
1073 | * |
||
1074 | * @return void |
||
1075 | */ |
||
1076 | 1 | protected function deactivateEntities() { |
|
1077 | 1 | $spec = (array) $this->getStaticConfig('entities', []); |
|
1078 | 1 | if (empty($spec)) { |
|
1079 | 1 | return; |
|
1080 | } |
||
1081 | |||
1082 | foreach ($spec as $entity) { |
||
1083 | if (isset($entity['type'], $entity['subtype'], $entity['class'])) { |
||
1084 | elgg_set_entity_class($entity['type'], $entity['subtype']); |
||
1085 | } |
||
1086 | } |
||
1087 | } |
||
1088 | |||
1089 | /** |
||
1090 | * Get an attribute, metadata or private setting value |
||
1091 | * |
||
1092 | * @param string $name Name of the attribute or private setting |
||
1093 | * |
||
1094 | * @return mixed |
||
1095 | */ |
||
1096 | 352 | public function __get($name) { |
|
1097 | // See if its in our base attribute |
||
1098 | 352 | if (array_key_exists($name, $this->attributes)) { |
|
1099 | 352 | return $this->attributes[$name]; |
|
1100 | } |
||
1101 | |||
1102 | // object title and description are stored as metadata |
||
1103 | 314 | if (in_array($name, ['title', 'description'])) { |
|
1104 | 314 | return parent::__get($name); |
|
1105 | } |
||
1106 | |||
1107 | 3 | $result = $this->getPrivateSetting($name); |
|
1108 | 3 | if ($result !== null) { |
|
1109 | 1 | return $result; |
|
1110 | } |
||
1111 | |||
1112 | 2 | $defaults = $this->getStaticConfig('settings', []); |
|
1113 | |||
1114 | 2 | return elgg_extract($name, $defaults, $result); |
|
1115 | } |
||
1116 | |||
1117 | /** |
||
1118 | * Set a value as attribute, metadata or private setting. |
||
1119 | * |
||
1120 | * Metadata applies to title and description. |
||
1121 | * |
||
1122 | * @param string $name Name of the attribute or private_setting |
||
1123 | * @param mixed $value Value to be set |
||
1124 | * |
||
1125 | * @return void |
||
1126 | */ |
||
1127 | 288 | public function __set($name, $value) { |
|
1128 | 288 | if (array_key_exists($name, $this->attributes)) { |
|
1129 | // Check that we're not trying to change the guid! |
||
1130 | 1 | if ((array_key_exists('guid', $this->attributes)) && ($name == 'guid')) { |
|
1131 | return; |
||
1132 | } |
||
1133 | |||
1134 | 1 | $this->attributes[$name] = $value; |
|
1135 | |||
1136 | 1 | return; |
|
1137 | } |
||
1138 | |||
1139 | // object title and description are stored as metadata |
||
1140 | 288 | if (in_array($name, ['title', 'description'])) { |
|
1141 | 288 | parent::__set($name, $value); |
|
1142 | |||
1143 | 288 | return; |
|
1144 | } |
||
1145 | |||
1146 | // to make sure we trigger the correct hooks |
||
1147 | 2 | $this->setSetting($name, $value); |
|
1148 | 2 | } |
|
1149 | |||
1150 | /** |
||
1151 | * Sets the plugin to active or inactive. |
||
1152 | * |
||
1153 | * @param bool $active Set to active or inactive |
||
1154 | * |
||
1155 | * @return bool |
||
1156 | */ |
||
1157 | 3 | private function setStatus($active) { |
|
1158 | 3 | if (!$this->guid) { |
|
1159 | return false; |
||
1160 | } |
||
1161 | |||
1162 | 3 | $site = elgg_get_site_entity(); |
|
1163 | 3 | if ($active) { |
|
1164 | 3 | $result = add_entity_relationship($this->guid, 'active_plugin', $site->guid); |
|
1165 | } else { |
||
1166 | 1 | $result = remove_entity_relationship($this->guid, 'active_plugin', $site->guid); |
|
1167 | } |
||
1168 | |||
1169 | 3 | $this->invalidateCache(); |
|
1170 | |||
1171 | 3 | return $result; |
|
1172 | } |
||
1173 | |||
1174 | /** |
||
1175 | * Returns the last error message registered. |
||
1176 | * |
||
1177 | * @return string|null |
||
1178 | */ |
||
1179 | public function getError() { |
||
1180 | return $this->errorMsg; |
||
1181 | } |
||
1182 | |||
1183 | /** |
||
1184 | * Returns this plugin's \ElggPluginManifest object |
||
1185 | * |
||
1186 | * @return ElggPluginManifest|null |
||
1187 | */ |
||
1188 | 224 | public function getManifest() { |
|
1189 | 224 | if ($this->manifest instanceof ElggPluginManifest) { |
|
1190 | 17 | return $this->manifest; |
|
1191 | } |
||
1192 | |||
1193 | try { |
||
1194 | 211 | $package = $this->getPackage(); |
|
1195 | 211 | if (!$package) { |
|
1196 | 1 | throw new PluginException('Package cannot be loaded'); |
|
1197 | } |
||
1198 | 210 | $this->manifest = $package->getManifest(); |
|
1199 | |||
1200 | 210 | return $this->manifest; |
|
1201 | 1 | } catch (PluginException $e) { |
|
1202 | 1 | _elgg_services()->logger->warn("Failed to load manifest for plugin $this->guid. " . $e->getMessage()); |
|
1203 | 1 | $this->errorMsg = $e->getmessage(); |
|
1204 | } |
||
1205 | 1 | } |
|
1206 | |||
1207 | /** |
||
1208 | * Returns this plugin's \ElggPluginPackage object |
||
1209 | * |
||
1210 | * @return ElggPluginPackage|null |
||
1211 | */ |
||
1212 | 214 | public function getPackage() { |
|
1213 | 214 | if ($this->package instanceof ElggPluginPackage) { |
|
1214 | 4 | return $this->package; |
|
1215 | } |
||
1216 | |||
1217 | try { |
||
1218 | 213 | $this->package = new ElggPluginPackage($this->getPath(), false); |
|
1219 | |||
1220 | 212 | return $this->package; |
|
1221 | 1 | } catch (Exception $e) { |
|
1222 | 1 | _elgg_services()->logger->warn("Failed to load package for $this->guid. " . $e->getMessage()); |
|
1223 | 1 | $this->errorMsg = $e->getmessage(); |
|
1224 | } |
||
1225 | 1 | } |
|
1226 | |||
1227 | /** |
||
1228 | * {@inheritdoc} |
||
1229 | */ |
||
1230 | 308 | public function isCacheable() { |
|
1231 | 308 | return true; |
|
1232 | } |
||
1233 | |||
1234 | /** |
||
1235 | * {@inheritdoc} |
||
1236 | */ |
||
1237 | 308 | public function cache($persist = true) { |
|
1238 | 308 | _elgg_services()->plugins->cache($this); |
|
1239 | |||
1240 | 308 | return parent::cache($persist); |
|
0 ignored issues
–
show
|
|||
1241 | } |
||
1242 | |||
1243 | /** |
||
1244 | * {@inheritdoc} |
||
1245 | */ |
||
1246 | 289 | public function invalidateCache() { |
|
1247 | 289 | _elgg_services()->plugins->invalidateCache($this->getID()); |
|
1248 | |||
1249 | 289 | return parent::invalidateCache(); |
|
0 ignored issues
–
show
Are you sure the usage of
parent::invalidateCache() targeting ElggEntity::invalidateCache() seems to always return null.
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.
Loading history...
|
|||
1250 | } |
||
1251 | } |
||
1252 |
This check looks for function or method calls that always return null and whose return value is used.
The method
getObject()
can return nothing but null, so it makes no sense to use the return value.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.