]> gitweb.fluxo.info Git - lorea/elgg.git/commitdiff
Fixes #1986, #2170, #2225, #2759. Integrated ElggPluginPackage and ElggPluginManifest...
authorbrettp <brettp@36083f99-b078-4883-b0ff-0f9b5a30f544>
Sun, 2 Jan 2011 23:00:23 +0000 (23:00 +0000)
committerbrettp <brettp@36083f99-b078-4883-b0ff-0f9b5a30f544>
Sun, 2 Jan 2011 23:00:23 +0000 (23:00 +0000)
git-svn-id: http://code.elgg.org/elgg/trunk@7817 36083f99-b078-4883-b0ff-0f9b5a30f544

documentation/examples/plugins/manifest.xml [new file with mode: 0644]
engine/classes/ElggPlugin.php
engine/classes/ElggPluginManifest.php
engine/classes/ElggPluginManifestParser18.php
engine/classes/ElggPluginPackage.php
engine/lib/plugins.php
engine/lib/upgrades/2011010101.php [new file with mode: 0644]
engine/tests/api/plugins.php
engine/tests/test_files/plugin_18/manifest.xml
languages/en.php
version.php

diff --git a/documentation/examples/plugins/manifest.xml b/documentation/examples/plugins/manifest.xml
new file mode 100644 (file)
index 0000000..34dc82d
--- /dev/null
@@ -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>
index 887eb667f6508ee2d7c3d7cd9231f5b0cbbc55f8..fb9138ab9bc6053f076572d281d1b876c5d1166a 100644 (file)
@@ -9,6 +9,11 @@
  * @subpackage Plugins.Settings
  */
 class ElggPlugin extends ElggObject {
+       public $package;
+       public $manifest;
+
+       private $path;
+       private $pluginID;
 
        /**
         * Set subtype to 'plugin'
@@ -19,9 +24,703 @@ 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.
         *
@@ -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
index 801769eb9fd9b8deef0848e02b938d949c77344f..9fcdaaf55ae46f7060a8944049ee98dbdd8340a7 100644 (file)
@@ -480,6 +480,77 @@ class ElggPluginManifest {
                return $normalized;
        }
 
+       /**
+        * 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
         *
index 9a4cfb2b7abccc6e7b56182c51081ca76e427b49..1f5b51bb57bd23f871fe92173b6b8406c722a016 100644 (file)
@@ -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':
index 8bbacce223c69a9c42997742f2c6c267b6ca0d04..6301ad1f248215b8016842ae69844139611c6f8b 100644 (file)
@@ -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) {
index 29f55926cad95fb4d9259db8d8a513f4980d4bd2..cd74353de07ae22f4385eee4c5068e8287545808 100644 (file)
  * @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 (file)
index 0000000..eac5810
--- /dev/null
@@ -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
index c996095590217baeb06bf21494e4a5fd5e42c17f..997d69fb7ace6ddad40c4c984c740cfcd1ee459c 100644 (file)
@@ -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');
index 454a418f668be64b6c37411d1b7db2d8110fd45e..69166c89c0fcce3906f4bd23f4df3563a6a1b3f5 100644 (file)
 
        <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>
index 42776cb3fa1f17b88356e22905e411ef738b1dc1..7199f5aa99c1d23d6dc209432b594950a785d8e7 100644 (file)
@@ -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',
index 235180d1c872ace4e99efde40e627413ca909c05..b9efe2301063d9ee8d565540c545ddd814a4fe15 100644 (file)
@@ -11,7 +11,7 @@
 
 // YYYYMMDD = Elgg Date
 // XX = Interim incrementer
-$version = 2010121702;
+$version = 2011010101;
 
 // Human-friendly version name
 $release = '1.8-svn';