Completed
Push — master ( caf222...deba87 )
by Jeroen
72:32 queued 44:47
created

engine/classes/Elgg/Database/Plugins.php (2 issues)

1
<?php
2
namespace Elgg\Database;
3
4
use Elgg\Cache\Pool;
5
use Elgg\Config;
6
use Elgg\Profilable;
7
use Exception;
8
use Elgg\Cache\PluginSettingsCache;
9
10
/**
11
 * Persistent, installation-wide key-value storage.
12
 *
13
 * WARNING: API IN FLUX. DO NOT USE DIRECTLY.
14
 *
15
 * @access private
16
 *
17
 * @since 1.10.0
18
 */
19
class Plugins {
20
	use Profilable;
21
22
	/**
23
	 * @var \ElggPlugin[]
24
	 */
25
	private $boot_plugins = [];
26
27
	/**
28
	 * @var array|null
29
	 */
30
	private $provides_cache;
31
32
	/**
33
	 * @var string[] Active plugins, with plugin ID => GUID. Missing keys imply inactive plugins.
34
	 */
35
	private $active_guids = [];
36
37
	/**
38
	 * @var bool Has $active_guids been populated?
39
	 */
40
	private $active_guids_known = false;
41
42
	/**
43
	 * @var Pool
44
	 */
45
	private $plugins_by_id;
46
47
	/**
48
	 * @var PluginSettingsCache
49
	 */
50
	private $settings_cache;
51
52
	/**
53
	 * Constructor
54
	 *
55
	 * @param Pool                $pool  Cache for referencing plugins by ID
56
	 * @param PluginSettingsCache $cache Plugin settings cache
57
	 */
58 1334
	public function __construct(Pool $pool, PluginSettingsCache $cache) {
59 1334
		$this->plugins_by_id = $pool;
60 1334
		$this->settings_cache = $cache;
61 1334
	}
62
63
	/**
64
	 * Set the list of active plugins according to the boot data cache
65
	 *
66
	 * @param \ElggPlugin[] $plugins Set of active plugins
67
	 * @return void
68
	 */
69 293
	public function setBootPlugins(array $plugins) {
70 293
		$this->boot_plugins = $plugins;
71 293
		foreach ($plugins as $plugin) {
72
			$this->plugins_by_id->put($plugin->getID(), $plugin);
73
		}
74 293
	}
75
76
	/**
77
	 * Returns a list of plugin directory names from a base directory.
78
	 *
79
	 * @param string $dir A dir to scan for plugins. Defaults to config's plugins_path.
80
	 *                    Must have a trailing slash.
81
	 *
82
	 * @return array Array of directory names (not full paths)
83
	 * @access private
84
	 */
85
	function getDirsInDir($dir = null) {
86
		if (!$dir) {
87
			$dir = elgg_get_plugins_path();
88
		}
89
	
90
		$plugin_dirs = [];
91
		$handle = opendir($dir);
92
	
93
		if ($handle) {
94
			while ($plugin_dir = readdir($handle)) {
95
				// must be directory and not begin with a .
96
				if (substr($plugin_dir, 0, 1) !== '.' && is_dir($dir . $plugin_dir)) {
97
					$plugin_dirs[] = $plugin_dir;
98
				}
99
			}
100
		}
101
	
102
		sort($plugin_dirs);
103
	
104
		return $plugin_dirs;
105
	}
106
	
107
	/**
108
	 * Discovers plugins in the plugins_path setting and creates \ElggPlugin
109
	 * entities for them if they don't exist.  If there are plugins with entities
110
	 * but not actual files, will disable the \ElggPlugin entities and mark as inactive.
111
	 * The \ElggPlugin object holds config data, so don't delete.
112
	 *
113
	 * @return bool
114
	 * @access private
115
	 */
116
	function generateEntities() {
117
	
118
		$mod_dir = elgg_get_plugins_path();
119
	
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
			'limit' => ELGG_ENTITIES_NO_VALUE,
130
		]);
131
		/* @var \ElggPlugin[] $known_plugins */
132
	
133
		if (!$known_plugins) {
134
			$known_plugins = [];
135
		}
136
	
137
		// map paths to indexes
138
		$id_map = [];
139
		foreach ($known_plugins as $i => $plugin) {
140
			// if the ID is wrong, delete the plugin because we can never load it.
141
			$id = $plugin->getID();
142
			if (!$id) {
143
				$plugin->delete();
144
				unset($known_plugins[$i]);
145
				continue;
146
			}
147
			$id_map[$plugin->getID()] = $i;
148
		}
149
	
150
		$physical_plugins = $this->getDirsInDir($mod_dir);
151
		if (!$physical_plugins) {
152
			elgg_set_ignore_access($old_ia);
153
			return false;
154
		}
155
	
156
		// check real plugins against known ones
157
		foreach ($physical_plugins as $plugin_id) {
158
			// is this already in the db?
159
			if (array_key_exists($plugin_id, $id_map)) {
160
				$index = $id_map[$plugin_id];
161
				$plugin = $known_plugins[$index];
162
				// was this plugin deleted and its entity disabled?
163
				if (!$plugin->isEnabled()) {
164
					$plugin->enable();
165
					$plugin->deactivate();
166
					$plugin->setPriority('last');
167
				}
168
	
169
				// remove from the list of plugins to disable
170
				unset($known_plugins[$index]);
171
			} else {
172
				// create new plugin
173
				// priority is forced to last in save() if not set.
174
				$plugin = new \ElggPlugin($mod_dir . $plugin_id);
175
				$plugin->save();
176
			}
177
		}
178
	
179
		// everything remaining in $known_plugins needs to be disabled
180
		// because they are entities, but their dirs were removed.
181
		// don't delete the entities because they hold settings.
182
		foreach ($known_plugins as $plugin) {
183
			if ($plugin->isActive()) {
184
				$plugin->deactivate();
185
			}
186
			// remove the priority.
187
			$name = $this->namespacePrivateSetting('internal', 'priority');
188
			remove_private_setting($plugin->guid, $name);
189
			if ($plugin->isEnabled()) {
190
				$plugin->disable();
191
			}
192
		}
193
	
194
		access_show_hidden_entities($old_access);
195
		elgg_set_ignore_access($old_ia);
196
	
197
		return true;
198
	}
199
	
200
	/**
201
	 * Cache a reference to this plugin by its ID
202
	 *
203
	 * @param \ElggPlugin $plugin
204
	 *
205
	 * @access private
206
	 */
207 10
	function cache(\ElggPlugin $plugin) {
208 10
		$this->plugins_by_id->put($plugin->getID(), $plugin);
209 10
	}
210
	
211
	/**
212
	 * Returns an \ElggPlugin object with the path $path.
213
	 *
214
	 * @param string $plugin_id The id (dir name) of the plugin. NOT the guid.
215
	 * @return \ElggPlugin|null
216
	 */
217 3
	function get($plugin_id) {
218
		return $this->plugins_by_id->get($plugin_id, function () use ($plugin_id) {
219 3
			$plugins = elgg_get_entities_from_metadata([
220 3
				'type' => 'object',
221 3
				'subtype' => 'plugin',
222
				'metadata_name_value_pairs' => [
223 3
					'name' => 'title',
224 3
					'value' => $plugin_id,
225
				],
226 3
				'limit' => 1,
227
				'distinct' => false,
228
			]);
229
230 3
			if ($plugins) {
231 3
				return $plugins[0];
232
			}
233
234
			return null;
235 3
		});
236
	}
237
	
238
	/**
239
	 * Returns if a plugin exists in the system.
240
	 *
241
	 * @warning This checks only plugins that are registered in the system!
242
	 * If the plugin cache is outdated, be sure to regenerate it with
243
	 * {@link _elgg_generate_plugin_objects()} first.
244
	 *
245
	 * @param string $id The plugin ID.
246
	 * @return bool
247
	 */
248
	function exists($id) {
249
		return (bool) $this->get($id);
250
	}
251
	
252
	/**
253
	 * Returns the highest priority of the plugins
254
	 *
255
	 * @return int
256
	 * @access private
257
	 */
258
	function getMaxPriority() {
259
		$db_prefix = _elgg_config()->dbprefix;
260
		$priority = $this->namespacePrivateSetting('internal', 'priority');
261
		$plugin_subtype = get_subtype_id('object', 'plugin');
262
	
263
		$q = "SELECT MAX(CAST(ps.value AS unsigned)) as max
264
			FROM {$db_prefix}entities e, {$db_prefix}private_settings ps
265
			WHERE ps.name = '$priority'
266
			AND ps.entity_guid = e.guid
267
			AND e.type = 'object' and e.subtype = $plugin_subtype";
268
	
269
		$data = get_data($q);
270
		if ($data) {
271
			$max = $data[0]->max;
272
		} else {
273
			$max = 1;
274
		}
275
	
276
		// can't have a priority of 0.
277
		return ($max) ? $max : 1;
278
	}
279
	
280
	/**
281
	 * Returns if a plugin is active for a current site.
282
	 *
283
	 * @param string $plugin_id The plugin ID
284
	 * @return bool
285
	 */
286 1
	function isActive($plugin_id) {
287 1
		if ($this->active_guids_known) {
288 1
			return isset($this->active_guids[$plugin_id]);
289
		}
290
291
		$site = elgg_get_site_entity();
292
	
293
		if (!($site instanceof \ElggSite)) {
294
			return false;
295
		}
296
	
297
		$plugin = $this->get($plugin_id);
298
	
299
		if (!$plugin) {
300
			return false;
301
		}
302
	
303
		return $plugin->isActive($site->guid);
304
	}
305
	
306
	/**
307
	 * Loads all active plugins in the order specified in the tool admin panel.
308
	 *
309
	 * @note This is called on every page load. If a plugin is active and problematic, it
310
	 * will be disabled and a visible error emitted. This does not check the deps system because
311
	 * that was too slow.
312
	 *
313
	 * @return bool
314
	 * @access private
315
	 */
316 293
	function load() {
317 293
		if ($this->timer) {
318
			$this->timer->begin([__METHOD__]);
319
		}
320
321 293
		$plugins_path = elgg_get_plugins_path();
322 293
		$start_flags = ELGG_PLUGIN_INCLUDE_START |
323 293
						ELGG_PLUGIN_REGISTER_VIEWS |
324 293
						ELGG_PLUGIN_REGISTER_ACTIONS |
325 293
						ELGG_PLUGIN_REGISTER_LANGUAGES |
326 293
						ELGG_PLUGIN_REGISTER_WIDGETS |
327 293
						ELGG_PLUGIN_REGISTER_CLASSES;
328
	
329 293
		if (!$plugins_path) {
330
			return false;
331
		}
332
	
333
		// temporary disable all plugins if there is a file called 'disabled' in the plugin dir
334 293
		if (file_exists("$plugins_path/disabled")) {
335
			if (elgg_is_admin_logged_in() && elgg_in_context('admin')) {
336
				system_message(_elgg_services()->translator->translate('plugins:disabled'));
337
			}
338
			return false;
339
		}
340
341 293
		$config = _elgg_config();
342
	
343 293
		if ($config->system_cache_loaded) {
344 293
			$start_flags = $start_flags & ~ELGG_PLUGIN_REGISTER_VIEWS;
345
		}
346
	
347 293
		if (_elgg_services()->translator->wasLoadedFromCache()) {
348 293
			$start_flags = $start_flags & ~ELGG_PLUGIN_REGISTER_LANGUAGES;
349
		}
350
	
351 293
		$plugins = $this->boot_plugins;
352 293
		if (!$plugins) {
353 293
			$this->active_guids_known = true;
354 293
			return true;
355
		}
356
357
		$return = true;
358
		foreach ($plugins as $plugin) {
359
			$id = $plugin->getID();
360
			try {
361
				$plugin->start($start_flags);
362
				$this->active_guids[$id] = $plugin->guid;
363
			} catch (Exception $e) {
364
				$disable_plugins = _elgg_config()->auto_disable_plugins;
365
				if ($disable_plugins === null) {
366
					$disable_plugins = true;
367
				}
368
				if ($disable_plugins) {
369
					$plugin->deactivate();
370
				
371
					$msg = _elgg_services()->translator->translate('PluginException:CannotStart',
372
									[$id, $plugin->guid, $e->getMessage()]);
373
					elgg_add_admin_notice("cannot_start $id", $msg);
374
					$return = false;
375
				}
376
			}
377
		}
378
379
		$this->active_guids_known = true;
380
381
		if ($this->timer) {
382
			$this->timer->end([__METHOD__]);
383
		}
384
		return $return;
385
	}
386
	
387
	/**
388
	 * Returns an ordered list of plugins
389
	 *
390
	 * @param string $status The status of the plugins. active, inactive, or all.
391
	 * @return \ElggPlugin[]
392
	 */
393 293
	function find($status = 'active') {
394 293
		if (!_elgg_services()->db) {
395
			return [];
396
		}
397
398 293
		$db_prefix = _elgg_config()->dbprefix;
399 293
		$priority = $this->namespacePrivateSetting('internal', 'priority');
400 293
		$site_guid = 1;
401
		
402
		// grab plugins
403
		$options = [
404 293
			'type' => 'object',
405 293
			'subtype' => 'plugin',
406 293
			'limit' => ELGG_ENTITIES_NO_VALUE,
407
			'selects' => ['ps.value'],
408
			'joins' => [
409 293
				"JOIN {$db_prefix}private_settings ps on ps.entity_guid = e.guid",
410
			],
411 293
			'wheres' => ["ps.name = '$priority'"],
412
			// ORDER BY CAST(ps.value) is super slow. We usort() below.
413
			'order_by' => false,
414
		];
415
	
416
		switch ($status) {
417 293
			case 'active':
418 293
				$options['relationship'] = 'active_plugin';
419 293
				$options['relationship_guid'] = $site_guid;
420 293
				$options['inverse_relationship'] = true;
421 293
				break;
422
	
423
			case 'inactive':
424
				$options['wheres'][] = "NOT EXISTS (
425
						SELECT 1 FROM {$db_prefix}entity_relationships active_er
426
						WHERE active_er.guid_one = e.guid
427
							AND active_er.relationship = 'active_plugin'
428
							AND active_er.guid_two = $site_guid)";
429
				break;
430
	
431
			case 'all':
432
			default:
433
				break;
434
		}
435
	
436 293
		$old_ia = elgg_set_ignore_access(true);
437 293
		$plugins = elgg_get_entities_from_relationship($options);
438 293
		elgg_set_ignore_access($old_ia);
439
440 293
		usort($plugins, function (\ElggPlugin $a, \ElggPlugin $b) {
441
			$a_value = $a->getVolatileData('select:value');
442
			$b_value = $b->getVolatileData('select:value');
443
444
			if ($b_value !== $a_value) {
445
				return $a_value - $b_value;
446
			} else {
447
				return $a->guid - $b->guid;
448
			}
449 293
		});
450
	
451 293
		return $plugins;
452
	}
453
	
454
	/**
455
	 * Reorder plugins to an order specified by the array.
456
	 * Plugins not included in this array will be appended to the end.
457
	 *
458
	 * @note This doesn't use the \ElggPlugin->setPriority() method because
459
	 *       all plugins are being changed and we don't want it to automatically
460
	 *       reorder plugins.
461
	 * @todo Can this be done in a single sql command?
462
	 *
463
	 * @param array $order An array of plugin ids in the order to set them
464
	 * @return bool
465
	 * @access private
466
	 */
467
	function setPriorities(array $order) {
468
		$name = $this->namespacePrivateSetting('internal', 'priority');
469
	
470
		$plugins = $this->find('any');
471
		if (!$plugins) {
472
			return false;
473
		}
474
	
475
		// reindex to get standard counting. no need to increment by 10.
476
		// though we do start with 1
477
		$order = array_values($order);
478
	
479
		$missing_plugins = [];
480
		/* @var \ElggPlugin[] $missing_plugins */
481
	
482
		$priority = 0;
483
		foreach ($plugins as $plugin) {
484
			$plugin_id = $plugin->getID();
485
	
486
			if (!in_array($plugin_id, $order)) {
487
				$missing_plugins[] = $plugin;
488
				continue;
489
			}
490
	
491
			$priority = array_search($plugin_id, $order) + 1;
492
	
493
			if (!$plugin->setPrivateSetting($name, $priority)) {
494
				return false;
495
			}
496
		}
497
	
498
		// set the missing plugins' priorities
499
		if (empty($missing_plugins)) {
500
			return true;
501
		}
502
		
503
		foreach ($missing_plugins as $plugin) {
504
			$priority++;
505
			if (!$plugin->setPrivateSetting($name, $priority)) {
506
				return false;
507
			}
508
		}
509
	
510
		return true;
511
	}
512
	
513
	/**
514
	 * Reindexes all plugin priorities starting at 1.
515
	 *
516
	 * @return bool
517
	 * @access private
518
	 */
519
	function reindexPriorities() {
520
		return $this->setPriorities([]);
521
	}
522
	
523
	/**
524
	 * Namespaces a string to be used as a private setting name for a plugin.
525
	 *
526
	 * For user_settings, two namespaces are added: a user setting namespace and the
527
	 * plugin id.
528
	 *
529
	 * For internal (plugin priority), there is a single internal namespace added.
530
	 *
531
	 * @param string $type The type of setting: user_setting or internal.
532
	 * @param string $name The name to namespace.
533
	 * @param string $id   The plugin's ID to namespace with.  Required for user_setting.
534
	 * @return string
535
	 * @access private
536
	 */
537 293
	function namespacePrivateSetting($type, $name, $id = null) {
538
		switch ($type) {
539 293
			case 'user_setting':
540 1
				if (!$id) {
541
					throw new \InvalidArgumentException("You must pass the plugin id for user settings");
542
				}
543 1
				$name = ELGG_PLUGIN_USER_SETTING_PREFIX . "$id:$name";
544 1
				break;
545
	
546 293
			case 'internal':
547 293
				$name = ELGG_PLUGIN_INTERNAL_PREFIX . $name;
548 293
				break;
549
		}
550
	
551 293
		return $name;
552
	}
553
	
554
	
555
	/**
556
	 * Returns an array of all provides from all active plugins.
557
	 *
558
	 * Array in the form array(
559
	 * 	'provide_type' => array(
560
	 * 		'provided_name' => array(
561
	 * 			'version' => '1.8',
562
	 * 			'provided_by' => 'provider_plugin_id'
563
	 *  	)
564
	 *  )
565
	 * )
566
	 *
567
	 * @param string $type The type of provides to return
568
	 * @param string $name A specific provided name to return. Requires $provide_type.
569
	 *
570
	 * @return array|false
571
	 * @access private
572
	 */
573
	function getProvides($type = null, $name = null) {
574
		if ($this->provides_cache === null) {
575
			$active_plugins = $this->find('active');
576
		
577
			$provides = [];
578
	
579
			foreach ($active_plugins as $plugin) {
580
				$plugin_provides = [];
581
				$manifest = $plugin->getManifest();
582
				if ($manifest instanceof \ElggPluginManifest) {
583
					$plugin_provides = $plugin->getManifest()->getProvides();
584
				}
585
				if ($plugin_provides) {
586
					foreach ($plugin_provides as $provided) {
587
						$provides[$provided['type']][$provided['name']] = [
588
							'version' => $provided['version'],
589
							'provided_by' => $plugin->getID()
590
						];
591
					}
592
				}
593
			}
594
			
595
			$this->provides_cache = $provides;
596
		}
597
		
598
		if ($type && $name) {
599 View Code Duplication
			if (isset($this->provides_cache[$type][$name])) {
600
				return $this->provides_cache[$type][$name];
601
			} else {
602
				return false;
603
			}
604 View Code Duplication
		} elseif ($type) {
605
			if (isset($this->provides_cache[$type])) {
606
				return $this->provides_cache[$type];
607
			} else {
608
				return false;
609
			}
610
		}
611
	
612
		return $this->provides_cache;
613
	}
614
	
615
	/**
616
	 * Deletes all cached data on plugins being provided.
617
	 *
618
	 * @return boolean
619
	 * @access private
620
	 */
621
	function invalidateProvidesCache() {
622
		$this->provides_cache = null;
623
		return true;
624
	}
625
626
	/**
627
	 * Delete the cache holding whether plugins are active or not
628
	 *
629
	 * @return void
630
	 * @access private
631
	 */
632
	public function invalidateIsActiveCache() {
633
		$this->active_guids = [];
634
		$this->active_guids_known = false;
635
	}
636
	
637
	/**
638
	 * Checks if a plugin is currently providing $type and $name, and optionally
639
	 * checking a version.
640
	 *
641
	 * @param string $type       The type of the provide
642
	 * @param string $name       The name of the provide
643
	 * @param string $version    A version to check against
644
	 * @param string $comparison The comparison operator to use in version_compare()
645
	 *
646
	 * @return array An array in the form array(
647
	 * 	'status' => bool Does the provide exist?,
648
	 * 	'value' => string The version provided
649
	 * )
650
	 * @access private
651
	 */
652
	function checkProvides($type, $name, $version = null, $comparison = 'ge') {
653
		$provided = $this->getProvides($type, $name);
654
		if (!$provided) {
655
			return [
656
				'status' => false,
657
				'value' => ''
658
			];
659
		}
660
	
661
		if ($version) {
662
			$status = version_compare($provided['version'], $version, $comparison);
663
		} else {
664
			$status = true;
665
		}
666
	
667
		return [
668
			'status' => $status,
669
			'value' => $provided['version']
670
		];
671
	}
672
	
673
	/**
674
	 * Returns an array of parsed strings for a dependency in the
675
	 * format: array(
676
	 * 	'type'			=>	requires, conflicts, or provides.
677
	 * 	'name'			=>	The name of the requirement / conflict
678
	 * 	'value'			=>	A string representing the expected value: <1, >=3, !=enabled
679
	 * 	'local_value'	=>	The current value, ("Not installed")
680
	 * 	'comment'		=>	Free form text to help resovle the problem ("Enable / Search for plugin <link>")
681
	 * )
682
	 *
683
	 * @param array $dep An \ElggPluginPackage dependency array
684
	 * @return array
685
	 * @access private
686
	 */
687
	function getDependencyStrings($dep) {
688
		$translator = _elgg_services()->translator;
689
		$dep_system = elgg_extract('type', $dep);
690
		$info = elgg_extract('dep', $dep);
691
		$type = elgg_extract('type', $info);
692
	
693
		if (!$dep_system || !$info || !$type) {
694
			return false;
695
		}
696
	
697
		// rewrite some of these to be more readable
698
		$comparison = elgg_extract('comparison', $info);
699
		switch ($comparison) {
700
			case 'lt':
701
				$comparison = '<';
702
				break;
703
			case 'gt':
704
				$comparison = '>';
705
				break;
706
			case 'ge':
707
				$comparison = '>=';
708
				break;
709
			case 'le':
710
				$comparison = '<=';
711
				break;
712
			default:
713
				//keep $comparison value intact
714
				break;
715
		}
716
	
717
		/*
718
		'requires'	'plugin oauth_lib'	<1.3	1.3		'downgrade'
719
		'requires'	'php setting bob'	>3		3		'change it'
720
		'conflicts'	'php setting'		>3		4		'change it'
721
		'conflicted''plugin profile'	any		1.8		'disable profile'
722
		'provides'	'plugin oauth_lib'	1.3		--		--
723
		'priority'	'before blog'		--		after	'move it'
724
		*/
725
		$strings = [];
726
		$strings['type'] = $translator->translate('ElggPlugin:Dependencies:' . ucwords($dep_system));
727
	
728
		switch ($type) {
729 View Code Duplication
			case 'elgg_release':
730
				// 'Elgg Version'
731
				$strings['name'] = $translator->translate('ElggPlugin:Dependencies:Elgg');
732
				$strings['expected_value'] = "$comparison {$info['version']}";
733
				$strings['local_value'] = $dep['value'];
734
				$strings['comment'] = '';
735
				break;
736
	
737 View Code Duplication
			case 'php_version':
738
				// 'PHP version'
739
				$strings['name'] = $translator->translate('ElggPlugin:Dependencies:PhpVersion');
740
				$strings['expected_value'] = "$comparison {$info['version']}";
741
				$strings['local_value'] = $dep['value'];
742
				$strings['comment'] = '';
743
				break;
744
			
745
			case 'php_extension':
746
				// PHP Extension %s [version]
747
				$strings['name'] = $translator->translate('ElggPlugin:Dependencies:PhpExtension', [$info['name']]);
748
				if ($info['version']) {
749
					$strings['expected_value'] = "$comparison {$info['version']}";
750
					$strings['local_value'] = $dep['value'];
751
				} else {
752
					$strings['expected_value'] = '';
753
					$strings['local_value'] = '';
754
				}
755
				$strings['comment'] = '';
756
				break;
757
	
758 View Code Duplication
			case 'php_ini':
759
				$strings['name'] = $translator->translate('ElggPlugin:Dependencies:PhpIni', [$info['name']]);
760
				$strings['expected_value'] = "$comparison {$info['value']}";
761
				$strings['local_value'] = $dep['value'];
762
				$strings['comment'] = '';
763
				break;
764
	
765
			case 'plugin':
766
				$strings['name'] = $translator->translate('ElggPlugin:Dependencies:Plugin', [$info['name']]);
767
				$expected = $info['version'] ? "$comparison {$info['version']}" : $translator->translate('any');
768
				$strings['expected_value'] = $expected;
769
				$strings['local_value'] = $dep['value'] ? $dep['value'] : '--';
770
				$strings['comment'] = '';
771
				break;
772
	
773
			case 'priority':
774
				$expected_priority = ucwords($info['priority']);
775
				$real_priority = ucwords($dep['value']);
776
				$strings['name'] = $translator->translate('ElggPlugin:Dependencies:Priority');
777
				$strings['expected_value'] = $translator->translate("ElggPlugin:Dependencies:Priority:$expected_priority", [$info['plugin']]);
778
				$strings['local_value'] = $translator->translate("ElggPlugin:Dependencies:Priority:$real_priority", [$info['plugin']]);
779
				$strings['comment'] = '';
780
				break;
781
		}
782
	
783
		if ($dep['type'] == 'suggests') {
784 View Code Duplication
			if ($dep['status']) {
785
				$strings['comment'] = $translator->translate('ok');
786
			} else {
787
				$strings['comment'] = $translator->translate('ElggPlugin:Dependencies:Suggests:Unsatisfied');
788
			}
789 View Code Duplication
		} else {
790
			if ($dep['status']) {
791
				$strings['comment'] = $translator->translate('ok');
792
			} else {
793
				$strings['comment'] = $translator->translate('error');
794
			}
795
		}
796
	
797
		return $strings;
798
	}
799
	
800
	/**
801
	 * Returns an array of all plugin user settings for a user.
802
	 *
803
	 * @param int    $user_guid  The user GUID or 0 for the currently logged in user.
804
	 * @param string $plugin_id  The plugin ID (Required)
805
	 * @param bool   $return_obj Return settings as an object? This can be used to in reusable
806
	 *                           views where the settings are passed as $vars['entity'].
807
	 * @return array
808
	 * @see \ElggPlugin::getAllUserSettings()
809
	 */
810
	function getAllUserSettings($user_guid = 0, $plugin_id = null, $return_obj = false) {
811
		$plugin = $this->get($plugin_id);
812
		if (!$plugin) {
813
			return false;
814
		}
815
	
816
		$settings = $plugin->getAllUserSettings((int) $user_guid);
817
	
818
		if ($settings && $return_obj) {
819
			$return = new \stdClass;
820
	
821
			foreach ($settings as $k => $v) {
822
				$return->$k = $v;
823
			}
824
	
825
			return $return;
826
		} else {
827
			return $settings;
828
		}
829
	}
830
	
831
	/**
832
	 * Set a user specific setting for a plugin.
833
	 *
834
	 * @param string $name      The name. Note: cannot be "title".
835
	 * @param mixed  $value     The value.
836
	 * @param int    $user_guid The user GUID or 0 for the currently logged in user.
837
	 * @param string $plugin_id The plugin ID (Required)
838
	 *
839
	 * @return bool
840
	 * @see \ElggPlugin::setUserSetting()
841
	 */
842 View Code Duplication
	function setUserSetting($name, $value, $user_guid = 0, $plugin_id = null) {
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
843
		$plugin = $this->get($plugin_id);
844
		if (!$plugin) {
845
			return false;
846
		}
847
848
		return $plugin->setUserSetting($name, $value, (int) $user_guid);
849
	}
850
	
851
	/**
852
	 * Unsets a user-specific plugin setting
853
	 *
854
	 * @param string $name      Name of the setting
855
	 * @param int    $user_guid The user GUID or 0 for the currently logged in user.
856
	 * @param string $plugin_id The plugin ID (Required)
857
	 *
858
	 * @return bool
859
	 * @see \ElggPlugin::unsetUserSetting()
860
	 */
861
	function unsetUserSetting($name, $user_guid = 0, $plugin_id = null) {
862
		$plugin = $this->get($plugin_id);
863
		if (!$plugin) {
864
			return false;
865
		}
866
867
		return $plugin->unsetUserSetting($name, (int) $user_guid);
868
	}
869
	
870
	/**
871
	 * Get a user specific setting for a plugin.
872
	 *
873
	 * @param string $name      The name of the setting.
874
	 * @param int    $user_guid The user GUID or 0 for the currently logged in user.
875
	 * @param string $plugin_id The plugin ID (Required)
876
	 * @param mixed  $default   The default value to return if none is set
877
	 *
878
	 * @return mixed
879
	 * @see \ElggPlugin::getUserSetting()
880
	 */
881 View Code Duplication
	function getUserSetting($name, $user_guid = 0, $plugin_id = null, $default = null) {
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
882
		$plugin = $this->get($plugin_id);
883
		if (!$plugin) {
884
			return false;
885
		}
886
887
		return $plugin->getUserSetting($name, (int) $user_guid, $default);
888
	}
889
	
890
	/**
891
	 * Set a setting for a plugin.
892
	 *
893
	 * @param string $name      The name of the setting - note, can't be "title".
894
	 * @param mixed  $value     The value.
895
	 * @param string $plugin_id The plugin ID (Required)
896
	 *
897
	 * @return bool
898
	 * @see \ElggPlugin::setSetting()
899
	 */
900
	function setSetting($name, $value, $plugin_id) {
901
		$plugin = $this->get($plugin_id);
902
		if (!$plugin) {
903
			return false;
904
		}
905
906
		return $plugin->setSetting($name, $value);
907
	}
908
	
909
	/**
910
	 * Get setting for a plugin.
911
	 *
912
	 * @param string $name      The name of the setting.
913
	 * @param string $plugin_id The plugin ID (Required)
914
	 * @param mixed  $default   The default value to return if none is set
915
	 *
916
	 * @return mixed
917
	 * @see \ElggPlugin::getSetting()
918
	 */
919
	function getSetting($name, $plugin_id, $default = null) {
920
		$plugin = $this->get($plugin_id);
921
		if (!$plugin) {
922
			return false;
923
		}
924
925
		return $plugin->getSetting($name, $default);
926
	}
927
	
928
	/**
929
	 * Unsets a plugin setting.
930
	 *
931
	 * @param string $name      The name of the setting.
932
	 * @param string $plugin_id The plugin ID (Required)
933
	 *
934
	 * @return bool
935
	 * @see \ElggPlugin::unsetSetting()
936
	 */
937
	function unsetSetting($name, $plugin_id) {
938
		$plugin = $this->get($plugin_id);
939
		if (!$plugin) {
940
			return false;
941
		}
942
943
		return $plugin->unsetSetting($name);
944
	}
945
	
946
	/**
947
	 * Unsets all plugin settings for a plugin.
948
	 *
949
	 * @param string $plugin_id The plugin ID (Required)
950
	 *
951
	 * @return bool
952
	 * @see \ElggPlugin::unsetAllSettings()
953
	 */
954
	function unsetAllSettings($plugin_id) {
955
		$plugin = $this->get($plugin_id);
956
		if (!$plugin) {
957
			return false;
958
		}
959
	
960
		return $plugin->unsetAllSettings();
961
	}
962
	
963
	/**
964
	 * Returns entities based upon plugin user settings.
965
	 * Takes all the options for {@link elgg_get_entities_from_private_settings()}
966
	 * in addition to the ones below.
967
	 *
968
	 * @param array $options Array in the format:
969
	 *
970
	 * 	plugin_id => STR The plugin id. Required.
971
	 *
972
	 * 	plugin_user_setting_names => null|ARR private setting names
973
	 *
974
	 * 	plugin_user_setting_values => null|ARR metadata values
975
	 *
976
	 * 	plugin_user_setting_name_value_pairs => null|ARR (
977
	 *                                         name => 'name',
978
	 *                                         value => 'value',
979
	 *                                         'operand' => '=',
980
	 *                                        )
981
	 * 	                             Currently if multiple values are sent via
982
	 *                               an array (value => array('value1', 'value2')
983
	 *                               the pair's operand will be forced to "IN".
984
	 *
985
	 * 	plugin_user_setting_name_value_pairs_operator => null|STR The operator to use for combining
986
	 *                                        (name = value) OPERATOR (name = value); default AND
987
	 *
988
	 * @return mixed int If count, int. If not count, array. false on errors.
989
	 */
990
	function getEntitiesFromUserSettings(array $options = []) {
991
		$singulars = ['plugin_user_setting_name', 'plugin_user_setting_value',
992
			'plugin_user_setting_name_value_pair'];
993
	
994
		$options = _elgg_normalize_plural_options_array($options, $singulars);
995
	
996
		// rewrite plugin_user_setting_name_* to the right PS ones.
997
		$map = [
998
			'plugin_user_setting_names' => 'private_setting_names',
999
			'plugin_user_setting_values' => 'private_setting_values',
1000
			'plugin_user_setting_name_value_pairs' => 'private_setting_name_value_pairs',
1001
			'plugin_user_setting_name_value_pairs_operator' => 'private_setting_name_value_pairs_operator',
1002
		];
1003
	
1004
		foreach ($map as $plugin => $private) {
1005
			if (!isset($options[$plugin])) {
1006
				continue;
1007
			}
1008
	
1009
			if (isset($options[$private])) {
1010
				if (!is_array($options[$private])) {
1011
					$options[$private] = [$options[$private]];
1012
				}
1013
	
1014
				$options[$private] = array_merge($options[$private], $options[$plugin]);
1015
			} else {
1016
				$options[$private] = $options[$plugin];
1017
			}
1018
		}
1019
	
1020
		$prefix = $this->namespacePrivateSetting('user_setting', '', $options['plugin_id']);
1021
		$options['private_setting_name_prefix'] = $prefix;
1022
	
1023
		return elgg_get_entities_from_private_settings($options);
1024
	}
1025
}
1026