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