aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbrettp <brettp@36083f99-b078-4883-b0ff-0f9b5a30f544>2011-01-02 23:00:23 +0000
committerbrettp <brettp@36083f99-b078-4883-b0ff-0f9b5a30f544>2011-01-02 23:00:23 +0000
commitfc21edb0785f2cac11dc592278fad97fffeeb082 (patch)
tree24047873840c5931766abaa5b15a73c0692e7565
parenta826bea54e8934c19b2ada619d966cc7d9628b42 (diff)
downloadelgg-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
-rw-r--r--documentation/examples/plugins/manifest.xml93
-rw-r--r--engine/classes/ElggPlugin.php739
-rw-r--r--engine/classes/ElggPluginManifest.php71
-rw-r--r--engine/classes/ElggPluginManifestParser18.php22
-rw-r--r--engine/classes/ElggPluginPackage.php25
-rw-r--r--engine/lib/plugins.php1134
-rw-r--r--engine/lib/upgrades/2011010101.php75
-rw-r--r--engine/tests/api/plugins.php28
-rw-r--r--engine/tests/test_files/plugin_18/manifest.xml11
-rw-r--r--languages/en.php14
-rw-r--r--version.php2
11 files changed, 1715 insertions, 499 deletions
diff --git a/documentation/examples/plugins/manifest.xml b/documentation/examples/plugins/manifest.xml
new file mode 100644
index 000000000..34dc82d2f
--- /dev/null
+++ b/documentation/examples/plugins/manifest.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin_manifest version="1.8">
+ <name>My Plugin</name>
+ <author>Elgg</author>
+ <version>1.0</version>
+ <blurb>A concise description.</blurb>
+ <description>This is a longer, more interesting description of my plugin, its features, and other important information.</description>
+ <website>http://www.elgg.org/</website>
+ <copyright>(C) Elgg 2010</copyright>
+ <license>GNU Public License version 2</license>
+
+ <requires>
+ <type>elgg_version</type>
+ <version>2009030802</version>
+ </requires>
+
+ <requires>
+ <type>elgg_release</type>
+ <version>1.8-svn</version>
+ </requires>
+
+ <screenshot>
+ <description>An example screenshot</description>
+ <path>graphics/plugin_ss1.png</path>
+ </screenshot>
+
+ <screenshot>
+ <description>Another screenshot</description>
+ <path>graphics/plugin_ss2.png</path>
+ </screenshot>
+
+ <category>Admin</category>
+ <category>ServiceAPI</category>
+
+ <on_enable>setup_function</on_enable>
+ <on_disable>teardown_function</on_disable>
+ <admin_interface>simple</admin_interface>
+
+ <requires>
+ <type>php_extension</type>
+ <name>gd</name>
+ </requires>
+
+ <requires>
+ <type>php_ini</type>
+ <name>short_open_tag</name>
+ <value>off</value>
+ </requires>
+
+ <requires>
+ <type>php_extension</type>
+ <name>made_up</name>
+ <version>1.0</version>
+ </requires>
+
+ <requires>
+ <type>plugin</type>
+ <name>fake_plugin</name>
+ <version>1.0</version>
+ </requires>
+
+ <requires>
+ <type>plugin</type>
+ <name>profile</name>
+ <version>1.0</version>
+ </requires>
+
+ <requires>
+ <type>plugin</type>
+ <name>profile_api</name>
+ <version>1.3</version>
+ <comparison>lt</comparison>
+ </requires>
+
+ <conflicts>
+ <type>plugin</type>
+ <name>profile_api</name>
+ <version>1.0</version>
+ </conflicts>
+
+ <provides>
+ <type>plugin</type>
+ <name>profile_api</name>
+ <version>1.3</version>
+ </provides>
+
+ <provides>
+ <type>php_extension</type>
+ <name>curl</name>
+ <version>1.0</version>
+ </provides>
+
+</plugin_manifest>
diff --git a/engine/classes/ElggPlugin.php b/engine/classes/ElggPlugin.php
index 887eb667f..fb9138ab9 100644
--- a/engine/classes/ElggPlugin.php
+++ b/engine/classes/ElggPlugin.php
@@ -9,6 +9,11 @@
* @subpackage Plugins.Settings
*/
class ElggPlugin extends ElggObject {
+ public $package;
+ public $manifest;
+
+ private $path;
+ private $pluginID;
/**
* Set subtype to 'plugin'
@@ -19,10 +24,704 @@ class ElggPlugin extends ElggObject {
parent::initializeAttributes();
$this->attributes['subtype'] = "plugin";
+
+ // plugins must be public.
+ $this->access_id = ACCESS_PUBLIC;
+ }
+
+
+ /**
+ * Loads the plugin by GUID or path.
+ *
+ * @warning Unlike other ElggEntity objects, you cannot null instantiate
+ * ElggPlugin. You must point it to an actual plugin GUID or location.
+ *
+ * @param mixed $plugin The GUID of the ElggPlugin object or the path of
+ * the plugin to load.
+ */
+ public function __construct($plugin) {
+ if (!$plugin) {
+ throw new PluginException(elgg_echo('PluginException:NullInstantiated'));
+ }
+
+ // ElggEntity can be instantiated with a guid or an object.
+ // @todo plugins w/id 12345
+ if (is_numeric($plugin) || is_object($plugin)) {
+ parent::__construct($plugin);
+ $this->path = get_config('plugins_path') . $this->getID();
+ } else {
+ // not a full path, so assume an id
+ // use the default path
+ if (substr($plugin, 0, 1) != '/') {
+ $plugin = elgg_get_plugin_path() . $plugin;
+ }
+
+ // path checking is done in the package
+ $plugin = sanitise_filepath($plugin);
+ $this->path = $plugin;
+ $path_parts = explode('/', rtrim($plugin, '/'));
+ $plugin_id = array_pop($path_parts);
+ $this->pluginID = $plugin_id;
+
+ // check if we're loading an existing plugin
+ $existing_plugin = elgg_get_plugin_from_id($this->pluginID);
+ $existing_guid = null;
+
+ if ($existing_plugin) {
+ $existing_guid = $existing_plugin->guid;
+ }
+
+ // load the rest of the plugin
+ parent::__construct($existing_guid);
+ }
+
+ // We have to let the entity load so we can manipulate it with the API.
+ // If the path is wrong or would cause an exception, catch it,
+ // disable the plugin, and emit an error.
+ try {
+ $this->package = new ElggPluginPackage($this->path, false);
+ $this->manifest = $this->package->getManifest();
+ } catch (Exception $e) {
+ // we always have to allow the entity to load.
+ }
+ }
+
+
+ /**
+ * Save the plugin object. Make sure required values exist.
+ *
+ * @see ElggObject::save()
+ * @return bool
+ */
+ public function save() {
+ // own by the current site so users can be deleted without affecting plugins
+ $site = get_config('site');
+ $this->attributes['site_guid'] = $site->guid;
+ $this->attributes['owner_guid'] = $site->guid;
+ $this->attributes['container_guid'] = $site->guid;
+ $this->attributes['title'] = $this->pluginID;
+
+ if (parent::save()) {
+ // make sure we have a priority
+ $priority = $this->getPriority();
+ if ($priority === FALSE || $priority === NULL) {
+ return $this->setPriority('last');
+ }
+ } else {
+ return false;
+ }
+ }
+
+
+ // Plugin ID
+
+ /**
+ * Returns the ID (dir name) of this plugin
+ *
+ * @return string
+ */
+ public function getID() {
+ return $this->title;
+ }
+
+
+ /**
+ * Sets the location of this plugin.
+ *
+ * @param path $id The path to the plugin's dir.
+ * @return bool
+ */
+ public function setID($id) {
+ return $this->attributes['title'] = $id;
+ }
+
+
+ // Load Priority
+
+ /**
+ * Gets the plugin's load priority.
+ *
+ * @return int
+ */
+ public function getPriority() {
+ $name = elgg_namespace_plugin_private_setting('internal', 'priority');
+ return $this->$name;
+ }
+
+
+ /**
+ * Sets the priority of the plugin
+ *
+ * @param mixed $priority The priority to set. One of +1, -1, first, last, or a number.
+ * If given a number, this will displace all plugins at that number
+ * and set their priorities +1
+ * @param mixed $site_guid Optional site GUID.
+ * @return bool
+ */
+ public function setPriority($priority, $site_guid = null) {
+ if (!$this->guid) {
+ return false;
+ }
+
+ $db_prefix = get_config('dbprefix');
+ $name = elgg_namespace_plugin_private_setting('internal', 'priority');
+ // if no priority assume a priority of 0
+ $old_priority = (int) $this->getPriority();
+ $max_priority = elgg_get_max_plugin_priority();
+
+ if ($priority == $old_priority) {
+ return false;
+ }
+
+ // there's nothing above the max.
+ if ($priority > $max_priority) {
+ $priority = $max_priority;
+ }
+
+ // there's nothing below 1.
+ if ($priority < 1) {
+ $priority = 1;
+ }
+
+ // (int) 0 matches (string) first, so cast to string.
+ $priority = (string) $priority;
+
+ switch ($priority) {
+ case '+1':
+ $priority = $old_priority + 1;
+ break;
+
+ case '-1':
+ $priority = $old_priority - 1;
+ break;
+
+ case 'first':
+ $priority = 1;
+ break;
+
+ case 'last':
+ $priority = $max_priority;
+ break;
+ }
+
+ // should be a number by now
+ if ($priority) {
+ if (!is_numeric($priority)) {
+ return false;
+ }
+
+ if ($priority > $old_priority) {
+ $op = '-';
+ $where = "CAST(value as unsigned) BETWEEN $old_priority AND $priority";
+ } else {
+ $op = '+';
+ $where = "CAST(value as unsigned) BETWEEN $priority AND $old_priority";
+ }
+
+ // displace the ones affected by this change
+ $q = "UPDATE {$db_prefix}private_settings
+ SET value = CAST(value as unsigned) $op 1
+ WHERE entity_guid != $this->guid
+ AND name = '$name'
+ AND $where";
+
+ if (!update_data($q)) {
+ return false;
+ }
+
+ // set this priority
+ if ($this->set($name, $priority)) {
+ //return elgg_plugins_reindex_priorities();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ return false;
+ }
+
+
+ // Plugin settings
+
+ /**
+ * Returns a plugin setting
+ *
+ * @todo These need to be namespaced
+ *
+ * @param string $name The setting name
+ * @return mixed
+ */
+ public function getSetting($name) {
+ return $this->$name;
+ }
+
+
+ /**
+ * Set a plugin setting for the plugin
+ *
+ * @todo This will only work once the plugin has a GUID.
+ * @todo These need to be namespaced.
+ *
+ * @param string $name The name to set
+ * @param string $value The value to set
+ *
+ * @return bool
+ */
+ public function setSetting($name, $value) {
+ if ($this->guid) {
+ return false;
+ }
+ // Hook to validate setting
+ $value = elgg_trigger_plugin_hook('plugin:setting', 'plugin', array(
+ 'plugin' => $this->pluginID,
+ 'plugin_object' => $this,
+ 'name' => $name,
+ 'value' => $value
+ ), $value);
+
+ return $this->$name = $value;
}
/**
+ * Removes a plugin setting name and value.
+ *
+ * @param string $name The setting name to remove
+ *
+ * @return bool
+ */
+ public function removeSetting($name) {
+ return remove_private_setting($this->guid, $name);
+ }
+
+
+ /**
+ * Removes all settings for this plugin.
+ *
+ * @todo Should be a better way to do this without dropping to raw SQL.
+ * @todo If we could namespace the plugin settings this would be cleaner.
+ * @return bool
+ */
+ public function removeAllSettings() {
+ $db_prefix = get_config('dbprefix');
+ $ps_prefix = elgg_namespace_plugin_private_setting('setting', '');
+
+ $q = "DELETE FROM {$db_prefix}private_settings
+ WHERE entity_guid = $this->guid
+ AND name NOT LIKE '$ps_prefix%'";
+
+ return delete_data($q);
+ }
+
+
+ // User settings
+
+ /**
+ * Returns a user's setting for this plugin
+ *
+ * @param int $user_guid The user GUID
+ * @param string $name The setting name
+ *
+ * @return mixed The setting string value or false
+ */
+ public function getUserSetting($user_guid, $name) {
+ $name = elgg_namespace_plugin_private_setting('user_setting', $name, $this->getID());
+ return get_private_setting($user_guid, $name);
+ }
+
+ /**
+ * Sets a user setting for a plugin
+ *
+ * @param int $user_guid The user GUID
+ * @param string $name The setting name
+ * @param string $value The setting value
+ *
+ * @return mixed The new setting ID or false
+ */
+ public function setUserSetting($user_guid, $name, $value) {
+ $name = elgg_namespace_plugin_private_setting('user_setting', $name, $this->getID());
+ return set_private_setting($user_guid, $name, $value);
+ }
+
+
+ /**
+ * Removes a user setting name and value.
+ *
+ * @param int $user_guid The user GUID
+ * @param string $name The user setting name
+ *
+ * @return bool
+ */
+ public function removeUserSetting($user_guid, $name) {
+ $name = elgg_namespace_plugin_private_setting('user_setting', $name, $this->getID());
+ return remove_private_setting($user_guid, $name);
+ }
+
+
+ /**
+ * Removes all User Settings for this plugin
+ *
+ * Use {@link removeAllUsersSettings()} to remove all user
+ * settings for all users. (Note the plural 'Users'.)
+ *
+ * @param int $user_guid The user GUID to remove user settings.
+ * @return bool
+ */
+ public function removeAllUserSettings($user_guid) {
+ $db_prefix = get_config('dbprefix');
+ $ps_prefix = elgg_namespace_plugin_private_setting('user_setting', '', $this->getID());
+
+ $q = "DELETE FROM {$db_prefix}private_settings
+ WHERE entity_guid = $user_guid
+ AND name LIKE '$ps_prefix%'";
+
+ return delete_data($q);
+ }
+
+
+ /**
+ * Removes this plugin's user settings for all users.
+ *
+ * Use {@link removeAllUserSettings()} if you just want to remove
+ * settings for a single user.
+ *
+ * @return bool
+ */
+ public function removeAllUsersSettings() {
+ $db_prefix = get_config('dbprefix');
+ $ps_prefix = elgg_namespace_plugin_private_setting('user_setting', '', $this->getID());
+
+ $q = "DELETE FROM {$db_prefix}private_settings
+ WHERE name LIKE '$ps_prefix%'";
+
+ return delete_data($q);
+ }
+
+
+ // validation
+
+ /**
+ * Returns if the plugin is complete, meaning has all required files
+ * and Elgg can read them and they make sense.
+ *
+ * @todo bad name? This could be confused with isValid() from ElggPackage.
+ *
+ * @return bool
+ */
+ public function isValid() {
+ if (!$this->getID()) {
+ return false;
+ }
+
+ if (!$this->package instanceof ElggPluginPackage) {
+ return false;
+ }
+
+ if (!$this->package->isValid()) {
+ return false;
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Is this plugin active?
+ *
+ * @param int $site_guid Optional site guid.
+ * @return bool
+ */
+ public function isActive($site_guid = null) {
+ if (!$this->guid) {
+ return false;
+ }
+
+ if ($site_guid) {
+ $site = get_entity($site_guid);
+
+ if (!($site instanceof ElggSite)) {
+ return false;
+ }
+ } else {
+ $site = get_config('site');
+ }
+
+ return check_entity_relationship($this->guid, 'active_plugin', $site->guid);
+ }
+
+
+ /**
+ * Checks if this plugin can be activated on the current
+ * Elgg installation.
+ *
+ * @param mixed $site_guid Optional site guid
+ * @return bool
+ */
+ public function canActivate($site_guid = null) {
+ if ($this->package) {
+ return $this->package->isValid() && $this->package->checkDependencies();
+ }
+
+ return false;
+ }
+
+
+ // activating and deactivating
+
+ /**
+ * Actives the plugin for the current site.
+ *
+ * @param mixed $site_guid Optional site GUID.
+ * @return bool
+ */
+ public function activate($site_guid = null) {
+ if ($this->isActive($site_guid)) {
+ return false;
+ }
+ // set in the db, now perform tasks and emit events
+ if ($this->setStatus(true, $site_guid)) {
+ // emit an event. returning false will make this not be activated.
+ // we need to do this after it's been fully activated
+ // or the deactivate will be confused.
+ $params = array(
+ 'plugin_id' => $this->pluginID,
+ 'plugin_entity' => $this
+ );
+
+ $return = elgg_trigger_event('activate', 'plugin', $params);
+
+ // if there are any on_enable functions, start the plugin now and run them
+ // Note: this will not run re-run the init hooks!
+ $functions = $this->manifest->getOnActivate();
+ if ($return && $functions) {
+ $flags = ELGG_PLUGIN_INCLUDE_START | ELGG_PLUGIN_REGISTER_CLASSES
+ | ELGG_PLUGIN_REGISTER_LANGUAGES | ELGG_PLUGIN_REGISTER_VIEWS;
+
+ $this->start($flags);
+ foreach ($functions as $function) {
+ if (!is_callable($function)) {
+ $return = false;
+ } else {
+ $on_enable = call_user_func($function);
+ // allow null to mean "I don't care" like other subsystems
+ $return = ($on_disable === false) ? false: true;
+ }
+
+ if ($return === false) {
+ break;
+ }
+ }
+ }
+
+ if ($return === false) {
+ $this->deactivate($site_guid);
+ }
+
+ return $return;
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Deactivates the plugin.
+ *
+ * @param mixed $site_guid Optional site GUID.
+ * @return bool
+ */
+ public function deactivate($site_guid = null) {
+ if (!$this->isActive($site_guid)) {
+ return false;
+ }
+
+ // emit an event. returning false will cause this to not be deactivated.
+ $params = array(
+ 'plugin_id' => $this->pluginID,
+ 'plugin_entity' => $this
+ );
+
+ $return = elgg_trigger_event('deactivate', 'plugin', $params);
+
+ // run any deactivate functions
+ // check for the manifest in case we haven't fully loaded the plugin.
+ if ($this->manifest) {
+ $functions = $this->manifest->getOnDeactivate();
+ } else {
+ $functions = array();
+ }
+
+ if ($return && $functions) {
+ foreach ($functions as $function) {
+ if (!is_callable($function)) {
+ $return = false;
+ } else {
+ $on_enable = call_user_func($function);
+ // allow null to mean "I don't care" like other subsystems
+ $return = ($on_disable === false) ? false : true;
+ }
+
+ if ($return === false) {
+ break;
+ }
+ }
+ }
+
+ if ($return === false) {
+ return false;
+ } else {
+ return $this->setStatus(false, $site_guid);
+ }
+ }
+
+
+ /**
+ * Start the plugin.
+ *
+ * @param int $flags Start flags for the plugin. See the constants in lib/plugins.php for details.
+ * @return true
+ * @throws PluginException
+ */
+ public function start($flags) {
+ if (!$this->canActivate()) {
+ return false;
+ }
+
+ // include start file
+ if ($flags & ELGG_PLUGIN_INCLUDE_START) {
+ $this->includeStart();
+ }
+
+ // include views
+ if ($flags & ELGG_PLUGIN_REGISTER_VIEWS) {
+ $this->registerViews();
+ }
+
+ // include languages
+ if ($flags & ELGG_PLUGIN_REGISTER_LANGUAGES) {
+ $this->registerLanguages();
+ }
+
+ // include classes
+ if ($flags & ELGG_PLUGIN_REGISTER_CLASSES) {
+ $this->registerClasses();
+ }
+
+ return true;
+ }
+
+
+ // start helpers
+
+ /**
+ * Includes the plugin's start file
+ *
+ * @throws PluginException
+ * @return true
+ */
+ protected function includeStart() {
+ $start = "$this->path/start.php";
+ if (!include($start)) {
+ $msg = elgg_echo('ElggPlugin:Exception:CannotIncludeStart',
+ array($this->getID(), $this->guid, $this->path));
+ throw new PluginException($msg);
+ }
+
+ return true;
+ }
+
+ /**
+ * Registers the plugin's views
+ *
+ * @throws PluginException
+ * @return true
+ */
+ protected function registerViews() {
+ $view_dir = "$this->path/views/";
+
+ // plugins don't have to have views.
+ if (!is_dir($view_dir)) {
+ return true;
+ }
+
+ // but if they do, they have to be readable
+ $handle = opendir($view_dir);
+ if (!$handle) {
+ $msg = elgg_echo('ElggPlugin:Exception:CannotRegisterViews',
+ array($this->getID(), $this->guid, $view_dir));
+ throw new PluginException($msg);
+ }
+
+ 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)) {
+ elgg_register_viewtype($view_type);
+ } else {
+ $msg = elgg_echo('ElggPlugin:Exception:CannotRegisterViews',
+ array($this->getID(), $view_type_dir));
+ throw new PluginException($msg);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Registers the plugin's languages
+ *
+ * @throws PluginException
+ * @return true
+ */
+ protected function registerLanguages() {
+ $languages_path = "$this->path/languages";
+
+ // don't need to have classes
+ if (!is_dir($languages_path)) {
+ return true;
+ }
+
+ // but need to have working ones.
+ if (!register_translations($languages_path)) {
+ $msg = elgg_echo('ElggPlugin:Exception:CannotRegisterLanguages',
+ array($this->getID(), $this->guid, $languages_path));
+ throw new PluginException($msg);
+ }
+
+ return true;
+ }
+
+ /**
+ * Registers the plugin's classes
+ *
+ * @throws PluginException
+ * @return true
+ */
+ protected function registerClasses() {
+ $classes_path = "$this->path/classes";
+
+ // don't need to have classes
+ if (!is_dir($classes_path)) {
+ return true;
+ }
+
+ // but need to have working ones.
+ if (!elgg_register_classes($classes_path)) {
+ $msg = elgg_echo('ElggPlugin:Exception:CannotRegisterClasses',
+ array($this->getID(), $this->guid, $classes_path));
+ throw new PluginException($msg);
+ }
+
+ return true;
+ }
+
+
+ // generic helpers and overrides
+
+ /**
* Get a value from private settings.
*
* @param string $name Name
@@ -30,8 +729,16 @@ class ElggPlugin extends ElggObject {
* @return mixed
*/
public function get($name) {
+ // rewrite for old and inaccurate plugin:setting
+ if (strstr($name, 'plugin:setting:')) {
+ $msg = 'Direct access of user settings is deprecated. Use ElggPlugin->getUserSetting()';
+ elgg_deprecated_notice($msg, 1.8);
+ $name = str_replace('plugin:setting:', '', $name);
+ $name = elgg_namespace_plugin_private_setting('user_setting', $name);
+ }
+
// See if its in our base attribute
- if (isset($this->attributes[$name])) {
+ if (array_key_exists($name, $this->attributes)) {
return $this->attributes[$name];
}
@@ -69,4 +776,34 @@ class ElggPlugin extends ElggObject {
return true;
}
+
+ /**
+ * Sets the plugin to active or inactive for $site_guid.
+ *
+ * @param bool $active Set to active or inactive
+ * @param mixed $site_guid Int for specific site, null for current site.
+ *
+ * @return bool
+ */
+ private function setStatus($active, $site_guid = null) {
+ if (!$this->guid) {
+ return false;
+ }
+
+ if ($site_guid) {
+ $site = get_entity($site_guid);
+
+ if (!($site instanceof ElggSite)) {
+ return false;
+ }
+ } else {
+ $site = get_config('site');
+ }
+
+ if ($active) {
+ return add_entity_relationship($this->guid, 'active_plugin', $site->guid);
+ } else {
+ return remove_entity_relationship($this->guid, 'active_plugin', $site->guid);
+ }
+ }
} \ No newline at end of file
diff --git a/engine/classes/ElggPluginManifest.php b/engine/classes/ElggPluginManifest.php
index 801769eb9..9fcdaaf55 100644
--- a/engine/classes/ElggPluginManifest.php
+++ b/engine/classes/ElggPluginManifest.php
@@ -481,6 +481,77 @@ class ElggPluginManifest {
}
/**
+ * Returns the functions to run upon activation
+ *
+ * @return array
+ */
+ public function getOnActivate() {
+ $functions = $this->parser->getAttribute('on_activate');
+
+ if (!$functions) {
+ $functions = array();
+ }
+
+ return $functions;
+ }
+
+ /**
+ * Returns the functions to run upon deactivation
+ *
+ * @return array
+ */
+ public function getOnDeactivate() {
+ $functions = $this->parser->getAttribute('on_deactivate');
+
+ if (!$functions) {
+ $functions = array();
+ }
+
+ return $functions;
+ }
+
+ /**
+ * Returns the admin interface to use.
+ *
+ * @return string simple or advanced
+ */
+ public function getAdminInterface() {
+ $interface = $this->parser->getAttribute('admin_interface');
+
+ switch ($interface) {
+ case 'simple':
+ case 'advanced':
+ return $interface;
+
+ default:
+ return 'advanced';
+ }
+ }
+
+ /**
+ * Returns the admin interface to use.
+ *
+ * @return bool
+ */
+ public function getActivateOnInstall() {
+ $activate = $this->parser->getAttribute('activate_on_install');
+ switch (strtolower($activate)) {
+ case 'yes':
+ case 'true':
+ case 'on':
+ case 1:
+ return true;
+
+ case 'no':
+ case 'false':
+ case 'off':
+ case 0:
+ case '':
+ return false;
+ }
+ }
+
+ /**
* Normalizes an array into the structure specified
*
* @param array $struct The struct to normalize $element to.
diff --git a/engine/classes/ElggPluginManifestParser18.php b/engine/classes/ElggPluginManifestParser18.php
index 9a4cfb2b7..1f5b51bb5 100644
--- a/engine/classes/ElggPluginManifestParser18.php
+++ b/engine/classes/ElggPluginManifestParser18.php
@@ -15,7 +15,8 @@ class ElggPluginManifestParser18 extends ElggPluginManifestParser {
protected $validAttributes = array(
'name', 'author', 'version', 'blurb', 'description',
'website', 'copyright', 'license', 'requires', 'screenshot',
- 'category', 'conflicts', 'provides', 'admin'
+ 'category', 'conflicts', 'provides', 'on_activate', 'on_deactivate',
+ 'admin_interface', 'activate_on_install'
);
/**
@@ -45,26 +46,19 @@ class ElggPluginManifestParser18 extends ElggPluginManifestParser {
case 'website':
case 'copyright':
case 'license':
+ case 'admin_interface':
+ case 'activate_on_install':
$parsed[$element->name] = $element->content;
break;
// arrays
+ case 'on_activate':
+ case 'on_deactivate':
case 'category':
- $parsed['category'][] = $element->content;
- break;
-
- case 'admin':
- $parsed['admin'] = array();
- if (!isset($element->children)) {
- return false;
- }
-
- foreach ($element->children as $child_element) {
- $parsed['admin'][$child_element->name] = $child_element->content;
- }
-
+ $parsed[$element->name][] = $element->content;
break;
+ // 3d arrays
case 'screenshot':
case 'provides':
case 'conflicts':
diff --git a/engine/classes/ElggPluginPackage.php b/engine/classes/ElggPluginPackage.php
index 8bbacce22..6301ad1f2 100644
--- a/engine/classes/ElggPluginPackage.php
+++ b/engine/classes/ElggPluginPackage.php
@@ -239,16 +239,6 @@ class ElggPluginPackage {
return true;
}
- /**
- * Checks if this plugin can be activated on the current
- * Elgg installation.
- *
- * @return bool
- */
- public function canActivate() {
- return $this->checkDependencies();
- }
-
/************
* Manifest *
@@ -261,7 +251,9 @@ class ElggPluginPackage {
*/
public function getManifest() {
if (!$this->manifest) {
- $this->loadManifest();
+ if (!$this->loadManifest()) {
+ return false;
+ }
}
return $this->manifest;
@@ -275,9 +267,14 @@ class ElggPluginPackage {
*/
private function loadManifest() {
$file = $this->path . 'manifest.xml';
- $this->manifest = new ElggPluginManifest($file, $this->id);
- if ($this->manifest) {
+ try {
+ $this->manifest = new ElggPluginManifest($file, $this->id);
+ } catch (Exception $e) {
+ return false;
+ }
+
+ if ($this->manifest instanceof ElggPluginManifest) {
return true;
}
@@ -307,7 +304,7 @@ class ElggPluginPackage {
public function checkDependencies($full_report = false) {
$requires = $this->getManifest()->getRequires();
$conflicts = $this->getManifest()->getConflicts();
- $enabled_plugins = get_installed_plugins('enabled');
+ $enabled_plugins = elgg_get_plugins('active');
$report = array();
foreach (array('requires', 'conflicts') as $dep_type) {
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
diff --git a/engine/tests/api/plugins.php b/engine/tests/api/plugins.php
index c99609559..997d69fb7 100644
--- a/engine/tests/api/plugins.php
+++ b/engine/tests/api/plugins.php
@@ -100,11 +100,10 @@ class ElggCorePluginsAPITest extends ElggCoreUnitTest {
array('type' => 'php_extension', 'name' => 'big_math', 'version' => 1.0)
),
- 'admin' => array(
- 'on_enable' => 'setup_function',
- 'on_disable' => 'teardown_function',
- 'interface_type' => 'simple'
- )
+ 'on_activate' => array('setup_function'),
+ 'on_deactivate' => array('teardown_function'),
+ 'admin_interface' => 'simple',
+ 'activate_on_install' => true
);
$this->assertEqual($this->manifest18->getManifest(), $manifest_array);
@@ -118,7 +117,8 @@ class ElggCorePluginsAPITest extends ElggCoreUnitTest {
'website' => 'http://www.elgg.org/',
'copyright' => '(C) Elgg 2010',
'license' => 'GNU Public License version 2',
- 'elgg_version' => '2009030702'
+ 'elgg_version' => '2009030702',
+ 'name' => 'Plugin Test 17',
);
$this->assertEqual($this->manifest17->getManifest(), $manifest_array);
@@ -261,6 +261,22 @@ class ElggCorePluginsAPITest extends ElggCoreUnitTest {
$this->assertEqual($this->manifest17->getConflicts(), array());
}
+ public function testElggPluginManifestGetOnActivate() {
+ $this->assertEqual($this->manifest18->getOnActivate(), array('setup_function'));
+ }
+
+ public function testElggPluginManifestGetOnDeactivate() {
+ $this->assertEqual($this->manifest18->getOnDeactivate(), array('teardown_function'));
+ }
+
+ public function testElggPluginManifestGetAdminInterface() {
+ $this->assertEqual($this->manifest18->getAdminInterface(), 'simple');
+ }
+
+ public function testElggPluginManifestGetActivateOnInstall() {
+ $this->assertEqual($this->manifest18->getActivateOnInstall(), true);
+ }
+
// ElggPluginPackage
public function testElggPluginPackageDetectIDFromPath() {
$this->assertEqual($this->package18->getID(), 'plugin_18');
diff --git a/engine/tests/test_files/plugin_18/manifest.xml b/engine/tests/test_files/plugin_18/manifest.xml
index 454a418f6..69166c89c 100644
--- a/engine/tests/test_files/plugin_18/manifest.xml
+++ b/engine/tests/test_files/plugin_18/manifest.xml
@@ -34,11 +34,10 @@
<category>ServiceAPI</category>
- <admin>
- <on_enable>setup_function</on_enable>
- <on_disable>teardown_function</on_disable>
- <interface_type>simple</interface_type>
- </admin>
+ <on_activate>setup_function</on_activate>
+ <on_deactivate>teardown_function</on_deactivate>
+ <admin_interface>simple</admin_interface>
+ <activate_on_install>true</activate_on_install>
<requires>
<type>php_extension</type>
@@ -94,4 +93,4 @@
<version>1.0</version>
</provides>
-</plugin_manifest> \ No newline at end of file
+</plugin_manifest>
diff --git a/languages/en.php b/languages/en.php
index 42776cb3f..7199f5aa9 100644
--- a/languages/en.php
+++ b/languages/en.php
@@ -62,7 +62,7 @@ $english = array(
'InvalidClassException:NotValidElggStar' => "GUID:%d is not a valid %s",
- 'PluginException:MisconfiguredPlugin' => "%s is a misconfigured plugin. It has been disabled. Please search the Elgg wiki for possible causes (http://docs.elgg.org/wiki/).",
+ 'PluginException:MisconfiguredPlugin' => "%s (guid: %s) is a misconfigured plugin. It has been disabled. Please search the Elgg wiki for possible causes (http://docs.elgg.org/wiki/).",
'PluginException:InvalidID' => "%s is an invalid plugin ID.",
'PluginException:InvalidPath' => "%s is an invalid plugin path.",
'PluginException:InvalidManifest' => 'Invalid manifest file for plugin %s',
@@ -73,6 +73,12 @@ $english = array(
'ElggPluginPackage:InvalidPlugin:InvalidProvides' => 'Invalid provides type "%s"',
'ElggPluginPackage:InvalidPlugin:CircularDep' => 'Invalid %s dependency "%s" in plugin %s. Plugins cannot conflict with or require something they provide!',
+ 'ElggPlugin:Exception:CannotIncludeStart' => 'Cannot include start.php for plugin %s (guid: %s) at %s. Check permissions!',
+ 'ElggPlugin:Exception:CannotRegisterViews' => 'Cannot open views dir for plugin %s (guid: %s) at %s. Check permissions!',
+ 'ElggPlugin:Exception:CannotRegisterLanguages' => 'Cannot register languages for plugin %s (guid: %s) at %s. Check permissions!',
+ 'ElggPlugin:Exception:CannotRegisterClasses' => 'Cannot register classes for plugin %s (guid: %s) at %s. Check permissions!',
+ 'ElggPlugin:Exception:NoID' => 'No ID for plugin guid %s!',
+
'PluginException:ParserError' => 'Error parsing manifest with API version %s in plugin %s.',
'PluginException:NoAvailableParser' => 'Cannot find a parser for manifest API version %s in plugin %s.',
'PluginException:ParserErrorMissingRequiredAttribute' => "Missing required '%s' attribute in manifest for plugin %s.",
@@ -403,7 +409,7 @@ $english = array(
'profile:explainchangefields' => 'You can replace the existing profile fields with your own using the form below. <br /><br />Give the new profile field a label, for example, \'Favorite team\', then select the field type (eg. text, url, tags), and click the \'Add\' button. To re-order the fields drag on the handle next to the field label. To edit a field label - click on the label\'s text to make it editable. <br />At any time you can revert back to the default profile set up, but you will loose any information already entered into custom fields on profile pages.',
'profile:editdefault:success' => 'Item successfully added to default profile',
'profile:editdefault:fail' => 'Default profile could not be saved',
-
+
/**
* Feeds
@@ -569,7 +575,7 @@ $english = array(
'plugins:settings:save:fail' => "There was a problem saving settings for the %s plugin.",
'plugins:usersettings:save:ok' => "User settings for the %s plugin were saved successfully.",
'plugins:usersettings:save:fail' => "There was a problem saving user settings for the %s plugin.",
- 'item:object:plugin' => 'Plugin configuration settings',
+ 'item:object:plugin' => 'Plugins',
'admin:plugins' => "Plugins",
'admin:plugins:description' => "This admin panel allows you to control and configure tools installed on your site.",
@@ -733,7 +739,7 @@ $english = array(
'site' => 'Site',
'activity' => 'Activity',
'members' => 'Members',
-
+
'up' => 'Up',
'down' => 'Down',
'top' => 'Top',
diff --git a/version.php b/version.php
index 235180d1c..b9efe2301 100644
--- a/version.php
+++ b/version.php
@@ -11,7 +11,7 @@
// YYYYMMDD = Elgg Date
// XX = Interim incrementer
-$version = 2010121702;
+$version = 2011010101;
// Human-friendly version name
$release = '1.8-svn';