diff options
Diffstat (limited to 'engine/lib/plugins.php')
| -rw-r--r-- | engine/lib/plugins.php | 1179 | 
1 files changed, 1179 insertions, 0 deletions
| diff --git a/engine/lib/plugins.php b/engine/lib/plugins.php new file mode 100644 index 000000000..d5d3db466 --- /dev/null +++ b/engine/lib/plugins.php @@ -0,0 +1,1179 @@ +<?php +/** + * Elgg plugins library + * Contains functions for managing plugins + * + * @package Elgg.Core + * @subpackage Plugins + */ + +/** + * Tells ElggPlugin::start() to include the start.php file. + */ +define('ELGG_PLUGIN_INCLUDE_START', 1); + +/** + * Tells ElggPlugin::start() to automatically register the plugin's views. + */ +define('ELGG_PLUGIN_REGISTER_VIEWS', 2); + +/** + * Tells ElggPlugin::start() to automatically register the plugin's languages. + */ +define('ELGG_PLUGIN_REGISTER_LANGUAGES', 4); + +/** + * Tells ElggPlugin::start() to automatically register the plugin's classes. + */ +define('ELGG_PLUGIN_REGISTER_CLASSES', 8); + +/** + * Prefix for plugin setting names + * + * @todo Can't namespace these because many plugins directly call + * private settings via $entity->$name. + */ +//define('ELGG_PLUGIN_SETTING_PREFIX', 'plugin:setting:'); + +/** + * Prefix for plugin user setting names + */ +define('ELGG_PLUGIN_USER_SETTING_PREFIX', 'plugin:user_setting:'); + +/** + * Internal settings prefix + * + * @todo This could be resolved by promoting ElggPlugin to a 5th type. + */ +define('ELGG_PLUGIN_INTERNAL_PREFIX', 'elgg:internal:'); + + +/** + * Returns a list of plugin IDs (dir names) from a dir. + * + * @param string $dir A dir to scan for plugins. Defaults to config's plugins_path. + * + * @return array + * @since 1.8.0 + * @access private + */ +function elgg_get_plugin_ids_in_dir($dir = null) { +	if (!$dir) { +		$dir = elgg_get_plugins_path(); +	} + +	$plugin_ids = array(); +	$handle = opendir($dir); + +	if ($handle) { +		while ($plugin_id = readdir($handle)) { +			// must be directory and not begin with a . +			if (substr($plugin_id, 0, 1) !== '.' && is_dir($dir . $plugin_id)) { +				$plugin_ids[] = $plugin_id; +			} +		} +	} + +	sort($plugin_ids); + +	return $plugin_ids; +} + +/** + * Discovers plugins in the plugins_path setting and creates ElggPlugin + * entities for them if they don't exist.  If there are plugins with entities + * but not actual files, will disable the ElggPlugin entities and mark as inactive. + * The ElggPlugin object holds config data, so don't delete. + * + * @todo Crappy name? + * @return bool + * @since 1.8.0 + * @access private + */ +function elgg_generate_plugin_entities() { +	// @todo $site unused, can remove? +	$site = get_config('site'); + +	$dir = elgg_get_plugins_path(); +	$db_prefix = elgg_get_config('dbprefix'); + +	$options = array( +		'type' => 'object', +		'subtype' => 'plugin', +		'selects' => array('plugin_oe.*'), +		'joins' => array("JOIN {$db_prefix}objects_entity plugin_oe on plugin_oe.guid = e.guid"), +		'limit' => ELGG_ENTITIES_NO_VALUE +	); + +	$old_ia = elgg_set_ignore_access(true); +	$old_access = access_get_show_hidden_status(); +	access_show_hidden_entities(true); +	$known_plugins = elgg_get_entities_from_relationship($options); +	/* @var ElggPlugin[] $known_plugins */ + +	if (!$known_plugins) { +		$known_plugins = array(); +	} + +	// map paths to indexes +	$id_map = array(); +	foreach ($known_plugins as $i => $plugin) { +		// if the ID is wrong, delete the plugin because we can never load it. +		$id = $plugin->getID(); +		if (!$id) { +			$plugin->delete(); +			unset($known_plugins[$i]); +			continue; +		} +		$id_map[$plugin->getID()] = $i; +	} + +	$physical_plugins = elgg_get_plugin_ids_in_dir($dir); + +	if (!$physical_plugins) { +		return false; +	} + +	// check real plugins against known ones +	foreach ($physical_plugins as $plugin_id) { +		// is this already in the db? +		if (array_key_exists($plugin_id, $id_map)) { +			$index = $id_map[$plugin_id]; +			$plugin = $known_plugins[$index]; +			// was this plugin deleted and its entity disabled? +			if (!$plugin->isEnabled()) { +				$plugin->enable(); +				$plugin->deactivate(); +				$plugin->setPriority('last'); +			} + +			// remove from the list of plugins to disable +			unset($known_plugins[$index]); +		} else { +			// add new plugins +			// priority is force to last in save() if not set. +			$plugin = new ElggPlugin($plugin_id); +			$plugin->save(); +		} +	} + +	// everything remaining in $known_plugins needs to be disabled +	// because they are entities, but their dirs were removed. +	// don't delete the entities because they hold settings. +	foreach ($known_plugins as $plugin) { +		if ($plugin->isActive()) { +			$plugin->deactivate(); +		} +		// remove the priority. +		$name = elgg_namespace_plugin_private_setting('internal', 'priority'); +		remove_private_setting($plugin->guid, $name); +		$plugin->disable(); +	} + +	access_show_hidden_entities($old_access); +	elgg_set_ignore_access($old_ia); + +	elgg_reindex_plugin_priorities(); + +	return true; +} + +/** + * Cache a reference to this plugin by its ID + *  + * @param ElggPlugin $plugin + *  + * @access private + */ +function _elgg_cache_plugin_by_id(ElggPlugin $plugin) { +	$map = (array) elgg_get_config('plugins_by_id_map'); +	$map[$plugin->getID()] = $plugin; +	elgg_set_config('plugins_by_id_map', $map); +} + +/** + * Returns an ElggPlugin object with the path $path. + * + * @param string $plugin_id The id (dir name) of the plugin. NOT the guid. + * @return ElggPlugin|false + * @since 1.8.0 + */ +function elgg_get_plugin_from_id($plugin_id) { +	$map = (array) elgg_get_config('plugins_by_id_map'); +	if (isset($map[$plugin_id])) { +		return $map[$plugin_id]; +	} + +	$plugin_id = sanitize_string($plugin_id); +	$db_prefix = get_config('dbprefix'); + +	$options = array( +		'type' => 'object', +		'subtype' => 'plugin', +		'joins' => array("JOIN {$db_prefix}objects_entity oe on oe.guid = e.guid"), +		'selects' => array("oe.title", "oe.description"), +		'wheres' => array("oe.title = '$plugin_id'"), +		'limit' => 1 +	); + +	$plugins = elgg_get_entities($options); + +	if ($plugins) { +		return $plugins[0]; +	} + +	return false; +} + +/** + * Returns if a plugin exists in the system. + * + * @warning This checks only plugins that are registered in the system! + * If the plugin cache is outdated, be sure to regenerate it with + * {@link elgg_generate_plugin_objects()} first. + * + * @param string $id The plugin ID. + * @since 1.8.0 + * @return bool + */ +function elgg_plugin_exists($id) { +	$plugin = elgg_get_plugin_from_id($id); + +	return ($plugin) ? true : false; +} + +/** + * Returns the highest priority of the plugins + * + * @return int + * @since 1.8.0 + * @access private + */ +function elgg_get_max_plugin_priority() { +	$db_prefix = get_config('dbprefix'); +	$priority = elgg_namespace_plugin_private_setting('internal', 'priority'); +	$plugin_subtype = get_subtype_id('object', 'plugin'); + +	$q = "SELECT MAX(CAST(ps.value AS unsigned)) as max +		FROM {$db_prefix}entities e, {$db_prefix}private_settings ps +		WHERE ps.name = '$priority' +		AND ps.entity_guid = e.guid +		AND e.type = 'object' and e.subtype = $plugin_subtype"; + +	$data = get_data($q); +	if ($data) { +		$max = $data[0]->max; +	} else { +		$max = 1; +	} + +	// can't have a priority of 0. +	return ($max) ? $max : 1; +} + +/** + * Returns if a plugin is active for a current site. + * + * @param string $plugin_id The plugin ID + * @param int    $site_guid The site guid + * @since 1.8.0 + * @return bool + */ +function elgg_is_active_plugin($plugin_id, $site_guid = null) { +	if ($site_guid) { +		$site = get_entity($site_guid); +	} else { +		$site = elgg_get_site_entity(); +	} + +	if (!($site instanceof ElggSite)) { +		return false; +	} + +	$plugin = elgg_get_plugin_from_id($plugin_id); + +	if (!$plugin) { +		return false; +	} + +	return $plugin->isActive($site->guid); +} + +/** + * Loads all active plugins in the order specified in the tool admin panel. + * + * @note This is called on every page load. If a plugin is active and problematic, it + * will be disabled and a visible error emitted. This does not check the deps system because + * that was too slow. + * + * @return bool + * @since 1.8.0 + * @access private + */ +function elgg_load_plugins() { +	$plugins_path = elgg_get_plugins_path(); +	$start_flags = ELGG_PLUGIN_INCLUDE_START | +					ELGG_PLUGIN_REGISTER_VIEWS | +					ELGG_PLUGIN_REGISTER_LANGUAGES | +					ELGG_PLUGIN_REGISTER_CLASSES; + +	if (!$plugins_path) { +		return false; +	} + +	// temporary disable all plugins if there is a file called 'disabled' in the plugin dir +	if (file_exists("$plugins_path/disabled")) { +		if (elgg_is_admin_logged_in() && elgg_in_context('admin')) { +			system_message(elgg_echo('plugins:disabled')); +		} +		return false; +	} + +	if (elgg_get_config('system_cache_loaded')) { +		$start_flags = $start_flags & ~ELGG_PLUGIN_REGISTER_VIEWS; +	} + +	if (elgg_get_config('i18n_loaded_from_cache')) { +		$start_flags = $start_flags & ~ELGG_PLUGIN_REGISTER_LANGUAGES; +	} + +	$return = true; +	$plugins = elgg_get_plugins('active'); +	if ($plugins) { +		foreach ($plugins as $plugin) { +			try { +				$plugin->start($start_flags); +			} catch (Exception $e) { +				$plugin->deactivate(); +				$msg = elgg_echo('PluginException:CannotStart', +								array($plugin->getID(), $plugin->guid, $e->getMessage())); +				elgg_add_admin_notice('cannot_start' . $plugin->getID(), $msg); +				$return = false; + +				continue; +			} +		} +	} + +	return $return; +} + +/** + * Returns an ordered list of plugins + * + * @param string $status      The status of the plugins. active, inactive, or all. + * @param mixed  $site_guid   Optional site guid + * @return ElggPlugin[] + * @since 1.8.0 + * @access private + */ +function elgg_get_plugins($status = 'active', $site_guid = null) { +	$db_prefix = get_config('dbprefix'); +	$priority = elgg_namespace_plugin_private_setting('internal', 'priority'); + +	if (!$site_guid) { +		$site = get_config('site'); +		$site_guid = $site->guid; +	} + +	// grab plugins +	$options = array( +		'type' => 'object', +		'subtype' => 'plugin', +		'limit' => ELGG_ENTITIES_NO_VALUE, +		'selects' => array('plugin_oe.*'), +		'joins' => array( +			"JOIN {$db_prefix}private_settings ps on ps.entity_guid = e.guid", +			"JOIN {$db_prefix}objects_entity plugin_oe on plugin_oe.guid = e.guid" +			), +		'wheres' => array("ps.name = '$priority'"), +		'order_by' => "CAST(ps.value as unsigned), e.guid" +	); + +	switch ($status) { +		case 'active': +			$options['relationship'] = 'active_plugin'; +			$options['relationship_guid'] = $site_guid; +			$options['inverse_relationship'] = true; +			break; + +		case 'inactive': +			$options['wheres'][] = "NOT EXISTS ( +					SELECT 1 FROM {$db_prefix}entity_relationships active_er +					WHERE active_er.guid_one = e.guid +						AND active_er.relationship = 'active_plugin' +						AND active_er.guid_two = $site_guid)"; +			break; + +		case 'all': +		default: +			break; +	} + +	$old_ia = elgg_set_ignore_access(true); +	$plugins = elgg_get_entities_from_relationship($options); +	elgg_set_ignore_access($old_ia); + +	return $plugins; +} + +/** + * Reorder plugins to an order specified by the array. + * Plugins not included in this array will be appended to the end. + * + * @note This doesn't use the ElggPlugin->setPriority() method because + *       all plugins are being changed and we don't want it to automatically + *       reorder plugins. + * + * @param array $order An array of plugin ids in the order to set them + * @return bool + * @since 1.8.0 + * @access private + */ +function elgg_set_plugin_priorities(array $order) { +	$name = elgg_namespace_plugin_private_setting('internal', 'priority'); + +	$plugins = elgg_get_plugins('any'); +	if (!$plugins) { +		return false; +	} + +	$return = true; + +	// reindex to get standard counting. no need to increment by 10. +	// though we do start with 1 +	$order = array_values($order); + +	$missing_plugins = array(); +	foreach ($plugins as $plugin) { +		$plugin_id = $plugin->getID(); + +		if (!in_array($plugin_id, $order)) { +			$missing_plugins[] = $plugin; +			continue; +		} + +		$priority = array_search($plugin_id, $order) + 1; + +		if (!$plugin->set($name, $priority)) { +			$return = false; +			break; +		} +	} + +	// set the missing plugins' priorities +	if ($return && $missing_plugins) { +		if (!isset($priority)) { +			$priority = 0; +		} +		foreach ($missing_plugins as $plugin) { +			$priority++; +			if (!$plugin->set($name, $priority)) { +				$return = false; +				break; +			} +		} +	} + +	return $return; +} + +/** + * Reindexes all plugin priorities starting at 1. + * + * @todo Can this be done in a single sql command? + * @return bool + * @since 1.8.0 + * @access private + */ +function elgg_reindex_plugin_priorities() { +	return elgg_set_plugin_priorities(array()); +} + +/** + * Namespaces a string to be used as a private setting for a plugin. + * + * @param string $type The type of value: user_setting or internal. + * @param string $name The name to namespace. + * @param string $id   The plugin's ID to namespace with.  Required for user_setting. + * @return string + * @since 1.8.0 + * @access private + */ +function elgg_namespace_plugin_private_setting($type, $name, $id = null) { +	switch ($type) { +		// commented out because it breaks $plugin->$name access to variables +		//case 'setting': +		//	$name = ELGG_PLUGIN_SETTING_PREFIX . $name; +		//	break; + +		case 'user_setting': +			if (!$id) { +				$id = elgg_get_calling_plugin_id(); +			} +			$name = ELGG_PLUGIN_USER_SETTING_PREFIX . "$id:$name"; +			break; + +		case 'internal': +			$name = ELGG_PLUGIN_INTERNAL_PREFIX . $name; +			break; +	} + +	return $name; +} + +/** + * Get the name of the most recent plugin to be called in the + * call stack (or the plugin that owns the current page, if any). + * + * i.e., if the last plugin was in /mod/foobar/, this would return foo_bar. + * + * @param boolean $mainfilename If set to true, this will instead determine the + *                              context from the main script filename called by + *                              the browser. Default = false. + * + * @return string|false Plugin name, or false if no plugin name was called + * @since 1.8.0 + * @access private + * + * @todo get rid of this + */ +function elgg_get_calling_plugin_id($mainfilename = false) { +	if (!$mainfilename) { +		if ($backtrace = debug_backtrace()) { +			foreach ($backtrace as $step) { +				$file = $step['file']; +				$file = str_replace("\\", "/", $file); +				$file = str_replace("//", "/", $file); +				if (preg_match("/mod\/([a-zA-Z0-9\-\_]*)\/start\.php$/", $file, $matches)) { +					return $matches[1]; +				} +			} +		} +	} else { +		//@todo this is a hack -- plugins do not have to match their page handler names! +		if ($handler = get_input('handler', FALSE)) { +			return $handler; +		} else { +			$file = $_SERVER["SCRIPT_NAME"]; +			$file = str_replace("\\", "/", $file); +			$file = str_replace("//", "/", $file); +			if (preg_match("/mod\/([a-zA-Z0-9\-\_]*)\//", $file, $matches)) { +				return $matches[1]; +			} +		} +	} +	return false; +} + +/** + * Returns an array of all provides from all active plugins. + * + * Array in the form array( + * 	'provide_type' => array( + * 		'provided_name' => array( + * 			'version' => '1.8', + * 			'provided_by' => 'provider_plugin_id' + *  	) + *  ) + * ) + * + * @param string $type The type of provides to return + * @param string $name A specific provided name to return. Requires $provide_type. + * + * @return array + * @since 1.8.0 + * @access private + */ +function elgg_get_plugins_provides($type = null, $name = null) { +	static $provides = null; +	$active_plugins = elgg_get_plugins('active'); + +	if (!isset($provides)) { +		$provides = array(); + +		foreach ($active_plugins as $plugin) { +			$plugin_provides = array(); +			$manifest = $plugin->getManifest(); +			if ($manifest instanceof ElggPluginManifest) { +				$plugin_provides = $plugin->getManifest()->getProvides(); +			} +			if ($plugin_provides) { +				foreach ($plugin_provides as $provided) { +					$provides[$provided['type']][$provided['name']] = array( +						'version' => $provided['version'], +						'provided_by' => $plugin->getID() +					); +				} +			} +		} +	} + +	if ($type && $name) { +		if (isset($provides[$type][$name])) { +			return $provides[$type][$name]; +		} else { +			return false; +		} +	} elseif ($type) { +		if (isset($provides[$type])) { +			return $provides[$type]; +		} else { +			return false; +		} +	} + +	return $provides; +} + +/** + * Checks if a plugin is currently providing $type and $name, and optionally + * checking a version. + * + * @param string $type       The type of the provide + * @param string $name       The name of the provide + * @param string $version    A version to check against + * @param string $comparison The comparison operator to use in version_compare() + * + * @return array An array in the form array( + * 	'status' => bool Does the provide exist?, + * 	'value' => string The version provided + * ) + * @since 1.8.0 + * @access private + */ +function elgg_check_plugins_provides($type, $name, $version = null, $comparison = 'ge') { +	$provided = elgg_get_plugins_provides($type, $name); +	if (!$provided) { +		return array( +			'status' => false, +			'version' => '' +		); +	} + +	if ($version) { +		$status = version_compare($provided['version'], $version, $comparison); +	} else { +		$status = true; +	} + +	return array( +		'status' => $status, +		'value' => $provided['version'] +	); +} + +/** + * Returns an array of parsed strings for a dependency in the + * format: array( + * 	'type'			=>	requires, conflicts, or provides. + * 	'name'			=>	The name of the requirement / conflict + * 	'value'			=>	A string representing the expected value: <1, >=3, !=enabled + * 	'local_value'	=>	The current value, ("Not installed") + * 	'comment'		=>	Free form text to help resovle the problem ("Enable / Search for plugin <link>") + * ) + * + * @param array $dep An ElggPluginPackage dependency array + * @return array + * @since 1.8.0 + * @access private + */ +function elgg_get_plugin_dependency_strings($dep) { +	$dep_system = elgg_extract('type', $dep); +	$info = elgg_extract('dep', $dep); +	$type = elgg_extract('type', $info); + +	if (!$dep_system || !$info || !$type) { +		return false; +	} + +	// rewrite some of these to be more readable +	switch($info['comparison']) { +		case 'lt': +			$comparison = '<'; +			break; +		case 'gt': +			$comparison = '>'; +			break; +		case 'ge': +			$comparison = '>='; +			break; +		case 'le': +			$comparison = '<='; +			break; +		default; +			$comparison = $info['comparison']; +			break; +	} + +	/* +	'requires'	'plugin oauth_lib'	<1.3	1.3		'downgrade' +	'requires'	'php setting bob'	>3		3		'change it' +	'conflicts'	'php setting'		>3		4		'change it' +	'conflicted''plugin profile'	any		1.8		'disable profile' +	'provides'	'plugin oauth_lib'	1.3		--		-- +	'priority'	'before blog'		--		after	'move it' +	*/ +	$strings = array(); +	$strings['type'] = elgg_echo('ElggPlugin:Dependencies:' . ucwords($dep_system)); + +	switch ($type) { +		case 'elgg_version': +		case 'elgg_release': +			// 'Elgg Version' +			$strings['name'] = elgg_echo('ElggPlugin:Dependencies:Elgg'); +			$strings['expected_value'] = "$comparison {$info['version']}"; +			$strings['local_value'] = $dep['value']; +			$strings['comment'] = ''; +			break; + +		case 'php_extension': +			// PHP Extension %s [version] +			$strings['name'] = elgg_echo('ElggPlugin:Dependencies:PhpExtension', array($info['name'])); +			if ($info['version']) { +				$strings['expected_value'] = "$comparison {$info['version']}"; +				$strings['local_value'] = $dep['value']; +			} else { +				$strings['expected_value'] = ''; +				$strings['local_value'] = ''; +			} +			$strings['comment'] = ''; +			break; + +		case 'php_ini': +			$strings['name'] = elgg_echo('ElggPlugin:Dependencies:PhpIni', array($info['name'])); +			$strings['expected_value'] = "$comparison {$info['value']}"; +			$strings['local_value'] = $dep['value']; +			$strings['comment'] = ''; +			break; + +		case 'plugin': +			$strings['name'] = elgg_echo('ElggPlugin:Dependencies:Plugin', array($info['name'])); +			$expected = $info['version'] ? "$comparison {$info['version']}" : elgg_echo('any'); +			$strings['expected_value'] = $expected; +			$strings['local_value'] = $dep['value'] ? $dep['value'] : '--'; +			$strings['comment'] = ''; +			break; + +		case 'priority': +			$expected_priority = ucwords($info['priority']); +			$real_priority = ucwords($dep['value']); +			$strings['name'] = elgg_echo('ElggPlugin:Dependencies:Priority'); +			$strings['expected_value'] = elgg_echo("ElggPlugin:Dependencies:Priority:$expected_priority", array($info['plugin'])); +			$strings['local_value'] = elgg_echo("ElggPlugin:Dependencies:Priority:$real_priority", array($info['plugin'])); +			$strings['comment'] = ''; +			break; +	} + +	if ($dep['type'] == 'suggests') { +		if ($dep['status']) { +			$strings['comment'] = elgg_echo('ok'); +		} else { +			$strings['comment'] = elgg_echo('ElggPlugin:Dependencies:Suggests:Unsatisfied'); +		} +	} else { +		if ($dep['status']) { +			$strings['comment'] = elgg_echo('ok'); +		} else { +			$strings['comment'] = elgg_echo('error'); +		} +	} + +	return $strings; +} + +/** + * Returns the ElggPlugin entity of the last plugin called. + * + * @return mixed ElggPlugin or false + * @since 1.8.0 + * @access private + */ +function elgg_get_calling_plugin_entity() { +	$plugin_id = elgg_get_calling_plugin_id(); + +	if ($plugin_id) { +		return elgg_get_plugin_from_id($plugin_id); +	} + +	return false; +} + +/** + * Returns an array of all plugin settings for a user. + * + * @param mixed  $user_guid  The user GUID or null for the currently logged in user. + * @param string $plugin_id  The plugin ID + * @param bool   $return_obj Return settings as an object? This can be used to in reusable + *                           views where the settings are passed as $vars['entity']. + * @return array + * @since 1.8.0 + */ +function elgg_get_all_plugin_user_settings($user_guid = null, $plugin_id = null, $return_obj = false) { +	if ($plugin_id) { +		$plugin = elgg_get_plugin_from_id($plugin_id); +	} else { +		$plugin = elgg_get_calling_plugin_entity(); +	} + +	if (!$plugin instanceof ElggPlugin) { +		return false; +	} + +	$settings = $plugin->getAllUserSettings($user_guid); + +	if ($settings && $return_obj) { +		$return = new stdClass; + +		foreach ($settings as $k => $v) { +			$return->$k = $v; +		} + +		return $return; +	} else { +		return $settings; +	} +} + +/** + * Set a user specific setting for a plugin. + * + * @param string $name      The name - note, can't be "title". + * @param mixed  $value     The value. + * @param int    $user_guid Optional user. + * @param string $plugin_id Optional plugin name, if not specified then it + *                          is detected from where you are calling from. + * + * @return bool + * @since 1.8.0 + */ +function elgg_set_plugin_user_setting($name, $value, $user_guid = null, $plugin_id = null) { +	if ($plugin_id) { +		$plugin = elgg_get_plugin_from_id($plugin_id); +	} else { +		$plugin = elgg_get_calling_plugin_entity(); +	} + +	if (!$plugin) { +		return false; +	} + +	return $plugin->setUserSetting($name, $value, $user_guid); +} + +/** + * Unsets a user-specific plugin setting + * + * @param string $name      Name of the setting + * @param int    $user_guid Defaults to logged in user + * @param string $plugin_id Defaults to contextual plugin name + * + * @return bool + * @since 1.8.0 + */ +function elgg_unset_plugin_user_setting($name, $user_guid = null, $plugin_id = null) { +	if ($plugin_id) { +		$plugin = elgg_get_plugin_from_id($plugin_id); +	} else { +		$plugin = elgg_get_calling_plugin_entity(); +	} + +	if (!$plugin) { +		return false; +	} + +	return $plugin->unsetUserSetting($name, $user_guid); +} + +/** + * Get a user specific setting for a plugin. + * + * @param string $name      The name of the setting. + * @param int    $user_guid Guid of owning user + * @param string $plugin_id Optional plugin name, if not specified + *                          it is detected from where you are calling. + * + * @return mixed + * @since 1.8.0 + */ +function elgg_get_plugin_user_setting($name, $user_guid = null, $plugin_id = null) { +	if ($plugin_id) { +		$plugin = elgg_get_plugin_from_id($plugin_id); +	} else { +		$plugin = elgg_get_calling_plugin_entity(); +	} + +	if (!$plugin) { +		return false; +	} + +	return $plugin->getUserSetting($name, $user_guid); +} + +/** + * Set a setting for a plugin. + * + * @param string $name      The name of the setting - note, can't be "title". + * @param mixed  $value     The value. + * @param string $plugin_id Optional plugin name, if not specified + *                          then it is detected from where you are calling from. + * + * @return bool + * @since 1.8.0 + */ +function elgg_set_plugin_setting($name, $value, $plugin_id = null) { +	if ($plugin_id) { +		$plugin = elgg_get_plugin_from_id($plugin_id); +	} else { +		$plugin = elgg_get_calling_plugin_entity(); +	} + +	if (!$plugin) { +		return false; +	} + +	return $plugin->setSetting($name, $value); +} + +/** + * Get setting for a plugin. + * + * @param string $name      The name of the setting. + * @param string $plugin_id Optional plugin name, if not specified + *                          then it is detected from where you are calling from. + * + * @return mixed + * @since 1.8.0 + * @todo make $plugin_id required in future version + */ +function elgg_get_plugin_setting($name, $plugin_id = null) { +	if ($plugin_id) { +		$plugin = elgg_get_plugin_from_id($plugin_id); +	} else { +		$plugin = elgg_get_calling_plugin_entity(); +	} + +	if (!$plugin) { +		return false; +	} + +	return $plugin->getSetting($name); +} + +/** + * Unsets a plugin setting. + * + * @param string $name      The name of the setting. + * @param string $plugin_id Optional plugin name, if not specified + *                          then it is detected from where you are calling from. + * + * @return bool + * @since 1.8.0 + */ +function elgg_unset_plugin_setting($name, $plugin_id = null) { +	if ($plugin_id) { +		$plugin = elgg_get_plugin_from_id($plugin_id); +	} else { +		$plugin = elgg_get_calling_plugin_entity(); +	} + +	if (!$plugin) { +		return false; +	} + +	return $plugin->unsetSetting($name); +} + +/** + * Unsets all plugin settings for a plugin. + * + * @param string $plugin_id Optional plugin name, if not specified + *                          then it is detected from where you are calling from. + * + * @return bool + * @since 1.8.0 + */ +function elgg_unset_all_plugin_settings($plugin_id = null) { +	if ($plugin_id) { +		$plugin = elgg_get_plugin_from_id($plugin_id); +	} else { +		$plugin = elgg_get_calling_plugin_entity(); +	} + +	if (!$plugin) { +		return false; +	} + +	return $plugin->unsetAllSettings(); +} + +/** + * Returns entities based upon plugin settings. + * Takes all the options for {@see elgg_get_entities_from_private_settings()} + * in addition to the ones below. + * + * @param array $options Array in the format: + * + * 	plugin_id => NULL|STR The plugin id. Defaults to calling plugin + * + * 	plugin_user_setting_names => NULL|ARR private setting names + * + * 	plugin_user_setting_values => NULL|ARR metadata values + * + * 	plugin_user_setting_name_value_pairs => NULL|ARR ( + *                                         name => 'name', + *                                         value => 'value', + *                                         'operand' => '=', + *                                        ) + * 	                             Currently if multiple values are sent via + *                               an array (value => array('value1', 'value2') + *                               the pair's operand will be forced to "IN". + * + * 	plugin_user_setting_name_value_pairs_operator => NULL|STR The operator to use for combining + *                                        (name = value) OPERATOR (name = value); default AND + * + * @return mixed int If count, int. If not count, array. false on errors. + */ +function elgg_get_entities_from_plugin_user_settings(array $options = array()) { +	// if they're passing it don't bother +	if (!isset($options['plugin_id'])) { +		$options['plugin_id'] = elgg_get_calling_plugin_id(); +	} + +	$singulars = array('plugin_user_setting_name', 'plugin_user_setting_value', +		'plugin_user_setting_name_value_pair'); + +	$options = elgg_normalise_plural_options_array($options, $singulars); + +	// rewrite plugin_user_setting_name_* to the right PS ones. +	$map = array( +		'plugin_user_setting_names' => 'private_setting_names', +		'plugin_user_setting_values' => 'private_setting_values', +		'plugin_user_setting_name_value_pairs' => 'private_setting_name_value_pairs', +		'plugin_user_setting_name_value_pairs_operator' => 'private_setting_name_value_pairs_operator' +	); + +	foreach ($map as $plugin => $private) { +		if (!isset($options[$plugin])) { +			continue; +		} + +		if (isset($options[$private])) { +			if (!is_array($options[$private])) { +				$options[$private] = array($options[$private]); +			} + +			$options[$private] = array_merge($options[$private], $options[$plugin]); +		} else { +			$options[$private] = $options[$plugin]; +		} +	} + + +	$plugin_id = $options['plugin_id']; +	$prefix = elgg_namespace_plugin_private_setting('user_setting', '', $plugin_id); +	$options['private_setting_name_prefix'] = $prefix; + +	return elgg_get_entities_from_private_settings($options); +} + +/** + * Register object, plugin entities as ElggPlugin classes + * + * @return void + * @access private + */ +function plugin_run_once() { +	add_subtype("object", "plugin", "ElggPlugin"); +} + +/** + * Runs unit tests for the entity objects. + * + * @param string  $hook   unit_test + * @param string $type   system + * @param mixed  $value  Array of tests + * @param mixed  $params Params + * + * @return array + * @access private + */ +function plugins_test($hook, $type, $value, $params) { +	global $CONFIG; +	$value[] = $CONFIG->path . 'engine/tests/api/plugins.php'; +	return $value; +} + +/** + * Checks on deactivate plugin event if disabling it won't create unmet dependencies and blocks disable in such case. + * + * @param string $event  deactivate + * @param string $type   plugin + * @param array  $params Parameters array containing entry with ELggPlugin instance under 'plugin_entity' key + * @return bool  false to block plugin deactivation action + * + * @access private + */ +function _plugins_deactivate_dependency_check($event, $type, $params) { +	$plugin_id = $params['plugin_entity']->getManifest()->getPluginID(); +	$plugin_name = $params['plugin_entity']->getManifest()->getName(); + +	$active_plugins = elgg_get_plugins(); + +	$dependents = array(); +	foreach ($active_plugins as $plugin) { +		$manifest = $plugin->getManifest(); +		$requires = $manifest->getRequires(); + +		foreach ($requires as $required) { +			if ($required['type'] == 'plugin' && $required['name'] == $plugin_id) { +				// there are active dependents +				$dependents[$manifest->getPluginID()] = $plugin; +			} +		} +	} + +	if ($dependents) { +		$list = '<ul>'; +		// construct error message and prevent disabling +		foreach ($dependents as $dependent) { +			$list .= '<li>' . $dependent->getManifest()->getName() . '</li>'; +		} +		$list .= '</ul>'; + +		register_error(elgg_echo('ElggPlugin:Dependencies:ActiveDependent', array($plugin_name, $list))); + +		return false; +	} +} + +/** + * Initialize the plugin system + * Listens to system init and registers actions + * + * @return void + * @access private + */ +function plugin_init() { +	run_function_once("plugin_run_once"); + +	elgg_register_plugin_hook_handler('unit_test', 'system', 'plugins_test'); +	 +	// note - plugins are booted by the time this handler is registered +	// deactivation due to error may have already occurred +	elgg_register_event_handler('deactivate', 'plugin', '_plugins_deactivate_dependency_check'); + +	elgg_register_action("plugins/settings/save", '', 'admin'); +	elgg_register_action("plugins/usersettings/save"); + +	elgg_register_action('admin/plugins/activate', '', 'admin'); +	elgg_register_action('admin/plugins/deactivate', '', 'admin'); +	elgg_register_action('admin/plugins/activate_all', '', 'admin'); +	elgg_register_action('admin/plugins/deactivate_all', '', 'admin'); + +	elgg_register_action('admin/plugins/set_priority', '', 'admin'); + +	elgg_register_library('elgg:markdown', elgg_get_root_path() . 'vendors/markdown/markdown.php'); +} + +elgg_register_event_handler('init', 'system', 'plugin_init'); | 
