diff --git a/PHPCI/Controller/PluginController.php b/PHPCI/Controller/PluginController.php
index 56d01f3e..b7e32ddb 100644
--- a/PHPCI/Controller/PluginController.php
+++ b/PHPCI/Controller/PluginController.php
@@ -11,6 +11,9 @@ namespace PHPCI\Controller;
use b8;
use PHPCI\Model\Build;
+use PHPCI\Plugin\Util\ComposerPluginInformation;
+use PHPCI\Plugin\Util\FilesPluginInformation;
+use PHPCI\Plugin\Util\PluginInformationCollection;
/**
* Plugin Controller - Provides support for installing Composer packages.
@@ -59,8 +62,18 @@ class PluginController extends \PHPCI\Controller
$this->view->required = $this->required;
$json = $this->getComposerJson();
- $this->view->installed = $json['require'];
- $this->view->suggested = $json['suggest'];
+ $this->view->installedPackages = $json['require'];
+ $this->view->suggestedPackages = $json['suggest'];
+
+ $pluginInfo = new PluginInformationCollection();
+ $pluginInfo->add(FilesPluginInformation::newFromDir(
+ PHPCI_DIR . "PHPCI/Plugin/"
+ ));
+ $pluginInfo->add(ComposerPluginInformation::buildFromYaml(
+ PHPCI_DIR . "vendor/composer/installed.json"
+ ));
+
+ $this->view->plugins = $pluginInfo->getInstalledPlugins();
return $this->view->render();
}
diff --git a/PHPCI/Plugin/Util/ComposerPluginInformation.php b/PHPCI/Plugin/Util/ComposerPluginInformation.php
new file mode 100644
index 00000000..0ce76e6f
--- /dev/null
+++ b/PHPCI/Plugin/Util/ComposerPluginInformation.php
@@ -0,0 +1,147 @@
+composerPackages = $composerPackages;
+ }
+
+ /**
+ * Returns an array of objects. Each one represents an available plugin
+ * and will have the following properties:
+ * name - The friendly name of the plugin (may be an empty string)
+ * class - The class of the plugin (will include namespace)
+ * @return \stdClass[]
+ */
+ public function getInstalledPlugins()
+ {
+ $this->loadPluginInfo();
+ return $this->pluginInfo;
+ }
+
+ /**
+ * Returns an array of all the class names of plugins that have been
+ * loaded.
+ *
+ * @return string[]
+ */
+ public function getPluginClasses()
+ {
+ return array_map(
+ function($plugin) {
+ return $plugin->class;
+ },
+ $this->getInstalledPlugins()
+ );
+ }
+
+ protected function loadPluginInfo()
+ {
+ if ($this->pluginInfo !== null) {
+ return;
+ }
+ $this->pluginInfo = array();
+ foreach($this->composerPackages as $package) {
+ $this->addPluginsFromPackage($package);
+ }
+ }
+
+ /**
+ * @param \stdClass $package
+ */
+ protected function addPluginsFromPackage($package)
+ {
+ if (isset($package->extra->phpci)) {
+ $phpciData = $package->extra->phpci;
+
+ if (isset($phpciData->pluginNamespace)) {
+ $rootNamespace = $phpciData->pluginNamespace;
+ }
+ else {
+ $rootNamespace = "";
+ }
+
+ if (is_array($phpciData->suppliedPlugins)) {
+ $this->addPlugins(
+ $phpciData->suppliedPlugins,
+ $package->name,
+ $rootNamespace
+ );
+ }
+ }
+ }
+
+ /**
+ * @param \stdClass[] $plugins
+ * @param string $sourcePackageName
+ * @param string $rootNamespace
+ */
+ protected function addPlugins(
+ array $plugins,
+ $sourcePackageName,
+ $rootNamespace = "")
+ {
+ foreach($plugins as $plugin) {
+ if (!isset($plugin->class)) {
+ continue;
+ }
+ $this->addPlugin($plugin, $sourcePackageName, $rootNamespace);
+ }
+ }
+
+ /**
+ * @param \stdClass $plugin
+ * @param string $sourcePackageName
+ * @param string $rootNamespace
+ */
+ protected function addPlugin(
+ $plugin,
+ $sourcePackageName,
+ $rootNamespace = "")
+ {
+ $newPlugin = clone $plugin;
+
+ $newPlugin->class = $rootNamespace . $newPlugin->class;
+
+ if (!isset($newPlugin->name)) {
+ $newPlugin->name = "";
+ }
+
+ $newPlugin->source = $sourcePackageName;
+
+ $this->pluginInfo[] = $newPlugin;
+ }
+}
\ No newline at end of file
diff --git a/PHPCI/Plugin/Util/FilesPluginInformation.php b/PHPCI/Plugin/Util/FilesPluginInformation.php
new file mode 100644
index 00000000..3d8b6f47
--- /dev/null
+++ b/PHPCI/Plugin/Util/FilesPluginInformation.php
@@ -0,0 +1,105 @@
+files = $files;
+ }
+
+ /**
+ * Returns an array of objects. Each one represents an available plugin
+ * and will have the following properties:
+ * name - The friendly name of the plugin (may be an empty string)
+ * class - The class of the plugin (will include namespace)
+ * @return \stdClass[]
+ */
+ public function getInstalledPlugins()
+ {
+ if ($this->pluginInfo === null) {
+ $this->loadPluginInfo();
+ }
+ return $this->pluginInfo;
+ }
+
+ /**
+ * Returns an array of all the class names of plugins that have been
+ * loaded.
+ *
+ * @return string[]
+ */
+ public function getPluginClasses()
+ {
+ return array_map(
+ function($plugin) {
+ return $plugin->class;
+ },
+ $this->getInstalledPlugins()
+ );
+ }
+
+ protected function loadPluginInfo()
+ {
+ $this->pluginInfo = array();
+ foreach($this->files as $fileInfo) {
+ if ($fileInfo instanceof \SplFileInfo) {
+ if ($fileInfo->isFile()) {
+ $this->addPluginFromFile($fileInfo);
+ }
+ }
+ }
+ }
+
+ protected function addPluginFromFile(\SplFileInfo $fileInfo)
+ {
+ $newPlugin = new \stdClass();
+ $newPlugin->class = $this->getFullClassFromFile($fileInfo);
+ $newPlugin->source = "core";
+ $parts = explode('\\', $newPlugin->class);
+ $newPlugin->name = end($parts);
+
+ $this->pluginInfo[] = $newPlugin;
+ }
+
+ protected function getFullClassFromFile(\SplFileInfo $fileInfo)
+ {
+ //TODO: Something less horrible than a regular expression
+ // on the contents of a file
+ $contents = file_get_contents($fileInfo->getRealPath());
+
+ $matches = array();
+ preg_match('#class +([A-Za-z]+) +implements#i', $contents, $matches);
+ $className = $matches[1];
+
+ $matches = array();
+ preg_match('#namespace +([A-Za-z\\\\]+);#i', $contents, $matches);
+ $namespace = $matches[1];
+
+ return $namespace . '\\' . $className;
+ }
+
+}
\ No newline at end of file
diff --git a/PHPCI/Plugin/Util/InstalledPluginInformation.php b/PHPCI/Plugin/Util/InstalledPluginInformation.php
new file mode 100644
index 00000000..f63c432a
--- /dev/null
+++ b/PHPCI/Plugin/Util/InstalledPluginInformation.php
@@ -0,0 +1,23 @@
+pluginInformations[] = $information;
+ }
+
+ /**
+ * Returns an array of objects. Each one represents an available plugin
+ * and will have the following properties:
+ * name - The friendly name of the plugin (may be an empty string)
+ * class - The class of the plugin (will include namespace)
+ * @return \stdClass[]
+ */
+ public function getInstalledPlugins()
+ {
+ $arr = array();
+ foreach($this->pluginInformations as $single) {
+ $arr = array_merge($arr, $single->getInstalledPlugins());
+ }
+ return $arr;
+ }
+
+ /**
+ * Returns an array of all the class names of plugins that have been
+ * loaded.
+ *
+ * @return string[]
+ */
+ public function getPluginClasses()
+ {
+ $arr = array();
+ foreach($this->pluginInformations as $single) {
+ $arr = array_merge($arr, $single->getPluginClasses());
+ }
+ return $arr;
+ }
+
+}
\ No newline at end of file
diff --git a/PHPCI/View/Plugin/index.phtml b/PHPCI/View/Plugin/index.phtml
index 134cf260..3cfac153 100644
--- a/PHPCI/View/Plugin/index.phtml
+++ b/PHPCI/View/Plugin/index.phtml
@@ -1,4 +1,4 @@
-
Plugins
+
Packages and Provided Plugins
PHPCI cannot automatically install/remove plugins for you, as either the shell_exec()
function is disabled or PHPCI could not find Composer. PHPCI will update composer.json for you, but you will need to run Composer manually to make the changes.