diff options
author | brettp <brettp@36083f99-b078-4883-b0ff-0f9b5a30f544> | 2011-01-02 23:00:23 +0000 |
---|---|---|
committer | brettp <brettp@36083f99-b078-4883-b0ff-0f9b5a30f544> | 2011-01-02 23:00:23 +0000 |
commit | fc21edb0785f2cac11dc592278fad97fffeeb082 (patch) | |
tree | 24047873840c5931766abaa5b15a73c0692e7565 /engine/lib | |
parent | a826bea54e8934c19b2ada619d966cc7d9628b42 (diff) | |
download | elgg-fc21edb0785f2cac11dc592278fad97fffeeb082.tar.gz elgg-fc21edb0785f2cac11dc592278fad97fffeeb082.tar.bz2 |
Fixes #1986, #2170, #2225, #2759. Integrated ElggPluginPackage and ElggPluginManifest with ElggPlugin. System now uses ElggPlugin objects to determin plugins. Order is stored in private settings. This absolutely requires running upgrade.php.
git-svn-id: http://code.elgg.org/elgg/trunk@7817 36083f99-b078-4883-b0ff-0f9b5a30f544
Diffstat (limited to 'engine/lib')
-rw-r--r-- | engine/lib/plugins.php | 1134 | ||||
-rw-r--r-- | engine/lib/upgrades/2011010101.php | 75 |
2 files changed, 756 insertions, 453 deletions
diff --git a/engine/lib/plugins.php b/engine/lib/plugins.php index 29f55926c..cd74353de 100644 --- a/engine/lib/plugins.php +++ b/engine/lib/plugins.php @@ -7,202 +7,296 @@ * @subpackage Plugins */ -/// Cache enabled plugins per page -$ENABLED_PLUGINS_CACHE = NULL; +/** + * Tells ElggPlugin::start() to include the start.php file. + */ +define('ELGG_PLUGIN_INCLUDE_START', 1); /** - * Returns a list of plugins to load, in the order that they should be loaded. + * 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 * - * @return array List of plugins + * @todo Can't namespace these because many plugins directly call + * private settings via $entity->$name. */ -function get_plugin_list() { - global $CONFIG; +//define('ELGG_PLUGIN_SETTING_PREFIX', 'plugin:setting:'); - if (!empty($CONFIG->pluginlistcache)) { - return $CONFIG->pluginlistcache; - } +/** + * Prefix for plugin user setting names + */ +define('ELGG_PLUGIN_USER_SETTING_PREFIX', 'plugin:user_setting:'); - if ($site = get_entity($CONFIG->site_guid)) { - $pluginorder = $site->pluginorder; - if (!empty($pluginorder)) { - $plugins = unserialize($pluginorder); +/** + * Internal settings prefix + * + * @todo This could be resolved by promoting ElggPlugin to a 5th type. + */ +define('ELGG_PLUGIN_INTERNAL_PREFIX', 'elgg:internal:'); - $CONFIG->pluginlistcache = $plugins; - return $plugins; - } else { - // this only runs on install, otherwise uses serialized plugin order - $plugins = array(); - - if ($handle = opendir($CONFIG->pluginspath)) { - while ($mod = readdir($handle)) { - // must be directory and not begin with a . - if (substr($mod, 0, 1) !== '.' && is_dir($CONFIG->pluginspath . "/" . $mod)) { - $plugins[] = $mod; - } - } - } - sort($plugins); +/** + * 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 + */ +function elgg_get_plugin_ids_in_dir($dir = null) { + if (!$dir) { + $dir = elgg_get_plugin_path(); + } + + $plugin_idss = array(); + $handle = opendir($dir); - $CONFIG->pluginlistcache = $plugins; - return $plugins; + 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; + } } } - return false; + sort($plugin_ids); + + return $plugin_ids; } /** - * Regenerates the list of known plugins and saves it to the current site - * - * Important: You should regenerate simplecache and the viewpath cache after executing this function - * otherwise you may experience view display artifacts. Do this with the following code: + * 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. * - * elgg_view_regenerate_simplecache(); - * elgg_filepath_cache_reset(); - * - * @param array $pluginorder Optionally, a list of existing plugins and their orders - * - * @return array The new list of plugins and their orders + * @todo Crappy name? + * @return bool */ -function regenerate_plugin_list($pluginorder = FALSE) { - global $CONFIG; - - $CONFIG->pluginlistcache = NULL; +function elgg_generate_plugin_entities() { + $site = get_config('site'); + $dir = elgg_get_plugin_path(); + + $options = array( + 'type' => 'object', + 'subtype' => 'plugin', + '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); + + if (!$known_plugins) { + $known_plugins = array(); + } - if ($site = get_entity($CONFIG->site_guid)) { - if (empty($pluginorder)) { - $pluginorder = $site->pluginorder; - $pluginorder = unserialize($pluginorder); - } else { - ksort($pluginorder); + // 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; + } - if (empty($pluginorder)) { - $pluginorder = array(); - } + $physical_plugins = elgg_get_plugin_ids_in_dir($dir); - $max = 0; - if (sizeof($pluginorder)) { - foreach ($pluginorder as $key => $plugin) { - if (is_dir($CONFIG->pluginspath . "/" . $plugin)) { - if ($key > $max) { - $max = $key; - } - } else { - unset($pluginorder[$key]); - } - } - } - // Add new plugins to the end - if ($handle = opendir($CONFIG->pluginspath)) { - while ($mod = readdir($handle)) { - // must be directory and not begin with a . - if (substr($mod, 0, 1) !== '.' && is_dir($CONFIG->pluginspath . "/" . $mod)) { - if (!in_array($mod, $pluginorder)) { - $max = $max + 10; - $pluginorder[$max] = $mod; - } - } + if (!$physical_plugins) { + return false; + } + + $new_plugin_priority = elgg_get_max_plugin_priority() + 1; + + // 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->enabled != 'yes') { + $plugin->enable(); + $plugin->deactivate(); } - } - ksort($pluginorder); + // remove from the list of plugins to disable + unset($known_plugins[$index]); + } else { + // add new plugins + $plugin = new ElggPlugin($plugin_id); + $plugin->save(); + $plugin->setPriority($new_plugin_priority); - // Now reorder the keys .. - $key = 10; - $plugins = array(); - if (sizeof($pluginorder)) { - foreach ($pluginorder as $plugin) { - $plugins[$key] = $plugin; - $key = $key + 10; - } + $new_plugin_priority++; } + } - $plugins = serialize($plugins); + // 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) { + $plugin->deactivate(); + $plugin->disable(); + } + + access_show_hidden_entities($old_access); + elgg_set_ignore_access($old_ia); - $site->pluginorder = $plugins; + return true; +} - return $plugins; +/** + * Returns an ElggPlugin object with the path $path. + * + * @param string $id The id (dir name) of the plugin. NOT the guid. + * @return mixed ElggPlugin or false. + */ +function elgg_get_plugin_from_id($id) { + $id = sanitize_string($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"), + 'wheres' => array("oe.title = '$id'"), + 'limit' => 1 + ); + + $plugins = elgg_get_entities($options); + + if ($plugins) { + return $plugins[0]; } - return FALSE; + 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. + * @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 + */ +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) { + return $data[0]->max; + } + + // can't have a priority of 0. + return 1; +} /** - * For now, loads plugins directly + * Loads all active plugins in the order specified in the tool admin panel. * - * @todo Add proper plugin handler that launches plugins in an - * admin-defined order and activates them on admin request + * @note This is called on every page load and includes additional checking that plugins + * are fit to be loaded. If a plugin is active and problematic, it will be disabled + * and a visible error emitted. * - * @return void + * @return bool */ -function load_plugins() { +function elgg_load_plugins() { global $CONFIG; - if (empty($CONFIG->pluginspath)) { - return; + $plugins_path = elgg_get_plugin_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($CONFIG->pluginspath . "disabled")) { - return; + if (file_exists("$plugins_path/disabled")) { + return false; } - - // See if we have cached values for things + + // Load view caches if available $cached_view_paths = elgg_filepath_cache_load('views'); $cached_view_types = elgg_filepath_cache_load('view_types'); $cached_view_info = is_string($cached_view_paths) && is_string($cached_view_types); + if ($cached_view_info) { $CONFIG->views = unserialize($cached_view_paths); $CONFIG->view_types = unserialize($cached_view_types); + + // don't need to register views + $start_flags = $start_flags & ~ELGG_PLUGIN_REGISTER_VIEWS; } - $plugins = get_plugin_list(); - - if (sizeof($plugins)) { - foreach ($plugins as $mod) { - if (is_plugin_enabled($mod)) { - if (file_exists($CONFIG->pluginspath . $mod)) { - if (!include($CONFIG->pluginspath . $mod . "/start.php")) { - // automatically disable the bad plugin - disable_plugin($mod); - - // register error rather than rendering the site unusable with exception - register_error(sprintf(elgg_echo('PluginException:MisconfiguredPlugin'), $mod)); - - // continue loading remaining plugins - continue; - } - - if (!$cached_view_info) { - $view_dir = $CONFIG->pluginspath . $mod . '/views/'; - - if (is_dir($view_dir) && ($handle = opendir($view_dir))) { - while (FALSE !== ($view_type = readdir($handle))) { - $view_type_dir = $view_dir . $view_type; - - if ('.' !== substr($view_type, 0, 1) && is_dir($view_type_dir)) { - if (autoregister_views('', $view_type_dir, $view_dir, $view_type)) { - // add the valid view type. - if (!in_array($view_type, $CONFIG->view_types)) { - $CONFIG->view_types[] = $view_type; - } - } - } - } - } - } - - if (is_dir($CONFIG->pluginspath . "$mod/classes")) { - elgg_register_classes($CONFIG->pluginspath . "$mod/classes"); - } - - if (is_dir($CONFIG->pluginspath . $mod . "/languages")) { - register_translations($CONFIG->pluginspath . $mod . "/languages/"); - } - } + $return = true; + $plugins = elgg_get_plugins('active'); + if ($plugins) { + foreach ($plugins as $plugin) { + // check if plugin can be started and try to start it. + // if anything is bad, disable it and emit a message. + if (!$plugin->isValid()) { + $plugin->deactivate(); + $msg = elgg_echo('PluginException:MisconfiguredPlugin', array($plugin->getID(), $plugin->guid)); + register_error($msg); + $return = false; + + continue; + } + + try { + $plugin->start($start_flags); + } catch (Exception $e) { + $plugin->deactivate(); + $msg = elgg_echo('PluginException:CannotStart', + array($plugin->getID(), $plugin->guid, $e->getMessage())); + register_error($msg); + $return = false; + + continue; } } } @@ -212,21 +306,257 @@ function load_plugins() { elgg_filepath_cache_save('views', serialize($CONFIG->views)); elgg_filepath_cache_save('view_types', serialize($CONFIG->view_types)); } + + return $return; +} + +/** + * Returns an ordered list of plugins + * + * @param string $status The status of the plugins. active, inactive, or all. + * @param bool $include_deleted Include physically deleted (and so inactive and disabled) plugins? + * @param mixed $site_guid Optional site guid + * @return array + */ +function elgg_get_plugins($status = 'active', $include_deleted = false, $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, + 'joins' => array("JOIN {$db_prefix}private_settings ps on ps.entity_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; + } + + if ($include_deleted) { + $old_id = elgg_set_ignore_access(true); + } + + $plugins = elgg_get_entities_from_relationship($options); + + if ($include_deleted) { + 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 + */ +function elgg_set_plugin_priorities(array $order) { + $name = elgg_namespace_plugin_private_setting('internal', 'priority'); + + $plugins = elgg_get_plugins('any', true); + 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); + + 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 (!$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 + */ +function elgg_plugins_reindex_priorities() { + return elgg_set_plugin_priorities(array()); +} + +/** + * Returns a list of plugins to load, in the order that they should be loaded. + * + * @deprecated 1.8 + * + * @return array List of plugins + */ +function get_plugin_list() { + elgg_deprecated_notice('get_plugin_list() is deprecated by elgg_get_plugin_ids_in_dir() or elgg_get_plugins()', 1.8); + + $plugins = elgg_get_plugins('any'); + + $list = array(); + if ($plugins) { + foreach ($plugins as $i => $plugin) { + // in <=1.7 this returned indexed by multiples of 10. + // uh...sure...why not. + $index = ($i + 1) * 10; + $list[$index] = $plugin->getID(); + } + } + + return $list; +} + +/** + * Regenerates the list of known plugins and saves it to the current site + * + * Important: You should regenerate simplecache and the viewpath cache after executing this function + * otherwise you may experience view display artifacts. Do this with the following code: + * + * elgg_view_regenerate_simplecache(); + * elgg_filepath_cache_reset(); + * + * @deprecated 1.8 + * + * @param array $pluginorder Optionally, a list of existing plugins and their orders + * + * @return array The new list of plugins and their orders + */ +function regenerate_plugin_list($pluginorder = FALSE) { + $msg = 'regenerate_plugin_list() is (sorta) deprecated by elgg_generate_plugin_entities() and' + . ' elgg_set_plugin_priorities().'; + elgg_deprecated_notice($msg, 1.8); + + // they're probably trying to set it? + if ($pluginorder) { + if (elgg_generate_plugin_entities()) { + // sort the plugins by the index numerically since we used + // weird indexes in the old system. + ksort($pluginorder, SORT_NUMERIC); + return elgg_set_plugin_priorities($pluginorder); + } + return false; + } else { + // they're probably trying to regenerate from disk? + return elgg_generate_plugin_entities(); + } +} + + +/** + * Loads plugins + * + * @deprecate 1.8 + * + * @return bool + */ +function load_plugins() { + elgg_deprecated_notice('load_plugins() is deprecated by elgg_load_plugins()', 1.8); + + return elgg_load_plugins(); +} + + +/** + * 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 + */ +function elgg_namespace_plugin_private_setting($type, $name, $id = null) { + switch ($type) { +// 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/, get_plugin_name would return foo_bar. + * 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. * + * @since 1.8 + * * @return string|false Plugin name, or false if no plugin name was called */ -function get_plugin_name($mainfilename = false) { +function elgg_get_calling_plugin_id($mainfilename = false) { if (!$mainfilename) { if ($backtrace = debug_backtrace()) { foreach ($backtrace as $step) { @@ -254,31 +584,38 @@ function get_plugin_name($mainfilename = false) { } /** - * Load and parse a plugin manifest from a plugin XML file. + * 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). * - * Example file: + * i.e., if the last plugin was in /mod/foobar/, get_plugin_name would return foo_bar. * - * <plugin_manifest> - * <!-- Basic information --> - * <field key="name" value="My Plugin" /> - * <field key="description" value="My Plugin's concise description" /> - * <field key="version" value="1.0" /> - * <field key="category" value="theme" /> - * <field key="category" value="bundled" /> - * <field key="screenshot" value="path/relative/to/my_plugin.jpg" /> - * <field key="screenshot" value="path/relative/to/my_plugin_2.jpg" /> + * @deprecated 1.8 * - * <field key="author" value="Curverider Ltd" /> - * <field key="website" value="http://www.elgg.org/" /> - * <field key="copyright" value="(C) Curverider 2008-2010" /> - * <field key="licence" value="GNU Public License version 2" /> - * </plugin_manifest> + * @param boolean $mainfilename If set to true, this will instead determine the + * context from the main script filename called by + * the browser. Default = false. * - * @param string $plugin Plugin name. + * @return string|false Plugin name, or false if no plugin name was called + */ +function get_plugin_name($mainfilename = false) { + elgg_deprecated_notice('get_plugin_name() is deprecated by elgg_get_calling_plugin_id()', 1.8); + + return elgg_get_calling_plugin_id($mainfilename); +} + +/** + * Load and parse a plugin manifest from a plugin XML file. + * + * @example plugins/manifest.xml Example 1.8-style manifest file. + * + * @deprecated 1.8 * + * @param string $plugin Plugin name. * @return array of values */ function load_plugin_manifest($plugin) { + elgg_deprecated_notice('load_plugin_manifest() is deprecated by ElggPlugin->getManifest()', 1.8); + $xml_file = elgg_get_plugin_path() . "$plugin/manifest.xml"; try { @@ -294,11 +631,14 @@ function load_plugin_manifest($plugin) { * This function checks a plugin manifest 'elgg_version' value against the current install * returning TRUE if the elgg_version is >= the current install's version. * - * @param string $manifest_elgg_version_string The build version (eg 2009010201). + * @deprecated 1.8 * + * @param string $manifest_elgg_version_string The build version (eg 2009010201). * @return bool */ function check_plugin_compatibility($manifest_elgg_version_string) { + elgg_deprecated_notice('check_plugin_compatibility() is deprecated by ElggPlugin->canActivate()', 1.8); + $version = get_version(); if (strpos($manifest_elgg_version_string, '.') === false) { @@ -327,6 +667,7 @@ function check_plugin_compatibility($manifest_elgg_version_string) { * @param string $name A specific provided name to return. Requires $provide_type. * * @return array + * @since 1.8 */ function elgg_get_plugins_provides($type = null, $name = null) { static $provides = null; @@ -377,6 +718,7 @@ function elgg_get_plugins_provides($type = null, $name = null) { * @param string $comparison The comparison operator to use in version_compare() * * @return bool + * @since 1.8 */ function elgg_check_plugins_provides($type, $name, $version = null, $comparison = 'ge') { if (!$provided = elgg_get_plugins_provides($type, $name)) { @@ -395,25 +737,33 @@ function elgg_check_plugins_provides($type, $name, $version = null, $comparison /** * Shorthand function for finding the plugin settings. * - * @param string $plugin_name Optional plugin name, if not specified - * then it is detected from where you are calling from. + * @deprecated 1.8 + * + * @param string $plugin_id Optional plugin id, if not specified + * then it is detected from where you are calling. * * @return mixed */ -function find_plugin_settings($plugin_name = "") { - $options = array('type' => 'object', 'subtype' => 'plugin', 'limit' => 9999); - $plugins = elgg_get_entities($options); - $plugin_name = sanitise_string($plugin_name); - if (!$plugin_name) { - $plugin_name = get_plugin_name(); +function find_plugin_settings($plugin_id = null) { + elgg_deprecated_notice('find_plugin_setting() is deprecated by elgg_get_calling_plugin_entity() or elgg_get_plugin_from_id()', 1.8); + if ($plugin_id) { + return elgg_get_plugin_from_id($plugin_id); + } else { + return elgg_get_calling_plugin_entity(); } +} - if ($plugins) { - foreach ($plugins as $plugin) { - if (strcmp($plugin->title, $plugin_name) == 0) { - return $plugin; - } - } +/** + * Returns the ElggPlugin entity of the last plugin called. + * + * @return mixed ElggPlugin or false + * @since 1.8 + */ +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; @@ -422,34 +772,41 @@ function find_plugin_settings($plugin_name = "") { /** * Find the plugin settings for a user. * - * @param string $plugin_name Plugin name. - * @param int $user_guid The guid who's settings to retrieve. + * @param string $plugin_id Plugin name. + * @param int $user_guid The guid who's settings to retrieve. * * @return array of settings in an associative array minus prefix. */ -function find_plugin_usersettings($plugin_name = "", $user_guid = 0) { - $plugin_name = sanitise_string($plugin_name); +function find_plugin_usersettings($plugin_id = null, $user_guid = 0) { + $plugin_id = sanitise_string($plugin_id); $user_guid = (int)$user_guid; + $db_prefix = get_config('db_prefix'); + $ps_prefix = elgg_namespace_plugin_private_setting('user_setting', "$plugin_id:"); + $ps_prefix_len = strlen($ps_prefix); - if (!$plugin_name) { - $plugin_name = get_plugin_name(); + if (!$plugin_id) { + $plugin_id = elgg_get_calling_plugin_id(); } if ($user_guid == 0) { $user_guid = get_loggedin_userid(); } - // Get metadata for user - $all_metadata = get_all_private_settings($user_guid); //get_metadata_for_entity($user_guid); - if ($all_metadata) { - $prefix = "plugin:settings:$plugin_name:"; + // Get private settings for user + $q = "SELECT * FROM {$db_prefix}private_settings + WHERE entity_guid = $user_guid + AND name LIKE '$ps_prefix$plugin_id'"; + + $private_settings = get_data($q); + if ($private_settings) { $return = new stdClass; - foreach ($all_metadata as $key => $meta) { - $name = substr($key, strlen($prefix)); - $value = $meta; + foreach ($private_settings as $setting) { + $name = substr($setting->name, $ps_prefix_len); + $value = $setting->value; - if (strpos($key, $prefix) === 0) { + // @todo why? + if (strpos($key, $ps_prefix) === 0) { $return->$name = $value; } } @@ -463,21 +820,21 @@ function find_plugin_usersettings($plugin_name = "", $user_guid = 0) { /** * 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_name Optional plugin name, if not specified then it - * is detected from where you are calling from. + * @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 */ -function set_plugin_usersetting($name, $value, $user_guid = 0, $plugin_name = "") { - $plugin_name = sanitise_string($plugin_name); +function set_plugin_usersetting($name, $value, $user_guid = 0, $plugin_id = "") { + $plugin_id = sanitise_string($plugin_id); $user_guid = (int)$user_guid; $name = sanitise_string($name); - if (!$plugin_name) { - $plugin_name = get_plugin_name(); + if (!$plugin_id) { + $plugin_id = elgg_get_calling_plugin_id(); } $user = get_entity($user_guid); @@ -486,19 +843,17 @@ function set_plugin_usersetting($name, $value, $user_guid = 0, $plugin_name = "" } if (($user) && ($user instanceof ElggUser)) { - $prefix = "plugin:settings:$plugin_name:$name"; - //$user->$prefix = $value; - //$user->save(); + $name = elgg_namespace_plugin_private_setting('user_setting', "$plugin_id:$name"); // Hook to validate setting $value = elgg_trigger_plugin_hook('plugin:usersetting', 'user', array( 'user' => $user, - 'plugin' => $plugin_name, + 'plugin' => $plugin_id, 'name' => $name, 'value' => $value ), $value); - return set_private_setting($user->guid, $prefix, $value); + return set_private_setting($user->guid, $name, $value); } return false; @@ -507,18 +862,18 @@ function set_plugin_usersetting($name, $value, $user_guid = 0, $plugin_name = "" /** * Clears a user-specific plugin setting * - * @param str $name Name of the plugin setting - * @param int $user_guid Defaults to logged in user - * @param str $plugin_name Defaults to contextual plugin name + * @param str $name Name of the plugin setting + * @param int $user_guid Defaults to logged in user + * @param str $plugin_id Defaults to contextual plugin name * * @return bool Success */ -function clear_plugin_usersetting($name, $user_guid = 0, $plugin_name = '') { - $plugin_name = sanitise_string($plugin_name); +function clear_plugin_usersetting($name, $user_guid = 0, $plugin_id = '') { + $plugin_id = sanitise_string($plugin_id); $name = sanitise_string($name); - if (!$plugin_name) { - $plugin_name = get_plugin_name(); + if (!$plugin_id) { + $plugin_id = elgg_get_calling_plugin_id(); } $user = get_entity((int) $user_guid); @@ -527,7 +882,7 @@ function clear_plugin_usersetting($name, $user_guid = 0, $plugin_name = '') { } if (($user) && ($user instanceof ElggUser)) { - $prefix = "plugin:settings:$plugin_name:$name"; + $prefix = elgg_namespace_plugin_private_setting('user_setting', "$plugin_id:$name"); return remove_private_setting($user->getGUID(), $prefix); } @@ -538,20 +893,20 @@ function clear_plugin_usersetting($name, $user_guid = 0, $plugin_name = '') { /** * Get a user specific setting for a plugin. * - * @param string $name The name. - * @param int $user_guid Guid of owning user - * @param string $plugin_name Optional plugin name, if not specified + * @param string $name The name. + * @param int $user_guid Guid of owning user + * @param string $plugin_id Optional plugin name, if not specified * then it is detected from where you are calling from. * * @return mixed */ -function get_plugin_usersetting($name, $user_guid = 0, $plugin_name = "") { - $plugin_name = sanitise_string($plugin_name); +function get_plugin_usersetting($name, $user_guid = 0, $plugin_id = "") { + $plugin_id = sanitise_string($plugin_id); $user_guid = (int)$user_guid; $name = sanitise_string($name); - if (!$plugin_name) { - $plugin_name = get_plugin_name(); + if (!$plugin_id) { + $plugin_id = elgg_get_calling_plugin_id(); } $user = get_entity($user_guid); @@ -560,8 +915,8 @@ function get_plugin_usersetting($name, $user_guid = 0, $plugin_name = "") { } if (($user) && ($user instanceof ElggUser)) { - $prefix = "plugin:settings:$plugin_name:$name"; - return get_private_setting($user->guid, $prefix); + $name = elgg_namespace_plugin_private_setting('user_setting', "$plugin_id:$name"); + return get_private_setting($user->guid, $name); } return false; @@ -570,143 +925,126 @@ function get_plugin_usersetting($name, $user_guid = 0, $plugin_name = "") { /** * Set a setting for a plugin. * - * @param string $name The name - note, can't be "title". - * @param mixed $value The value. - * @param string $plugin_name Optional plugin name, if not specified - * then it is detected from where you are calling from. + * @param string $name The name - 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 int|false */ -function set_plugin_setting($name, $value, $plugin_name = "") { - if (!$plugin_name) { - $plugin_name = get_plugin_name(); +function 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(); } - $plugin = find_plugin_settings($plugin_name); if (!$plugin) { - $plugin = new ElggPlugin(); - } - - if ($name != 'title') { - // Hook to validate setting - $value = elgg_trigger_plugin_hook('plugin:setting', 'plugin', array( - 'plugin' => $plugin_name, - 'name' => $name, - 'value' => $value - ), $value); - - $plugin->title = $plugin_name; - $plugin->access_id = ACCESS_PUBLIC; - $plugin->save(); - $plugin->$name = $value; - - return $plugin->getGUID(); + return false; } - return false; + return $plugin->setSetting($name, $value); } /** * Get setting for a plugin. * - * @param string $name The name. - * @param string $plugin_name Optional plugin name, if not specified - * then it is detected from where you are calling from. + * @param string $name The name. + * @param string $plugin_id Optional plugin name, if not specified + * then it is detected from where you are calling from. * * @return mixed */ -function get_plugin_setting($name, $plugin_name = "") { - $plugin = find_plugin_settings($plugin_name); +function get_plugin_setting($name, $plugin_id = "") { + if ($plugin_id) { + $plugin = elgg_get_plugin_from_id($plugin_id); + } else { + $plugin = elgg_get_calling_plugin_entity(); + } - if ($plugin) { - return $plugin->$name; + if (!$plugin) { + return false; } - return false; + return $plugin->getSetting($name); } /** * Clear a plugin setting. * - * @param string $name The name. - * @param string $plugin_name Optional plugin name, if not specified - * then it is detected from where you are calling from. + * @param string $name The name. + * @param string $plugin_id Optional plugin name, if not specified + * then it is detected from where you are calling from. * * @return bool */ -function clear_plugin_setting($name, $plugin_name = "") { - $plugin = find_plugin_settings($plugin_name); +function clear_plugin_setting($name, $plugin_id = "") { + if ($plugin_id) { + $plugin = elgg_get_plugin_from_id($plugin_id); + } else { + $plugin = elgg_get_calling_plugin_entity(); + } - if ($plugin) { - return remove_private_setting($plugin->guid, $name); + if (!$plugin) { + return false; } - return FALSE; + return $plugin->removeSetting($name); } /** * Clear all plugin settings. * - * @param string $plugin_name Optional plugin name, if not specified - * then it is detected from where you are calling from. + * @param string $plugin_id Optional plugin name, if not specified + * then it is detected from where you are calling from. * * @return bool * @since 1.7.0 */ -function clear_all_plugin_settings($plugin_name = "") { - $plugin = find_plugin_settings($plugin_name); +function clear_all_plugin_settings($plugin_id = "") { + if ($plugin_id) { + $plugin = elgg_get_plugin_from_id($plugin_id); + } else { + $plugin = elgg_get_calling_plugin_entity(); + } if ($plugin) { - return remove_all_private_settings($plugin->guid); + $plugin->removeAllSettings(); } - return FALSE; + return false; } /** * Return an array of installed plugins. * + * @deprecated 1.8 + * * @param string $status any|enabled|disabled * @return array */ -function get_installed_plugins($status = 'any') { +function get_installed_plugins($status = 'all') { global $CONFIG; - $installed_plugins = array(); + elgg_deprecated_notice('get_installed_plugins() was deprecated by elgg_get_plugins()', 1.8); - if (!empty($CONFIG->pluginspath)) { - $plugins = get_plugin_list(); + $plugins = elgg_get_plugins($status); - foreach ($plugins as $mod) { - // require manifest. - if (!$manifest = load_plugin_manifest($mod)) { - continue; - } - - $enabled = is_plugin_enabled($mod); - - switch ($status) { - case 'enabled': - if ($enabled != true) { - continue 2; - } - break; - - case 'disabled': - if ($enabled == true) { - continue 2; - } - break; + if (!$plugins) { + return array(); + } - case 'any': - default: - break; - } + $installed_plugins = array(); - $installed_plugins[$mod] = array(); - $installed_plugins[$mod]['active'] = $enabled; - $installed_plugins[$mod]['manifest'] = $manifest; + foreach ($plugins as $plugin) { + if (!$plugin->isValid()) { + continue; } + + $installed_plugins[$plugin->getID()] = array( + 'active' => $plugin->isActive(), + 'manifest' => $plugin->manifest->getManifest() + ); } return $installed_plugins; @@ -721,82 +1059,36 @@ function get_installed_plugins($status = 'any') { * elgg_view_regenerate_simplecache(); * elgg_filepath_cache_reset(); * + * @deprecated 1.8 + * * @param string $plugin The plugin name. * @param int $site_guid The site id, if not specified then this is detected. * * @return array * @throws InvalidClassException */ -function enable_plugin($plugin, $site_guid = 0) { - global $CONFIG, $ENABLED_PLUGINS_CACHE; +function enable_plugin($plugin, $site_guid = null) { + elgg_deprecated_notice('enable_plugin() was deprecated by ElggPlugin->activate()', 1.8); $plugin = sanitise_string($plugin); - $site_guid = (int) $site_guid; - if ($site_guid == 0) { - $site_guid = $CONFIG->site_guid; - } - $site = get_entity($site_guid); - if (!($site instanceof ElggSite)) { - $msg = elgg_echo('InvalidClassException:NotValidElggStar', array($site_guid, "ElggSite")); - throw new InvalidClassException($msg); - } - - if (!$plugin_info = load_plugin_manifest($plugin)) { - return FALSE; + $site_guid = (int) $site_guid; + if (!$site_guid) { + $site = get_config('site'); + $site_guid = $site->guid; } - // getMetadata() doesn't return an array if only one plugin is enabled - if ($enabled = $site->enabled_plugins) { - if (!is_array($enabled)) { - $enabled = array($enabled); - } - } else { - $enabled = array(); + try { + $plugin = new ElggPlugin($plugin); + } catch(Exception $e) { + return false; } - $enabled[] = $plugin; - $enabled = array_unique($enabled); - - if ($return = $site->setMetaData('enabled_plugins', $enabled)) { - - // for other plugins that want to hook into this. - $params = array('plugin' => $plugin, 'manifest' => $plugin_info); - if ($return && !elgg_trigger_event('enable', 'plugin', $params)) { - $return = FALSE; - } - - // for this plugin's on_enable - if ($return && isset($plugin_info['on_enable'])) { - // pull in the actual plugin's start so the on_enable function is callable - // NB: this will not run re-run the init hooks! - $start = "{$CONFIG->pluginspath}$plugin/start.php"; - if (!file_exists($start) || !include($start)) { - $return = FALSE; - } - - // need language files for the messages - $translations = "{$CONFIG->pluginspath}$plugin/languages/"; - register_translations($translations); - if (!is_callable($plugin_info['on_enable'])) { - $return = FALSE; - } else { - $on_enable = call_user_func($plugin_info['on_enable']); - // allow null to mean "I don't care" like other subsystems - $return = ($on_disable === FALSE) ? FALSE : TRUE; - } - } - - // disable the plugin if the on_enable or trigger results failed - if (!$return) { - array_pop($enabled); - $site->setMetaData('enabled_plugins', $enabled); - } - - $ENABLED_PLUGINS_CACHE = $enabled; + if (!$plugin->canActivate($site_guid)) { + return false; } - return $return; + return $plugin->activate($site_guid); } /** @@ -808,6 +1100,8 @@ function enable_plugin($plugin, $site_guid = 0) { * elgg_view_regenerate_simplecache(); * elgg_filepath_cache_reset(); * + * @deprecated 1.8 + * * @param string $plugin The plugin name. * @param int $site_guid The site id, if not specified then this is detected. * @@ -815,118 +1109,53 @@ function enable_plugin($plugin, $site_guid = 0) { * @throws InvalidClassException */ function disable_plugin($plugin, $site_guid = 0) { - global $CONFIG, $ENABLED_PLUGINS_CACHE; + elgg_deprecated_notice('disable_plugin() was deprecated by ElggPlugin->deactivate()', 1.8); $plugin = sanitise_string($plugin); - $site_guid = (int) $site_guid; - if ($site_guid == 0) { - $site_guid = $CONFIG->site_guid; - } - - $site = get_entity($site_guid); - if (!($site instanceof ElggSite)) { - $msg = elgg_echo('InvalidClassException:NotValidElggStar', array($site_guid, "ElggSite")); - throw new InvalidClassException(); - } - if (!$plugin_info = load_plugin_manifest($plugin)) { - return FALSE; - } - - // getMetadata() doesn't return an array if only one plugin is enabled - if ($enabled = $site->enabled_plugins) { - if (!is_array($enabled)) { - $enabled = array($enabled); - } - } else { - $enabled = array(); - } - - $old_enabled = $enabled; - - // remove the disabled plugin from the array - if (FALSE !== $i = array_search($plugin, $enabled)) { - unset($enabled[$i]); + $site_guid = (int) $site_guid; + if (!$site_guid) { + $site = get_config('site'); + $site_guid = $site->guid; } - // if we're unsetting all the plugins, this will return an empty array. - // it will fail with FALSE, though. - $return = (FALSE === $site->enabled_plugins = $enabled) ? FALSE : TRUE; - - if ($return) { - // for other plugins that want to hook into this. - $params = array('plugin' => $plugin, 'manifest' => $plugin_info); - if ($return && !elgg_trigger_event('disable', 'plugin', $params)) { - $return = FALSE; - } - - // for this plugin's on_disable - if ($return && isset($plugin_info['on_disable'])) { - if (!is_callable($plugin_info['on_disable'])) { - $return = FALSE; - } else { - $on_disable = call_user_func($plugin_info['on_disable']); - // allow null to mean "I don't care" like other subsystems - $return = ($on_disable === FALSE) ? FALSE : TRUE; - } - } - - // disable the plugin if the on_enable or trigger results failed - if (!$return) { - $site->enabled_plugins = $old_enabled; - $ENABLED_PLUGINS_CACHE = $old_enabled; - } else { - $ENABLED_PLUGINS_CACHE = $enabled; - } + try { + $plugin = new ElggPlugin($plugin); + } catch(Exception $e) { + return false; } - return $return; + return $plugin->deactivate($site_guid); } /** * Return whether a plugin is enabled or not. * + * @deprecated 1.8 + * * @param string $plugin The plugin name. * @param int $site_guid The site id, if not specified then this is detected. * * @return bool - * @throws InvalidClassException */ function is_plugin_enabled($plugin, $site_guid = 0) { - global $CONFIG, $ENABLED_PLUGINS_CACHE; + elgg_deprecated_notice('is_plugin_enabled() was deprecated by ElggPlugin->isActive()', 1.8); - if (!file_exists($CONFIG->pluginspath . $plugin)) { - return false; - } + $plugin = sanitise_string($plugin); $site_guid = (int) $site_guid; - if ($site_guid == 0) { - $site_guid = $CONFIG->site_guid; + if (!$site_guid) { + $site = get_config('site'); + $site_guid = $site->guid; } - if (!$ENABLED_PLUGINS_CACHE) { - $site = get_entity($site_guid); - if (!($site instanceof ElggSite)) { - $msg = elgg_echo('InvalidClassException:NotValidElggStar', array($site_guid, "ElggSite")); - throw new InvalidClassException($msg); - } - - $enabled_plugins = $site->enabled_plugins; - if ($enabled_plugins && !is_array($enabled_plugins)) { - $enabled_plugins = array($enabled_plugins); - } - $ENABLED_PLUGINS_CACHE = $enabled_plugins; - } - - if (is_array($ENABLED_PLUGINS_CACHE)) { - foreach ($ENABLED_PLUGINS_CACHE as $e) { - if ($e == $plugin) { - return true; - } - } + try { + $plugin = new ElggPlugin($plugin); + } catch(Exception $e) { + return false; } - return false; + return $plugin->isActive($site_guid); } /** @@ -935,7 +1164,6 @@ function is_plugin_enabled($plugin, $site_guid = 0) { * @return void */ function plugin_run_once() { - // Register a class add_subtype("object", "plugin", "ElggPlugin"); } @@ -978,4 +1206,4 @@ function plugin_init() { elgg_register_action('admin/plugins/reorder', '', 'admin'); } -elgg_register_event_handler('init', 'system', 'plugin_init'); +elgg_register_event_handler('init', 'system', 'plugin_init');
\ No newline at end of file diff --git a/engine/lib/upgrades/2011010101.php b/engine/lib/upgrades/2011010101.php new file mode 100644 index 000000000..eac5810c4 --- /dev/null +++ b/engine/lib/upgrades/2011010101.php @@ -0,0 +1,75 @@ +<?php +/** + * Migrate plugins to the new system using ElggPlugin and private settings + */ + +$old_ia = elgg_set_ignore_access(true); + +$site = get_config('site'); +$old_plugin_order = unserialize($site->pluginorder); +$old_enabled_plugins = $site->enabled_plugins; + +$db_prefix = get_config('dbprefix'); +$plugin_subtype_id = get_subtype_id('object', 'plugin'); + +// easy one first: make sure the the site owns all plugin entities. +$q = "UPDATE {$db_prefix}entities e + SET owner_guid = $site->guid, container_guid = $site->guid + WHERE e.type = 'object' AND e.subtype = $plugin_subtype_id"; + +$r = update_data($q); + +// rewrite all plugin:setting:* to ELGG_PLUGIN_USER_SETTING_PREFIX . * +$q = "UPDATE {$db_prefix}private_settings + SET name = replace(name, 'plugin:setting', '" . ELGG_PLUGIN_USER_SETTING_PREFIX . "') + WHERE name LIKE 'plugin:setting:%'"; + +$r = update_data($q); + +// grab current plugin GUIDs to add a temp priority +$q = "SELECT * FROM {$db_prefix}entities e + JOIN {$db_prefix}objects_entity oe ON e.guid = oe.guid + WHERE e.type = 'object' AND e.subtype = $plugin_subtype_id"; + +$plugins = get_data($q); + +foreach ($plugins as $plugin) { + $priority = elgg_namespace_plugin_private_setting('internal', 'priority'); + set_private_setting($plugin->guid, $priority, 0); +} + +// force regenerating plugin entities +elgg_generate_plugin_entities(); + +// set the priorities for all plugins +// this function rewrites it to a normal index so use the current one. +elgg_set_plugin_priorities($old_plugin_order); + +// add relationships for enabled plugins +if ($old_enabled_plugins) { + // they might only have one plugin enabled. + if (!is_array($old_enabled_plugins)) { + $old_enabled_plugins = array($old_enabled_plugins); + } + + // sometimes there were problems and you'd get 1000s of enabled plugins. + $old_enabled_plugins = array_unique($old_enabled_plugins); + + foreach ($old_enabled_plugins as $plugin_id) { + $plugin = elgg_get_plugin_from_id($plugin_id); + + if ($plugin) { + $plugin->activate(); + } + } +} + +// invalidate caches +elgg_invalidate_simplecache(); +elgg_filepath_cache_reset(); + +// clean up. +remove_metadata($site->guid, 'pluginorder'); +remove_metadata($site->guid, 'enabled_plugins'); + +elgg_set_ignore_access($old_id);
\ No newline at end of file |