Test Failed
Push — master ( 8c47c2...3acf9f )
by Steve
12:37
created

engine/classes/Elgg/Database/Plugins.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
namespace Elgg\Database;
3
4
use Elgg\Cache\Pool;
5
use Elgg\Profilable;
6
use Exception;
7
use Elgg\Cache\PluginSettingsCache;
8
9
/**
10
 * Persistent, installation-wide key-value storage.
11
 *
12
 * WARNING: API IN FLUX. DO NOT USE DIRECTLY.
13
 *
14
 * @access private
15
 *
16
 * @since 1.10.0
17
 */
18
class Plugins {
19
	use Profilable;
20
21
	/**
22
	 * @var \ElggPlugin[]
23
	 */
24
	private $boot_plugins = [];
25
26
	/**
27
	 * @var array|null
28
	 */
29
	private $provides_cache;
30
31
	/**
32
	 * @var string[] Active plugins, with plugin ID => GUID. Missing keys imply inactive plugins.
33
	 */
34
	private $active_guids = [];
35
36
	/**
37
	 * @var bool Has $active_guids been populated?
38
	 */
39
	private $active_guids_known = false;
40
41
	/**
42
	 * @var Pool
43
	 */
44
	private $plugins_by_id;
45
46
	/**
47
	 * @var PluginSettingsCache
48
	 */
49
	private $settings_cache;
50
51
	/**
52
	 * Constructor
53
	 *
54
	 * @param Pool                $pool  Cache for referencing plugins by ID
55
	 * @param PluginSettingsCache $cache Plugin settings cache
56
	 */
57 8
	public function __construct(Pool $pool, PluginSettingsCache $cache) {
58 8
		$this->plugins_by_id = $pool;
59 8
		$this->settings_cache = $cache;
60 8
	}
61
62
	/**
63
	 * Set the list of active plugins according to the boot data cache
64
	 *
65
	 * @param \ElggPlugin[] $plugins Set of active plugins
66
	 * @return void
67
	 */
68
	public function setBootPlugins(array $plugins) {
69
		$this->boot_plugins = $plugins;
70
		foreach ($plugins as $plugin) {
71
			$this->plugins_by_id->put($plugin->getID(), $plugin);
72
		}
73
	}
74
75
	/**
76
	 * Returns a list of plugin directory names from a base directory.
77
	 *
78
	 * @param string $dir A dir to scan for plugins. Defaults to config's plugins_path.
79
	 *                    Must have a trailing slash.
80
	 *
81
	 * @return array Array of directory names (not full paths)
82
	 * @access private
83
	 */
84
	function getDirsInDir($dir = null) {
85
		if (!$dir) {
86
			$dir = elgg_get_plugins_path();
87
		}
88
	
89
		$plugin_dirs = [];
90
		$handle = opendir($dir);
91
	
92
		if ($handle) {
93
			while ($plugin_dir = readdir($handle)) {
94
				// must be directory and not begin with a .
95
				if (substr($plugin_dir, 0, 1) !== '.' && is_dir($dir . $plugin_dir)) {
96
					$plugin_dirs[] = $plugin_dir;
97
				}
98
			}
99
		}
100
	
101
		sort($plugin_dirs);
102
	
103
		return $plugin_dirs;
104
	}
105
	
106
	/**
107
	 * Discovers plugins in the plugins_path setting and creates \ElggPlugin
108
	 * entities for them if they don't exist.  If there are plugins with entities
109
	 * but not actual files, will disable the \ElggPlugin entities and mark as inactive.
110
	 * The \ElggPlugin object holds config data, so don't delete.
111
	 *
112
	 * @return bool
113
	 * @access private
114
	 */
115
	function generateEntities() {
116
	
117
		$mod_dir = elgg_get_plugins_path();
118
		$db_prefix = _elgg_config()->dbprefix;
119
	
120
		// ignore access in case this is called with no admin logged in - needed for creating plugins perhaps?
121
		$old_ia = elgg_set_ignore_access(true);
122
	
123
		// show hidden entities so that we can enable them if appropriate
124
		$old_access = access_show_hidden_entities(true);
125
	
126
		$known_plugins = elgg_get_entities_from_relationship([
127
			'type' => 'object',
128
			'subtype' => 'plugin',
129
			'selects' => ['plugin_oe.*'],
130
			'joins' => ["JOIN {$db_prefix}objects_entity plugin_oe on plugin_oe.guid = e.guid"],
131
			'limit' => ELGG_ENTITIES_NO_VALUE,
132
		]);
133
		/* @var \ElggPlugin[] $known_plugins */
134
	
135
		if (!$known_plugins) {
136
			$known_plugins = [];
137
		}
138
	
139
		// map paths to indexes
140
		$id_map = [];
141
		foreach ($known_plugins as $i => $plugin) {
142
			// if the ID is wrong, delete the plugin because we can never load it.
143
			$id = $plugin->getID();
144
			if (!$id) {
145
				$plugin->delete();
146
				unset($known_plugins[$i]);
147
				continue;
148
			}
149
			$id_map[$plugin->getID()] = $i;
150
		}
151
	
152
		$physical_plugins = $this->getDirsInDir($mod_dir);
153
		if (!$physical_plugins) {
154
			return false;
155
		}
156
	
157
		// check real plugins against known ones
158
		foreach ($physical_plugins as $plugin_id) {
159
			// is this already in the db?
160
			if (array_key_exists($plugin_id, $id_map)) {
161
				$index = $id_map[$plugin_id];
162
				$plugin = $known_plugins[$index];
163
				// was this plugin deleted and its entity disabled?
164
				if (!$plugin->isEnabled()) {
165
					$plugin->enable();
166
					$plugin->deactivate();
167
					$plugin->setPriority('last');
168
				}
169
	
170
				// remove from the list of plugins to disable
171
				unset($known_plugins[$index]);
172
			} else {
173
				// create new plugin
174
				// priority is forced to last in save() if not set.
175
				$plugin = new \ElggPlugin($mod_dir . $plugin_id);
176
				$plugin->save();
177
			}
178
		}
179
	
180
		// everything remaining in $known_plugins needs to be disabled
181
		// because they are entities, but their dirs were removed.
182
		// don't delete the entities because they hold settings.
183
		foreach ($known_plugins as $plugin) {
184
			if ($plugin->isActive()) {
185
				$plugin->deactivate();
186
			}
187
			// remove the priority.
188
			$name = $this->namespacePrivateSetting('internal', 'priority');
189
			remove_private_setting($plugin->guid, $name);
190
			if ($plugin->isEnabled()) {
191
				$plugin->disable();
192
			}
193
		}
194
	
195
		access_show_hidden_entities($old_access);
196
		elgg_set_ignore_access($old_ia);
197
	
198
		return true;
199
	}
200
	
201
	/**
202
	 * Cache a reference to this plugin by its ID
203
	 *
204
	 * @param \ElggPlugin $plugin
205
	 *
206
	 * @access private
207
	 */
208
	function cache(\ElggPlugin $plugin) {
209
		$this->plugins_by_id->put($plugin->getID(), $plugin);
210
	}
211
	
212
	/**
213
	 * Returns an \ElggPlugin object with the path $path.
214
	 *
215
	 * @param string $plugin_id The id (dir name) of the plugin. NOT the guid.
216
	 * @return \ElggPlugin|null
217
	 */
218
	function get($plugin_id) {
219
		return $this->plugins_by_id->get($plugin_id, function () use ($plugin_id) {
220
			$plugin_id = sanitize_string($plugin_id);
221
			$db_prefix = _elgg_config()->dbprefix;
222
223
			$options = [
224
				'type' => 'object',
225
				'subtype' => 'plugin',
226
				'joins' => ["JOIN {$db_prefix}objects_entity oe on oe.guid = e.guid"],
227
				'selects' => ["oe.title", "oe.description"],
228
				'wheres' => ["oe.title = '$plugin_id'"],
229
				'limit' => 1,
230
				'distinct' => false,
231
			];
232
233
			$plugins = elgg_get_entities($options);
234
235
			if ($plugins) {
236
				return $plugins[0];
237
			}
238
239
			return null;
240
		});
241
	}
242
	
243
	/**
244
	 * Returns if a plugin exists in the system.
245
	 *
246
	 * @warning This checks only plugins that are registered in the system!
247
	 * If the plugin cache is outdated, be sure to regenerate it with
248
	 * {@link _elgg_generate_plugin_objects()} first.
249
	 *
250
	 * @param string $id The plugin ID.
251
	 * @return bool
252
	 */
253
	function exists($id) {
254
		return (bool) $this->get($id);
255
	}
256
	
257
	/**
258
	 * Returns the highest priority of the plugins
259
	 *
260
	 * @return int
261
	 * @access private
262
	 */
263
	function getMaxPriority() {
264
		$db_prefix = _elgg_config()->dbprefix;
265
		$priority = $this->namespacePrivateSetting('internal', 'priority');
266
		$plugin_subtype = get_subtype_id('object', 'plugin');
267
	
268
		$q = "SELECT MAX(CAST(ps.value AS unsigned)) as max
269
			FROM {$db_prefix}entities e, {$db_prefix}private_settings ps
270
			WHERE ps.name = '$priority'
271
			AND ps.entity_guid = e.guid
272
			AND e.type = 'object' and e.subtype = $plugin_subtype";
273
	
274
		$data = get_data($q);
275
		if ($data) {
276
			$max = $data[0]->max;
277
		} else {
278
			$max = 1;
279
		}
280
	
281
		// can't have a priority of 0.
282
		return ($max) ? $max : 1;
283
	}
284
	
285
	/**
286
	 * Returns if a plugin is active for a current site.
287
	 *
288
	 * @param string $plugin_id The plugin ID
289
	 * @return bool
290
	 */
291
	function isActive($plugin_id) {
292
		if ($this->active_guids_known) {
293
			return isset($this->active_guids[$plugin_id]);
294
		}
295
296
		$site = elgg_get_site_entity();
297
	
298
		if (!($site instanceof \ElggSite)) {
299
			return false;
300
		}
301
	
302
		$plugin = $this->get($plugin_id);
303
	
304
		if (!$plugin) {
305
			return false;
306
		}
307
	
308
		return $plugin->isActive($site->guid);
309
	}
310
	
311
	/**
312
	 * Loads all active plugins in the order specified in the tool admin panel.
313
	 *
314
	 * @note This is called on every page load. If a plugin is active and problematic, it
315
	 * will be disabled and a visible error emitted. This does not check the deps system because
316
	 * that was too slow.
317
	 *
318
	 * @return bool
319
	 * @access private
320
	 */
321
	function load() {
322
		if ($this->timer) {
323
			$this->timer->begin([__METHOD__]);
324
		}
325
326
		$plugins_path = elgg_get_plugins_path();
327
		$start_flags = ELGG_PLUGIN_INCLUDE_START |
328
						ELGG_PLUGIN_REGISTER_VIEWS |
329
						ELGG_PLUGIN_REGISTER_ACTIONS |
330
						ELGG_PLUGIN_REGISTER_LANGUAGES |
331
						ELGG_PLUGIN_REGISTER_WIDGETS |
332
						ELGG_PLUGIN_REGISTER_CLASSES;
333
	
334
		if (!$plugins_path) {
335
			return false;
336
		}
337
	
338
		// temporary disable all plugins if there is a file called 'disabled' in the plugin dir
339
		if (file_exists("$plugins_path/disabled")) {
340
			if (elgg_is_admin_logged_in() && elgg_in_context('admin')) {
341
				system_message(_elgg_services()->translator->translate('plugins:disabled'));
342
			}
343
			return false;
344
		}
345
346
		$config = _elgg_config();
347
	
348
		if ($config->system_cache_loaded) {
349
			$start_flags = $start_flags & ~ELGG_PLUGIN_REGISTER_VIEWS;
350
		}
351
	
352
		if (!empty($GLOBALS['_ELGG']->i18n_loaded_from_cache)) {
353
			$start_flags = $start_flags & ~ELGG_PLUGIN_REGISTER_LANGUAGES;
354
		}
355
	
356
		$plugins = $this->boot_plugins;
357
		if (!$plugins) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $plugins of type ElggPlugin[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
358
			$this->active_guids_known = true;
359
			return true;
360
		}
361
362
		$return = true;
363
		foreach ($plugins as $plugin) {
364
			$id = $plugin->getID();
365
			try {
366
				$plugin->start($start_flags);
367
				$this->active_guids[$id] = $plugin->guid;
368
			} catch (Exception $e) {
369
				$disable_plugins = _elgg_config()->auto_disable_plugins;
370
				if ($disable_plugins === null) {
371
					$disable_plugins = true;
372
				}
373
				if ($disable_plugins) {
374
					$plugin->deactivate();
375
				
376
					$msg = _elgg_services()->translator->translate('PluginException:CannotStart',
377
									[$id, $plugin->guid, $e->getMessage()]);
378
					elgg_add_admin_notice("cannot_start $id", $msg);
379
					$return = false;
380
				}
381
			}
382
		}
383
384
		$this->active_guids_known = true;
385
386
		if ($this->timer) {
387
			$this->timer->end([__METHOD__]);
388
		}
389
		return $return;
390
	}
391
	
392
	/**
393
	 * Returns an ordered list of plugins
394
	 *
395
	 * @param string $status The status of the plugins. active, inactive, or all.
396
	 * @return \ElggPlugin[]
397
	 */
398
	function find($status = 'active') {
399
		$db_prefix = elgg_get_config('dbprefix');
400
		$priority = $this->namespacePrivateSetting('internal', 'priority');
401
		$site_guid = 1;
402
		
403
		// grab plugins
404
		$options = [
405
			'type' => 'object',
406
			'subtype' => 'plugin',
407
			'limit' => ELGG_ENTITIES_NO_VALUE,
408
			'selects' => ['plugin_oe.*', 'ps.value'],
409
			'joins' => [
410
				"JOIN {$db_prefix}private_settings ps on ps.entity_guid = e.guid",
411
				"JOIN {$db_prefix}objects_entity plugin_oe on plugin_oe.guid = e.guid"
412
				],
413
			'wheres' => ["ps.name = '$priority'"],
414
			// ORDER BY CAST(ps.value) is super slow. We usort() below.
415
			'order_by' => false,
416
			'distinct' => false,
417
		];
418
	
419
		switch ($status) {
420
			case 'active':
421
				$options['relationship'] = 'active_plugin';
422
				$options['relationship_guid'] = $site_guid;
423
				$options['inverse_relationship'] = true;
424
				break;
425
	
426
			case 'inactive':
427
				$options['wheres'][] = "NOT EXISTS (
428
						SELECT 1 FROM {$db_prefix}entity_relationships active_er
429
						WHERE active_er.guid_one = e.guid
430
							AND active_er.relationship = 'active_plugin'
431
							AND active_er.guid_two = $site_guid)";
432
				break;
433
	
434
			case 'all':
435
			default:
436
				break;
437
		}
438
	
439
		$old_ia = elgg_set_ignore_access(true);
440
		$plugins = elgg_get_entities_from_relationship($options);
441
		elgg_set_ignore_access($old_ia);
442
443
		usort($plugins, function (\ElggPlugin $a, \ElggPlugin $b) {
444
			$a_value = $a->getVolatileData('select:value');
445
			$b_value = $b->getVolatileData('select:value');
446
447
			if ($b_value !== $a_value) {
448
				return $a_value - $b_value;
449
			} else {
450
				return $a->guid - $b->guid;
451
			}
452
		});
453
	
454
		return $plugins;
455
	}
456
	
457
	/**
458
	 * Reorder plugins to an order specified by the array.
459
	 * Plugins not included in this array will be appended to the end.
460
	 *
461
	 * @note This doesn't use the \ElggPlugin->setPriority() method because
462
	 *       all plugins are being changed and we don't want it to automatically
463
	 *       reorder plugins.
464
	 * @todo Can this be done in a single sql command?
465
	 *
466
	 * @param array $order An array of plugin ids in the order to set them
467
	 * @return bool
468
	 * @access private
469
	 */
470
	function setPriorities(array $order) {
471
		$name = $this->namespacePrivateSetting('internal', 'priority');
472
	
473
		$plugins = $this->find('any');
474
		if (!$plugins) {
475
			return false;
476
		}
477
	
478
		// reindex to get standard counting. no need to increment by 10.
479
		// though we do start with 1
480
		$order = array_values($order);
481
	
482
		$missing_plugins = [];
483
		/* @var \ElggPlugin[] $missing_plugins */
484
	
485
		$priority = 0;
486
		foreach ($plugins as $plugin) {
487
			$plugin_id = $plugin->getID();
488
	
489
			if (!in_array($plugin_id, $order)) {
490
				$missing_plugins[] = $plugin;
491
				continue;
492
			}
493
	
494
			$priority = array_search($plugin_id, $order) + 1;
495
	
496
			if (!$plugin->setPrivateSetting($name, $priority)) {
497
				return false;
498
			}
499
		}
500
	
501
		// set the missing plugins' priorities
502
		if (empty($missing_plugins)) {
503
			return true;
504
		}
505
		
506
		foreach ($missing_plugins as $plugin) {
507
			$priority++;
508
			if (!$plugin->setPrivateSetting($name, $priority)) {
509
				return false;
510
			}
511
		}
512
	
513
		return true;
514
	}
515
	
516
	/**
517
	 * Reindexes all plugin priorities starting at 1.
518
	 *
519
	 * @return bool
520
	 * @access private
521
	 */
522
	function reindexPriorities() {
523
		return $this->setPriorities([]);
524
	}
525
	
526
	/**
527
	 * Namespaces a string to be used as a private setting name for a plugin.
528
	 *
529
	 * For user_settings, two namespaces are added: a user setting namespace and the
530
	 * plugin id.
531
	 *
532
	 * For internal (plugin priority), there is a single internal namespace added.
533
	 *
534
	 * @param string $type The type of setting: user_setting or internal.
535
	 * @param string $name The name to namespace.
536
	 * @param string $id   The plugin's ID to namespace with.  Required for user_setting.
537
	 * @return string
538
	 * @access private
539
	 */
540
	function namespacePrivateSetting($type, $name, $id = null) {
541
		switch ($type) {
542
			// commented out because it breaks $plugin->$name access to variables
543
			//case 'setting':
544
			//	$name = ELGG_PLUGIN_SETTING_PREFIX . $name;
545
			//	break;
546
	
547
			case 'user_setting':
548
				if (!$id) {
549
					throw new \InvalidArgumentException("You must pass the plugin id for user settings");
550
				}
551
				$name = ELGG_PLUGIN_USER_SETTING_PREFIX . "$id:$name";
552
				break;
553
	
554
			case 'internal':
555
				$name = ELGG_PLUGIN_INTERNAL_PREFIX . $name;
556
				break;
557
		}
558
	
559
		return $name;
560
	}
561
	
562
	
563
	/**
564
	 * Returns an array of all provides from all active plugins.
565
	 *
566
	 * Array in the form array(
567
	 * 	'provide_type' => array(
568
	 * 		'provided_name' => array(
569
	 * 			'version' => '1.8',
570
	 * 			'provided_by' => 'provider_plugin_id'
571
	 *  	)
572
	 *  )
573
	 * )
574
	 *
575
	 * @param string $type The type of provides to return
576
	 * @param string $name A specific provided name to return. Requires $provide_type.
577
	 *
578
	 * @return array
579
	 * @access private
580
	 */
581
	function getProvides($type = null, $name = null) {
582
		if ($this->provides_cache === null) {
583
			$active_plugins = $this->find('active');
584
		
585
			$provides = [];
586
	
587
			foreach ($active_plugins as $plugin) {
588
				$plugin_provides = [];
589
				$manifest = $plugin->getManifest();
590
				if ($manifest instanceof \ElggPluginManifest) {
591
					$plugin_provides = $plugin->getManifest()->getProvides();
592
				}
593
				if ($plugin_provides) {
594
					foreach ($plugin_provides as $provided) {
595
						$provides[$provided['type']][$provided['name']] = [
596
							'version' => $provided['version'],
597
							'provided_by' => $plugin->getID()
598
						];
599
					}
600
				}
601
			}
602
			
603
			$this->provides_cache = $provides;
604
		}
605
		
606
		if ($type && $name) {
607 View Code Duplication
			if (isset($this->provides_cache[$type][$name])) {
608
				return $this->provides_cache[$type][$name];
609
			} else {
610
				return false;
611
			}
612 View Code Duplication
		} elseif ($type) {
613
			if (isset($this->provides_cache[$type])) {
614
				return $this->provides_cache[$type];
615
			} else {
616
				return false;
617
			}
618
		}
619
	
620
		return $this->provides_cache;
621
	}
622
	
623
	/**
624
	 * Deletes all cached data on plugins being provided.
625
	 *
626
	 * @return boolean
627
	 * @access private
628
	 */
629
	function invalidateProvidesCache() {
630
		$this->provides_cache = null;
631
		return true;
632
	}
633
634
	/**
635
	 * Delete the cache holding whether plugins are active or not
636
	 *
637
	 * @return void
638
	 * @access private
639
	 */
640
	public function invalidateIsActiveCache() {
641
		$this->active_guids = [];
642
		$this->active_guids_known = false;
643
	}
644
	
645
	/**
646
	 * Checks if a plugin is currently providing $type and $name, and optionally
647
	 * checking a version.
648
	 *
649
	 * @param string $type       The type of the provide
650
	 * @param string $name       The name of the provide
651
	 * @param string $version    A version to check against
652
	 * @param string $comparison The comparison operator to use in version_compare()
653
	 *
654
	 * @return array An array in the form array(
655
	 * 	'status' => bool Does the provide exist?,
656
	 * 	'value' => string The version provided
657
	 * )
658
	 * @access private
659
	 */
660
	function checkProvides($type, $name, $version = null, $comparison = 'ge') {
661
		$provided = $this->getProvides($type, $name);
662
		if (!$provided) {
663
			return [
664
				'status' => false,
665
				'value' => ''
666
			];
667
		}
668
	
669
		if ($version) {
670
			$status = version_compare($provided['version'], $version, $comparison);
671
		} else {
672
			$status = true;
673
		}
674
	
675
		return [
676
			'status' => $status,
677
			'value' => $provided['version']
678
		];
679
	}
680
	
681
	/**
682
	 * Returns an array of parsed strings for a dependency in the
683
	 * format: array(
684
	 * 	'type'			=>	requires, conflicts, or provides.
685
	 * 	'name'			=>	The name of the requirement / conflict
686
	 * 	'value'			=>	A string representing the expected value: <1, >=3, !=enabled
687
	 * 	'local_value'	=>	The current value, ("Not installed")
688
	 * 	'comment'		=>	Free form text to help resovle the problem ("Enable / Search for plugin <link>")
689
	 * )
690
	 *
691
	 * @param array $dep An \ElggPluginPackage dependency array
692
	 * @return array
693
	 * @access private
694
	 */
695
	function getDependencyStrings($dep) {
696
		$translator = _elgg_services()->translator;
697
		$dep_system = elgg_extract('type', $dep);
698
		$info = elgg_extract('dep', $dep);
699
		$type = elgg_extract('type', $info);
700
	
701
		if (!$dep_system || !$info || !$type) {
702
			return false;
703
		}
704
	
705
		// rewrite some of these to be more readable
706
		$comparison = elgg_extract('comparison', $info);
707
		switch ($comparison) {
708
			case 'lt':
709
				$comparison = '<';
710
				break;
711
			case 'gt':
712
				$comparison = '>';
713
				break;
714
			case 'ge':
715
				$comparison = '>=';
716
				break;
717
			case 'le':
718
				$comparison = '<=';
719
				break;
720
			default:
721
				//keep $comparison value intact
722
				break;
723
		}
724
	
725
		/*
726
		'requires'	'plugin oauth_lib'	<1.3	1.3		'downgrade'
727
		'requires'	'php setting bob'	>3		3		'change it'
728
		'conflicts'	'php setting'		>3		4		'change it'
729
		'conflicted''plugin profile'	any		1.8		'disable profile'
730
		'provides'	'plugin oauth_lib'	1.3		--		--
731
		'priority'	'before blog'		--		after	'move it'
732
		*/
733
		$strings = [];
734
		$strings['type'] = $translator->translate('ElggPlugin:Dependencies:' . ucwords($dep_system));
735
	
736
		switch ($type) {
737 View Code Duplication
			case 'elgg_release':
738
				// 'Elgg Version'
739
				$strings['name'] = $translator->translate('ElggPlugin:Dependencies:Elgg');
740
				$strings['expected_value'] = "$comparison {$info['version']}";
741
				$strings['local_value'] = $dep['value'];
742
				$strings['comment'] = '';
743
				break;
744
	
745 View Code Duplication
			case 'php_version':
746
				// 'PHP version'
747
				$strings['name'] = $translator->translate('ElggPlugin:Dependencies:PhpVersion');
748
				$strings['expected_value'] = "$comparison {$info['version']}";
749
				$strings['local_value'] = $dep['value'];
750
				$strings['comment'] = '';
751
				break;
752
			
753
			case 'php_extension':
754
				// PHP Extension %s [version]
755
				$strings['name'] = $translator->translate('ElggPlugin:Dependencies:PhpExtension', [$info['name']]);
756
				if ($info['version']) {
757
					$strings['expected_value'] = "$comparison {$info['version']}";
758
					$strings['local_value'] = $dep['value'];
759
				} else {
760
					$strings['expected_value'] = '';
761
					$strings['local_value'] = '';
762
				}
763
				$strings['comment'] = '';
764
				break;
765
	
766 View Code Duplication
			case 'php_ini':
767
				$strings['name'] = $translator->translate('ElggPlugin:Dependencies:PhpIni', [$info['name']]);
768
				$strings['expected_value'] = "$comparison {$info['value']}";
769
				$strings['local_value'] = $dep['value'];
770
				$strings['comment'] = '';
771
				break;
772
	
773
			case 'plugin':
774
				$strings['name'] = $translator->translate('ElggPlugin:Dependencies:Plugin', [$info['name']]);
775
				$expected = $info['version'] ? "$comparison {$info['version']}" : $translator->translate('any');
776
				$strings['expected_value'] = $expected;
777
				$strings['local_value'] = $dep['value'] ? $dep['value'] : '--';
778
				$strings['comment'] = '';
779
				break;
780
	
781
			case 'priority':
782
				$expected_priority = ucwords($info['priority']);
783
				$real_priority = ucwords($dep['value']);
784
				$strings['name'] = $translator->translate('ElggPlugin:Dependencies:Priority');
785
				$strings['expected_value'] = $translator->translate("ElggPlugin:Dependencies:Priority:$expected_priority", [$info['plugin']]);
786
				$strings['local_value'] = $translator->translate("ElggPlugin:Dependencies:Priority:$real_priority", [$info['plugin']]);
787
				$strings['comment'] = '';
788
				break;
789
		}
790
	
791
		if ($dep['type'] == 'suggests') {
792 View Code Duplication
			if ($dep['status']) {
793
				$strings['comment'] = $translator->translate('ok');
794
			} else {
795
				$strings['comment'] = $translator->translate('ElggPlugin:Dependencies:Suggests:Unsatisfied');
796
			}
797 View Code Duplication
		} else {
798
			if ($dep['status']) {
799
				$strings['comment'] = $translator->translate('ok');
800
			} else {
801
				$strings['comment'] = $translator->translate('error');
802
			}
803
		}
804
	
805
		return $strings;
806
	}
807
	
808
	/**
809
	 * Returns an array of all plugin user settings for a user.
810
	 *
811
	 * @param int    $user_guid  The user GUID or 0 for the currently logged in user.
812
	 * @param string $plugin_id  The plugin ID (Required)
813
	 * @param bool   $return_obj Return settings as an object? This can be used to in reusable
814
	 *                           views where the settings are passed as $vars['entity'].
815
	 * @return array
816
	 * @see \ElggPlugin::getAllUserSettings()
817
	 */
818
	function getAllUserSettings($user_guid = 0, $plugin_id = null, $return_obj = false) {
819
		$plugin = $this->get($plugin_id);
820
		if (!$plugin) {
821
			return false;
822
		}
823
	
824
		$settings = $plugin->getAllUserSettings((int) $user_guid);
825
	
826
		if ($settings && $return_obj) {
827
			$return = new \stdClass;
828
	
829
			foreach ($settings as $k => $v) {
830
				$return->$k = $v;
831
			}
832
	
833
			return $return;
834
		} else {
835
			return $settings;
836
		}
837
	}
838
	
839
	/**
840
	 * Set a user specific setting for a plugin.
841
	 *
842
	 * @param string $name      The name. Note: cannot be "title".
843
	 * @param mixed  $value     The value.
844
	 * @param int    $user_guid The user GUID or 0 for the currently logged in user.
845
	 * @param string $plugin_id The plugin ID (Required)
846
	 *
847
	 * @return bool
848
	 * @see \ElggPlugin::setUserSetting()
849
	 */
850 View Code Duplication
	function setUserSetting($name, $value, $user_guid = 0, $plugin_id = null) {
851
		$plugin = $this->get($plugin_id);
852
		if (!$plugin) {
853
			return false;
854
		}
855
856
		return $plugin->setUserSetting($name, $value, (int) $user_guid);
857
	}
858
	
859
	/**
860
	 * Unsets a user-specific plugin setting
861
	 *
862
	 * @param string $name      Name of the setting
863
	 * @param int    $user_guid The user GUID or 0 for the currently logged in user.
864
	 * @param string $plugin_id The plugin ID (Required)
865
	 *
866
	 * @return bool
867
	 * @see \ElggPlugin::unsetUserSetting()
868
	 */
869
	function unsetUserSetting($name, $user_guid = 0, $plugin_id = null) {
870
		$plugin = $this->get($plugin_id);
871
		if (!$plugin) {
872
			return false;
873
		}
874
875
		return $plugin->unsetUserSetting($name, (int) $user_guid);
876
	}
877
	
878
	/**
879
	 * Get a user specific setting for a plugin.
880
	 *
881
	 * @param string $name      The name of the setting.
882
	 * @param int    $user_guid The user GUID or 0 for the currently logged in user.
883
	 * @param string $plugin_id The plugin ID (Required)
884
	 * @param mixed  $default   The default value to return if none is set
885
	 *
886
	 * @return mixed
887
	 * @see \ElggPlugin::getUserSetting()
888
	 */
889 View Code Duplication
	function getUserSetting($name, $user_guid = 0, $plugin_id = null, $default = null) {
890
		$plugin = $this->get($plugin_id);
891
		if (!$plugin) {
892
			return false;
893
		}
894
895
		return $plugin->getUserSetting($name, (int) $user_guid, $default);
896
	}
897
	
898
	/**
899
	 * Set a setting for a plugin.
900
	 *
901
	 * @param string $name      The name of the setting - note, can't be "title".
902
	 * @param mixed  $value     The value.
903
	 * @param string $plugin_id The plugin ID (Required)
904
	 *
905
	 * @return bool
906
	 * @see \ElggPlugin::setSetting()
907
	 */
908
	function setSetting($name, $value, $plugin_id) {
909
		$plugin = $this->get($plugin_id);
910
		if (!$plugin) {
911
			return false;
912
		}
913
914
		return $plugin->setSetting($name, $value);
915
	}
916
	
917
	/**
918
	 * Get setting for a plugin.
919
	 *
920
	 * @param string $name      The name of the setting.
921
	 * @param string $plugin_id The plugin ID (Required)
922
	 * @param mixed  $default   The default value to return if none is set
923
	 *
924
	 * @return mixed
925
	 * @see \ElggPlugin::getSetting()
926
	 */
927
	function getSetting($name, $plugin_id, $default = null) {
928
		$plugin = $this->get($plugin_id);
929
		if (!$plugin) {
930
			return false;
931
		}
932
933
		return $plugin->getSetting($name, $default);
934
	}
935
	
936
	/**
937
	 * Unsets a plugin setting.
938
	 *
939
	 * @param string $name      The name of the setting.
940
	 * @param string $plugin_id The plugin ID (Required)
941
	 *
942
	 * @return bool
943
	 * @see \ElggPlugin::unsetSetting()
944
	 */
945
	function unsetSetting($name, $plugin_id) {
946
		$plugin = $this->get($plugin_id);
947
		if (!$plugin) {
948
			return false;
949
		}
950
951
		return $plugin->unsetSetting($name);
952
	}
953
	
954
	/**
955
	 * Unsets all plugin settings for a plugin.
956
	 *
957
	 * @param string $plugin_id The plugin ID (Required)
958
	 *
959
	 * @return bool
960
	 * @see \ElggPlugin::unsetAllSettings()
961
	 */
962
	function unsetAllSettings($plugin_id) {
963
		$plugin = $this->get($plugin_id);
964
		if (!$plugin) {
965
			return false;
966
		}
967
	
968
		return $plugin->unsetAllSettings();
969
	}
970
	
971
	/**
972
	 * Returns entities based upon plugin user settings.
973
	 * Takes all the options for {@link elgg_get_entities_from_private_settings()}
974
	 * in addition to the ones below.
975
	 *
976
	 * @param array $options Array in the format:
977
	 *
978
	 * 	plugin_id => STR The plugin id. Required.
979
	 *
980
	 * 	plugin_user_setting_names => null|ARR private setting names
981
	 *
982
	 * 	plugin_user_setting_values => null|ARR metadata values
983
	 *
984
	 * 	plugin_user_setting_name_value_pairs => null|ARR (
985
	 *                                         name => 'name',
986
	 *                                         value => 'value',
987
	 *                                         'operand' => '=',
988
	 *                                        )
989
	 * 	                             Currently if multiple values are sent via
990
	 *                               an array (value => array('value1', 'value2')
991
	 *                               the pair's operand will be forced to "IN".
992
	 *
993
	 * 	plugin_user_setting_name_value_pairs_operator => null|STR The operator to use for combining
994
	 *                                        (name = value) OPERATOR (name = value); default AND
995
	 *
996
	 * @return mixed int If count, int. If not count, array. false on errors.
997
	 */
998
	function getEntitiesFromUserSettings(array $options = []) {
999
		$singulars = ['plugin_user_setting_name', 'plugin_user_setting_value',
1000
			'plugin_user_setting_name_value_pair'];
1001
	
1002
		$options = _elgg_normalize_plural_options_array($options, $singulars);
1003
	
1004
		// rewrite plugin_user_setting_name_* to the right PS ones.
1005
		$map = [
1006
			'plugin_user_setting_names' => 'private_setting_names',
1007
			'plugin_user_setting_values' => 'private_setting_values',
1008
			'plugin_user_setting_name_value_pairs' => 'private_setting_name_value_pairs',
1009
			'plugin_user_setting_name_value_pairs_operator' => 'private_setting_name_value_pairs_operator',
1010
		];
1011
	
1012
		foreach ($map as $plugin => $private) {
1013
			if (!isset($options[$plugin])) {
1014
				continue;
1015
			}
1016
	
1017
			if (isset($options[$private])) {
1018
				if (!is_array($options[$private])) {
1019
					$options[$private] = [$options[$private]];
1020
				}
1021
	
1022
				$options[$private] = array_merge($options[$private], $options[$plugin]);
1023
			} else {
1024
				$options[$private] = $options[$plugin];
1025
			}
1026
		}
1027
	
1028
		$prefix = $this->namespacePrivateSetting('user_setting', '', $options['plugin_id']);
1029
		$options['private_setting_name_prefix'] = $prefix;
1030
	
1031
		return elgg_get_entities_from_private_settings($options);
1032
	}
1033
}
1034