aboutsummaryrefslogtreecommitdiff
path: root/engine/classes/ElggPluginPackage.php
diff options
context:
space:
mode:
Diffstat (limited to 'engine/classes/ElggPluginPackage.php')
-rw-r--r--engine/classes/ElggPluginPackage.php233
1 files changed, 179 insertions, 54 deletions
diff --git a/engine/classes/ElggPluginPackage.php b/engine/classes/ElggPluginPackage.php
index fd54ff731..37eb4bf4d 100644
--- a/engine/classes/ElggPluginPackage.php
+++ b/engine/classes/ElggPluginPackage.php
@@ -28,6 +28,17 @@ class ElggPluginPackage {
);
/**
+ * The optional files that can be read and served through the markdown page handler
+ * @var array
+ */
+ private $textFiles = array(
+ 'README.txt', 'CHANGES.txt',
+ 'INSTALL.txt', 'COPYRIGHT.txt', 'LICENSE.txt',
+
+ 'README', 'README.md', 'README.markdown'
+ );
+
+ /**
* Valid types for provides.
*
* @var array
@@ -42,13 +53,13 @@ class ElggPluginPackage {
* @var array
*/
private $depsSupportedTypes = array(
- 'elgg_version', 'elgg_release', 'php_extension', 'php_ini', 'plugin'
+ 'elgg_version', 'elgg_release', 'php_extension', 'php_ini', 'plugin', 'priority',
);
/**
* An invalid plugin error.
*/
- private $invalidPluginError = '';
+ private $errorMsg = '';
/**
* Any dependencies messages
@@ -89,11 +100,13 @@ class ElggPluginPackage {
* @param string $plugin The ID (directory name) or full path of the plugin.
* @param bool $validate Automatically run isValid()?
*
- * @return true
* @throws PluginException
*/
public function __construct($plugin, $validate = true) {
- if (substr($plugin, 0, 1) == '/') {
+ $plugin_path = elgg_get_plugins_path();
+ // @todo wanted to avoid another is_dir() call here.
+ // should do some profiling to see how much it affects
+ if (strpos($plugin, $plugin_path) === 0 || is_dir($plugin)) {
// this is a path
$path = sanitise_filepath($plugin);
@@ -103,11 +116,11 @@ class ElggPluginPackage {
} else {
// this is a plugin id
// strict plugin names
- if (preg_match('/[^a-z0-9\.\-_]/i', $id)) {
+ if (preg_match('/[^a-z0-9\.\-_]/i', $plugin)) {
throw new PluginException(elgg_echo('PluginException:InvalidID', array($plugin)));
}
- $path = get_config('pluginspath') . "$plugin/";
+ $path = "{$plugin_path}$plugin/";
$id = $plugin;
}
@@ -119,9 +132,9 @@ class ElggPluginPackage {
$this->id = $id;
if ($validate && !$this->isValid()) {
- if ($this->invalidPluginError) {
+ if ($this->errorMsg) {
throw new PluginException(elgg_echo('PluginException:InvalidPlugin:Details',
- array($plugin, $this->invalidPluginError)));
+ array($plugin, $this->errorMsg)));
} else {
throw new PluginException(elgg_echo('PluginException:InvalidPlugin', array($plugin)));
}
@@ -152,14 +165,12 @@ class ElggPluginPackage {
return $this->valid;
}
- $valid = true;
-
// check required files.
$have_req_files = true;
foreach ($this->requiredFiles as $file) {
if (!is_readable($this->path . $file)) {
$have_req_files = false;
- $this->invalidPluginError =
+ $this->errorMsg =
elgg_echo('ElggPluginPackage:InvalidPlugin:MissingFile', array($file));
break;
}
@@ -167,23 +178,21 @@ class ElggPluginPackage {
// check required files
if (!$have_req_files) {
- $valid = false;
+ return $this->valid = false;
}
// check for valid manifest.
if (!$this->loadManifest()) {
- $valid = false;
+ return $this->valid = false;
}
// can't require or conflict with yourself or something you provide.
// make sure provides are all valid.
if (!$this->isSaneDeps()) {
- $valid = false;
+ return $this->valid = false;
}
- $this->valid = $valid;
-
- return $valid;
+ return $this->valid = true;
}
/**
@@ -198,6 +207,12 @@ class ElggPluginPackage {
* @return bool
*/
private function isSaneDeps() {
+ // protection against plugins with no manifest file
+ if (!$this->getManifest()) {
+ return false;
+ }
+
+ // Note: $conflicts and $requires are not unused. They're called dynamically
$conflicts = $this->getManifest()->getConflicts();
$requires = $this->getManifest()->getRequires();
$provides = $this->getManifest()->getProvides();
@@ -205,7 +220,7 @@ class ElggPluginPackage {
foreach ($provides as $provide) {
// only valid provide types
if (!in_array($provide['type'], $this->providesSupportedTypes)) {
- $this->invalidPluginError =
+ $this->errorMsg =
elgg_echo('ElggPluginPackage:InvalidPlugin:InvalidProvides', array($provide['type']));
return false;
}
@@ -215,17 +230,17 @@ class ElggPluginPackage {
foreach (array('conflicts', 'requires') as $dep_type) {
foreach (${$dep_type} as $dep) {
if (!in_array($dep['type'], $this->depsSupportedTypes)) {
- $this->invalidPluginError =
+ $this->errorMsg =
elgg_echo('ElggPluginPackage:InvalidPlugin:InvalidDependency', array($dep['type']));
return false;
}
// make sure nothing is providing something it conflicts or requires.
- if ($dep['name'] == $name) {
+ if (isset($dep['name']) && $dep['name'] == $name) {
$version_compare = version_compare($provide['version'], $dep['version'], $dep['comparison']);
if ($version_compare) {
- $this->invalidPluginError =
+ $this->errorMsg =
elgg_echo('ElggPluginPackage:InvalidPlugin:CircularDep',
array($dep['type'], $dep['name'], $this->id));
@@ -271,6 +286,7 @@ class ElggPluginPackage {
try {
$this->manifest = new ElggPluginManifest($file, $this->id);
} catch (Exception $e) {
+ $this->errorMsg = $e->getMessage();
return false;
}
@@ -278,9 +294,22 @@ class ElggPluginPackage {
return true;
}
+ $this->errorMsg = elgg_echo('unknown_error');
return false;
}
+ /****************
+ * Readme Files *
+ ***************/
+
+ /**
+ * Returns an array of present and readable text files
+ *
+ * @return array
+ */
+ public function getTextFilenames() {
+ return $this->textFiles;
+ }
/***********************
* Dependencies system *
@@ -302,39 +331,84 @@ class ElggPluginPackage {
* @return bool|array
*/
public function checkDependencies($full_report = false) {
+ // Note: $conflicts and $requires are not unused. They're called dynamically
$requires = $this->getManifest()->getRequires();
$conflicts = $this->getManifest()->getConflicts();
+
$enabled_plugins = elgg_get_plugins('active');
+ $this_id = $this->getID();
$report = array();
- foreach (array('requires', 'conflicts') as $dep_type) {
+ // first, check if any active plugin conflicts with us.
+ foreach ($enabled_plugins as $plugin) {
+ $temp_conflicts = array();
+ $temp_manifest = $plugin->getManifest();
+ if ($temp_manifest instanceof ElggPluginManifest) {
+ $temp_conflicts = $plugin->getManifest()->getConflicts();
+ }
+ foreach ($temp_conflicts as $conflict) {
+ if ($conflict['type'] == 'plugin' && $conflict['name'] == $this_id) {
+ $result = $this->checkDepPlugin($conflict, $enabled_plugins, false);
+
+ // rewrite the conflict to show the originating plugin
+ $conflict['name'] = $plugin->getManifest()->getName();
+
+ if (!$full_report && !$result['status']) {
+ $this->errorMsg = "Conflicts with plugin \"{$plugin->getManifest()->getName()}\".";
+ return $result['status'];
+ } else {
+ $report[] = array(
+ 'type' => 'conflicted',
+ 'dep' => $conflict,
+ 'status' => $result['status'],
+ 'value' => $this->getManifest()->getVersion()
+ );
+ }
+ }
+ }
+ }
+
+ $check_types = array('requires', 'conflicts');
+
+ if ($full_report) {
+ // Note: $suggests is not unused. It's called dynamically
+ $suggests = $this->getManifest()->getSuggests();
+ $check_types[] = 'suggests';
+ }
+
+ foreach ($check_types as $dep_type) {
$inverse = ($dep_type == 'conflicts') ? true : false;
foreach (${$dep_type} as $dep) {
switch ($dep['type']) {
case 'elgg_version':
- $result = $this->checkDepElgg($dep, get_version());
+ $result = $this->checkDepElgg($dep, get_version(), $inverse);
break;
case 'elgg_release':
- $result = $this->checkDepElgg($dep, get_version(true));
+ $result = $this->checkDepElgg($dep, get_version(true), $inverse);
break;
case 'plugin':
$result = $this->checkDepPlugin($dep, $enabled_plugins, $inverse);
break;
+ case 'priority':
+ $result = $this->checkDepPriority($dep, $enabled_plugins, $inverse);
+ break;
+
case 'php_extension':
- $result = $this->checkDepPhpExtension($dep);
+ $result = $this->checkDepPhpExtension($dep, $inverse);
break;
case 'php_ini':
- $result = $this->checkDepPhpIni($dep);
+ $result = $this->checkDepPhpIni($dep, $inverse);
break;
}
// unless we're doing a full report, break as soon as we fail.
if (!$full_report && !$result['status']) {
+ $this->errorMsg = "Missing dependencies.";
return $result['status'];
} else {
// build report element and comment
@@ -371,7 +445,7 @@ class ElggPluginPackage {
* Checks if $plugins meets the requirement by $dep.
*
* @param array $dep An Elgg manifest.xml deps array
- * @param array $plugins A list of plugins as returned by get_installed_plugins();
+ * @param array $plugins A list of plugins as returned by elgg_get_plugins();
* @param bool $inverse Inverse the results to use as a conflicts.
* @return bool
*/
@@ -386,6 +460,61 @@ class ElggPluginPackage {
}
/**
+ * Checks if $plugins meets the requirement by $dep.
+ *
+ * @param array $dep An Elgg manifest.xml deps array
+ * @param array $plugins A list of plugins as returned by elgg_get_plugins();
+ * @param bool $inverse Inverse the results to use as a conflicts.
+ * @return bool
+ */
+ private function checkDepPriority(array $dep, array $plugins, $inverse = false) {
+ // grab the ElggPlugin using this package.
+ $plugin_package = elgg_get_plugin_from_id($this->getID());
+ $plugin_priority = $plugin_package->getPriority();
+ $test_plugin = elgg_get_plugin_from_id($dep['plugin']);
+
+ // If this isn't a plugin or the plugin isn't installed or active
+ // priority doesn't matter. Use requires to check if a plugin is active.
+ if (!$plugin_package || !$test_plugin || !$test_plugin->isActive()) {
+ return array(
+ 'status' => true,
+ 'value' => 'uninstalled'
+ );
+ }
+
+ $test_plugin_priority = $test_plugin->getPriority();
+
+ switch ($dep['priority']) {
+ case 'before':
+ $status = $plugin_priority < $test_plugin_priority;
+ break;
+
+ case 'after':
+ $status = $plugin_priority > $test_plugin_priority;
+ break;
+
+ default;
+ $status = false;
+ }
+
+ // get the current value
+ if ($plugin_priority < $test_plugin_priority) {
+ $value = 'before';
+ } else {
+ $value = 'after';
+ }
+
+ if ($inverse) {
+ $status = !$status;
+ }
+
+ return array(
+ 'status' => $status,
+ 'value' => $value
+ );
+ }
+
+ /**
* Checks if $elgg_version meets the requirement by $dep.
*
* @param array $dep An Elgg manifest.xml deps array
@@ -411,13 +540,14 @@ class ElggPluginPackage {
*
* @todo Can this be merged with the plugin checker?
*
- * @param array $dep An Elgg manifest.xml deps array
+ * @param array $dep An Elgg manifest.xml deps array
+ * @param bool $inverse Inverse the result to use as a conflicts.
* @return array An array in the form array(
* 'status' => bool
* 'value' => string The version provided
* )
*/
- private function checkDepPhpExtension(array $dep) {
+ private function checkDepPhpExtension(array $dep, $inverse = false) {
$name = $dep['name'];
$version = $dep['version'];
$comparison = $dep['comparison'];
@@ -447,6 +577,10 @@ class ElggPluginPackage {
$ext_version = $provides['value'];
}
+ if ($inverse) {
+ $status = !$status;
+ }
+
return array(
'status' => $status,
'value' => $ext_version
@@ -456,10 +590,11 @@ class ElggPluginPackage {
/**
* Check if the PHP ini setting satisfies $dep.
*
- * @param array $dep An Elgg manifest.xml deps array
+ * @param array $dep An Elgg manifest.xml deps array
+ * @param bool $inverse Inverse the result to use as a conflicts.
* @return bool
*/
- private function checkDepPhpIni($dep) {
+ private function checkDepPhpIni($dep, $inverse = false) {
$name = $dep['name'];
$value = $dep['value'];
$comparison = $dep['comparison'];
@@ -475,6 +610,10 @@ class ElggPluginPackage {
$status = version_compare($setting, $value, $comparison);
+ if ($inverse) {
+ $status = !$status;
+ }
+
return array(
'status' => $status,
'value' => $setting
@@ -482,28 +621,6 @@ class ElggPluginPackage {
}
/**
- * Activate the plugin.
- *
- * @note This method is activate() to avoid clashing with ElggEntity::enable()
- *
- * @return bool
- */
- public function activate() {
- return enable_plugin($this->getID());
- }
-
- /**
- * Deactivate the plugin.
- *
- * @note This method is deactivate() to avoid clashing with ElggEntity::disable()
- *
- * @return bool
- */
- public function deactivate() {
- return disable_plugin($this->getID());
- }
-
- /**
* Returns the Plugin ID
*
* @return string
@@ -512,4 +629,12 @@ class ElggPluginPackage {
return $this->id;
}
-} \ No newline at end of file
+ /**
+ * Returns the last error message.
+ *
+ * @return string
+ */
+ public function getError() {
+ return $this->errorMsg;
+ }
+}