aboutsummaryrefslogtreecommitdiff
path: root/engine/classes/ElggPlugin.php
diff options
context:
space:
mode:
Diffstat (limited to 'engine/classes/ElggPlugin.php')
-rw-r--r--engine/classes/ElggPlugin.php486
1 files changed, 331 insertions, 155 deletions
diff --git a/engine/classes/ElggPlugin.php b/engine/classes/ElggPlugin.php
index 1b9be3ec1..545b9a53c 100644
--- a/engine/classes/ElggPlugin.php
+++ b/engine/classes/ElggPlugin.php
@@ -9,11 +9,12 @@
* @subpackage Plugins.Settings
*/
class ElggPlugin extends ElggObject {
- public $package;
- public $manifest;
+ private $package;
+ private $manifest;
private $path;
private $pluginID;
+ private $errorMsg = '';
/**
* Set subtype to 'plugin'
@@ -29,15 +30,15 @@ class ElggPlugin extends ElggObject {
$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.
+ * @param mixed $plugin The GUID of the ElggPlugin object or the path of the plugin to load.
+ *
+ * @throws PluginException
*/
public function __construct($plugin) {
if (!$plugin) {
@@ -77,19 +78,9 @@ class ElggPlugin extends ElggObject {
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.
- elgg_log("Failed to load $this->guid as a plugin. " . $e->getMessage(), 'WARNING');
- }
+ _elgg_cache_plugin_by_id($this);
}
-
/**
* Save the plugin object. Make sure required values exist.
*
@@ -128,6 +119,21 @@ class ElggPlugin extends ElggObject {
}
/**
+ * Returns the manifest's name if available, otherwise the ID.
+ *
+ * @return string
+ * @since 1.8.1
+ */
+ public function getFriendlyName() {
+ $manifest = $this->getManifest();
+ if ($manifest) {
+ return $manifest->getName();
+ }
+
+ return $this->getID();
+ }
+
+ /**
* Returns the plugin's full path with trailing slash.
*
* @return string
@@ -136,17 +142,33 @@ class ElggPlugin extends ElggObject {
return sanitise_filepath($this->path);
}
-
/**
* Sets the location of this plugin.
*
- * @param path $id The path to the plugin's dir.
+ * @param string $id The path to the plugin's dir.
* @return bool
*/
public function setID($id) {
return $this->attributes['title'] = $id;
}
+ /**
+ * Returns an array of available markdown files for this plugin
+ *
+ * @return array
+ */
+ public function getAvailableTextFiles() {
+ $filenames = $this->getPackage()->getTextFilenames();
+
+ $files = array();
+ foreach ($filenames as $filename) {
+ if ($this->canReadFile($filename)) {
+ $files[$filename] = "$this->path/$filename";
+ }
+ }
+
+ return $files;
+ }
// Load Priority
@@ -160,7 +182,6 @@ class ElggPlugin extends ElggObject {
return $this->$name;
}
-
/**
* Sets the priority of the plugin
*
@@ -177,41 +198,29 @@ class ElggPlugin extends ElggObject {
$db_prefix = get_config('dbprefix');
$name = elgg_namespace_plugin_private_setting('internal', 'priority');
- // if no priority assume a priority of 0
+ // if no priority assume a priority of 1
$old_priority = (int) $this->getPriority();
+ $old_priority = (!$old_priority) ? 1 : $old_priority;
$max_priority = elgg_get_max_plugin_priority();
- // (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;
+ // can't use switch here because it's not strict and
+ // php evaluates +1 == 1
+ if ($priority === '+1') {
+ $priority = $old_priority + 1;
+ } elseif ($priority === '-1') {
+ $priority = $old_priority - 1;
+ } elseif ($priority === 'first') {
+ $priority = 1;
+ } elseif ($priority === 'last') {
+ $priority = $max_priority;
}
// should be a number by now
- if ($priority) {
+ if ($priority > 0) {
if (!is_numeric($priority)) {
return false;
}
- if ($priority == $old_priority) {
- return false;
- }
-
// there's nothing above the max.
if ($priority > $max_priority) {
$priority = $max_priority;
@@ -243,7 +252,6 @@ class ElggPlugin extends ElggObject {
// set this priority
if ($this->set($name, $priority)) {
- //return elgg_plugins_reindex_priorities();
return true;
} else {
return false;
@@ -259,8 +267,6 @@ class ElggPlugin extends ElggObject {
/**
* Returns a plugin setting
*
- * @todo These need to be namespaced
- *
* @param string $name The setting name
* @return mixed
*/
@@ -268,12 +274,46 @@ class ElggPlugin extends ElggObject {
return $this->$name;
}
+ /**
+ * Returns an array of all settings saved for this plugin.
+ *
+ * @note Unlike user settings, plugin settings are not namespaced.
+ *
+ * @return array An array of key/value pairs.
+ */
+ public function getAllSettings() {
+ if (!$this->guid) {
+ return false;
+ }
+
+ $db_prefix = elgg_get_config('dbprefix');
+ // need to remove all namespaced private settings.
+ $us_prefix = elgg_namespace_plugin_private_setting('user_setting', '', $this->getID());
+ $is_prefix = elgg_namespace_plugin_private_setting('internal', '', $this->getID());
+
+ // Get private settings for user
+ $q = "SELECT * FROM {$db_prefix}private_settings
+ WHERE entity_guid = $this->guid
+ AND name NOT LIKE '$us_prefix%'
+ AND name NOT LIKE '$is_prefix%'";
+
+ $private_settings = get_data($q);
+
+ $return = array();
+
+ if ($private_settings) {
+ foreach ($private_settings as $setting) {
+ $return[$setting->name] = $setting->value;
+ }
+ }
+
+ return $return;
+ }
/**
* 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
@@ -284,18 +324,10 @@ class ElggPlugin extends ElggObject {
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->set($name, $value);
}
-
/**
* Removes a plugin setting name and value.
*
@@ -303,11 +335,10 @@ class ElggPlugin extends ElggObject {
*
* @return bool
*/
- public function removeSetting($name) {
+ public function unsetSetting($name) {
return remove_private_setting($this->guid, $name);
}
-
/**
* Removes all settings for this plugin.
*
@@ -315,13 +346,16 @@ class ElggPlugin extends ElggObject {
* @todo If we could namespace the plugin settings this would be cleaner.
* @return bool
*/
- public function removeAllSettings() {
+ public function unsetAllSettings() {
$db_prefix = get_config('dbprefix');
- $ps_prefix = elgg_namespace_plugin_private_setting('setting', '');
+
+ $us_prefix = elgg_namespace_plugin_private_setting('user_setting', '', $this->getID());
+ $is_prefix = elgg_namespace_plugin_private_setting('internal', '', $this->getID());
$q = "DELETE FROM {$db_prefix}private_settings
WHERE entity_guid = $this->guid
- AND name NOT LIKE '$ps_prefix%'";
+ AND name NOT LIKE '$us_prefix%'
+ AND name NOT LIKE '$is_prefix%'";
return delete_data($q);
}
@@ -332,44 +366,139 @@ class ElggPlugin extends ElggObject {
/**
* Returns a user's setting for this plugin
*
- * @param int $user_guid The user GUID
* @param string $name The setting name
+ * @param int $user_guid The user GUID
*
* @return mixed The setting string value or false
*/
- public function getUserSetting($user_guid, $name) {
+ public function getUserSetting($name, $user_guid = null) {
+ $user_guid = (int)$user_guid;
+
+ if ($user_guid) {
+ $user = get_entity($user_guid);
+ } else {
+ $user = elgg_get_logged_in_user_entity();
+ }
+
+ if (!($user instanceof ElggUser)) {
+ return false;
+ }
+
$name = elgg_namespace_plugin_private_setting('user_setting', $name, $this->getID());
- return get_private_setting($user_guid, $name);
+ return get_private_setting($user->guid, $name);
+ }
+
+ /**
+ * Returns an array of all user settings saved for this plugin for the user.
+ *
+ * @note Plugin settings are saved with a prefix. This removes that prefix.
+ *
+ * @param int $user_guid The user GUID. Defaults to logged in.
+ * @return array An array of key/value pairs.
+ */
+ public function getAllUserSettings($user_guid = null) {
+ $user_guid = (int)$user_guid;
+
+ if ($user_guid) {
+ $user = get_entity($user_guid);
+ } else {
+ $user = elgg_get_logged_in_user_entity();
+ }
+
+ if (!($user instanceof ElggUser)) {
+ return false;
+ }
+
+ $db_prefix = elgg_get_config('dbprefix');
+ // send an empty name so we just get the first part of the namespace
+ $ps_prefix = elgg_namespace_plugin_private_setting('user_setting', '', $this->getID());
+ $ps_prefix_len = strlen($ps_prefix);
+
+ // Get private settings for user
+ $q = "SELECT * FROM {$db_prefix}private_settings
+ WHERE entity_guid = {$user->guid}
+ AND name LIKE '$ps_prefix%'";
+
+ $private_settings = get_data($q);
+
+ $return = array();
+
+ if ($private_settings) {
+ foreach ($private_settings as $setting) {
+ $name = substr($setting->name, $ps_prefix_len);
+ $value = $setting->value;
+
+ $return[$name] = $value;
+ }
+ }
+
+ return $return;
}
/**
* 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
+ * @param int $user_guid The user GUID
*
* @return mixed The new setting ID or false
*/
- public function setUserSetting($user_guid, $name, $value) {
+ public function setUserSetting($name, $value, $user_guid = null) {
+ $user_guid = (int)$user_guid;
+
+ if ($user_guid) {
+ $user = get_entity($user_guid);
+ } else {
+ $user = elgg_get_logged_in_user_entity();
+ }
+
+ if (!($user instanceof ElggUser)) {
+ return false;
+ }
+
+ // Hook to validate setting
+ // note: this doesn't pass the namespaced name
+ $value = elgg_trigger_plugin_hook('usersetting', 'plugin', array(
+ 'user' => $user,
+ 'plugin' => $this,
+ 'plugin_id' => $this->getID(),
+ 'name' => $name,
+ 'value' => $value
+ ), $value);
+
+ // set the namespaced name.
$name = elgg_namespace_plugin_private_setting('user_setting', $name, $this->getID());
- return set_private_setting($user_guid, $name, $value);
+
+ 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
- *
+ * @param int $user_guid The user GUID
* @return bool
*/
- public function removeUserSetting($user_guid, $name) {
+ public function unsetUserSetting($name, $user_guid = null) {
+ $user_guid = (int)$user_guid;
+
+ if ($user_guid) {
+ $user = get_entity($user_guid);
+ } else {
+ $user = elgg_get_logged_in_user_entity();
+ }
+
+ if (!($user instanceof ElggUser)) {
+ return false;
+ }
+
+ // set the namespaced name.
$name = elgg_namespace_plugin_private_setting('user_setting', $name, $this->getID());
- return remove_private_setting($user_guid, $name);
- }
+ return remove_private_setting($user->guid, $name);
+ }
/**
* Removes all User Settings for this plugin
@@ -380,7 +509,7 @@ class ElggPlugin extends ElggObject {
* @param int $user_guid The user GUID to remove user settings.
* @return bool
*/
- public function removeAllUserSettings($user_guid) {
+ public function unsetAllUserSettings($user_guid) {
$db_prefix = get_config('dbprefix');
$ps_prefix = elgg_namespace_plugin_private_setting('user_setting', '', $this->getID());
@@ -391,7 +520,6 @@ class ElggPlugin extends ElggObject {
return delete_data($q);
}
-
/**
* Removes this plugin's user settings for all users.
*
@@ -400,7 +528,7 @@ class ElggPlugin extends ElggObject {
*
* @return bool
*/
- public function removeAllUsersSettings() {
+ public function unsetAllUsersSettings() {
$db_prefix = get_config('dbprefix');
$ps_prefix = elgg_namespace_plugin_private_setting('user_setting', '', $this->getID());
@@ -417,27 +545,29 @@ class ElggPlugin extends ElggObject {
* 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.
+ * @todo bad name? This could be confused with isValid() from ElggPluginPackage.
*
* @return bool
*/
public function isValid() {
if (!$this->getID()) {
+ $this->errorMsg = elgg_echo('ElggPlugin:NoId', array($this->guid));
return false;
}
- if (!$this->package instanceof ElggPluginPackage) {
+ if (!$this->getPackage() instanceof ElggPluginPackage) {
+ $this->errorMsg = elgg_echo('ElggPlugin:NoPluginPackagePackage', array($this->getID(), $this->guid));
return false;
}
- if (!$this->package->isValid()) {
+ if (!$this->getPackage()->isValid()) {
+ $this->errorMsg = $this->getPackage()->getError();
return false;
}
return true;
}
-
/**
* Is this plugin active?
*
@@ -451,28 +581,34 @@ class ElggPlugin extends ElggObject {
if ($site_guid) {
$site = get_entity($site_guid);
-
- if (!($site instanceof ElggSite)) {
- return false;
- }
} else {
$site = get_config('site');
}
+ if (!($site instanceof ElggSite)) {
+ return false;
+ }
+
return check_entity_relationship($this->guid, 'active_plugin', $site->guid);
}
-
/**
* Checks if this plugin can be activated on the current
* Elgg installation.
*
+ * @todo remove $site_guid param or implement it
+ *
* @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();
+ if ($this->getPackage()) {
+ $result = $this->getPackage()->isValid() && $this->getPackage()->checkDependencies();
+ if (!$result) {
+ $this->errorMsg = $this->getPackage()->getError();
+ }
+
+ return $result;
}
return false;
@@ -510,24 +646,14 @@ class ElggPlugin extends ElggObject {
// 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) {
+ if ($this->canReadFile('activate.php')) {
+ $flags = ELGG_PLUGIN_INCLUDE_START | ELGG_PLUGIN_REGISTER_CLASSES |
+ ELGG_PLUGIN_REGISTER_LANGUAGES | ELGG_PLUGIN_REGISTER_VIEWS;
+
+ $this->start($flags);
+
+ $return = $this->includeFile('activate.php');
}
}
@@ -541,7 +667,6 @@ class ElggPlugin extends ElggObject {
return false;
}
-
/**
* Deactivates the plugin.
*
@@ -561,27 +686,10 @@ class ElggPlugin extends ElggObject {
$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;
- }
+ // run any deactivate code
+ if ($return) {
+ if ($this->canReadFile('deactivate.php')) {
+ $return = $this->includeFile('deactivate.php');
}
}
@@ -592,7 +700,6 @@ class ElggPlugin extends ElggObject {
}
}
-
/**
* Start the plugin.
*
@@ -601,13 +708,18 @@ class ElggPlugin extends ElggObject {
* @throws PluginException
*/
public function start($flags) {
- if (!$this->canActivate()) {
- return false;
- }
+ //if (!$this->canActivate()) {
+ // return false;
+ //}
+ // include classes
+ if ($flags & ELGG_PLUGIN_REGISTER_CLASSES) {
+ $this->registerClasses();
+ }
+
// include start file
if ($flags & ELGG_PLUGIN_INCLUDE_START) {
- $this->includeStart();
+ $this->includeFile('start.php');
}
// include views
@@ -620,11 +732,6 @@ class ElggPlugin extends ElggObject {
$this->registerLanguages();
}
- // include classes
- if ($flags & ELGG_PLUGIN_REGISTER_CLASSES) {
- $this->registerClasses();
- }
-
return true;
}
@@ -632,24 +739,39 @@ class ElggPlugin extends ElggObject {
// start helpers
/**
- * Includes the plugin's start file
+ * Includes one of the plugins files
+ *
+ * @param string $filename The name of the file
*
* @throws PluginException
- * @return true
+ * @return mixed The return value of the included file (or 1 if there is none)
*/
- protected function includeStart() {
+ protected function includeFile($filename) {
// This needs to be here to be backwards compatible for 1.0-1.7.
// They expect the global config object to be available in start.php.
- global $CONFIG;
+ if ($filename == 'start.php') {
+ global $CONFIG;
+ }
- $start = "$this->path/start.php";
- if (!include($start)) {
- $msg = elgg_echo('ElggPlugin:Exception:CannotIncludeStart',
- array($this->getID(), $this->guid, $this->path));
+ $filepath = "$this->path/$filename";
+
+ if (!$this->canReadFile($filename)) {
+ $msg = elgg_echo('ElggPlugin:Exception:CannotIncludeFile',
+ array($filename, $this->getID(), $this->guid, $this->path));
throw new PluginException($msg);
}
- return true;
+ return include $filepath;
+ }
+
+ /**
+ * Checks whether a plugin file with the given name exists
+ *
+ * @param string $filename The name of the file
+ * @return bool
+ */
+ protected function canReadFile($filename) {
+ return is_readable($this->path . '/' . $filename);
}
/**
@@ -729,12 +851,7 @@ class ElggPlugin extends ElggObject {
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);
- }
+ elgg_register_classes($classes_path);
return true;
}
@@ -765,7 +882,7 @@ class ElggPlugin extends ElggObject {
// No, so see if its in the private data store.
// get_private_setting() returns false if it doesn't exist
- $meta = get_private_setting($this->guid, $name);
+ $meta = $this->getPrivateSetting($name);
if ($meta === false) {
// Can't find it, so return null
@@ -776,7 +893,9 @@ class ElggPlugin extends ElggObject {
}
/**
- * Save a value to private settings.
+ * Save a value as private setting or attribute.
+ *
+ * Attributes include title and description.
*
* @param string $name Name
* @param mixed $value Value
@@ -794,7 +913,15 @@ class ElggPlugin extends ElggObject {
return true;
} else {
- return set_private_setting($this->guid, $name, $value);
+ // Hook to validate setting
+ $value = elgg_trigger_plugin_hook('setting', 'plugin', array(
+ 'plugin_id' => $this->pluginID,
+ 'plugin' => $this,
+ 'name' => $name,
+ 'value' => $value
+ ), $value);
+
+ return $this->setPrivateSetting($name, $value);
}
}
@@ -827,4 +954,53 @@ class ElggPlugin extends ElggObject {
return remove_entity_relationship($this->guid, 'active_plugin', $site->guid);
}
}
-} \ No newline at end of file
+
+ /**
+ * Returns the last error message registered.
+ *
+ * @return string|null
+ */
+ public function getError() {
+ return $this->errorMsg;
+ }
+
+ /**
+ * Returns this plugin's ElggPluginManifest object
+ *
+ * @return ElggPluginManifest
+ */
+ public function getManifest() {
+ if ($this->manifest instanceof ElggPluginManifest) {
+ return $this->manifest;
+ }
+
+ try {
+ $this->manifest = $this->getPackage()->getManifest();
+ } catch (Exception $e) {
+ elgg_log("Failed to load manifest for plugin $this->guid. " . $e->getMessage(), 'WARNING');
+ $this->errorMsg = $e->getmessage();
+ }
+
+ return $this->manifest;
+ }
+
+ /**
+ * Returns this plugin's ElggPluginPackage object
+ *
+ * @return ElggPluginPackage
+ */
+ public function getPackage() {
+ if ($this->package instanceof ElggPluginPackage) {
+ return $this->package;
+ }
+
+ try {
+ $this->package = new ElggPluginPackage($this->path, false);
+ } catch (Exception $e) {
+ elgg_log("Failed to load package for $this->guid. " . $e->getMessage(), 'WARNING');
+ $this->errorMsg = $e->getmessage();
+ }
+
+ return $this->package;
+ }
+}