diff --git a/lib/Pico.php b/lib/Pico.php index 18817ce..08edde4 100644 --- a/lib/Pico.php +++ b/lib/Pico.php @@ -441,6 +441,29 @@ class Pico return $output; } + /** + * Loads plugins from vendor/pico-plugin.php and Pico::$pluginsDir + * + * See {@see Pico::loadLocalPlugins()} for details about plugins installed + * to {@see Pico::$pluginsDir}, and {@see Pico::loadComposerPlugins()} for + * details about plugins installed using `composer`. + * + * Please note that Pico will change the processing order when needed to + * incorporate plugin dependencies. See {@see Pico::sortPlugins()} for + * details. + * + * @see Pico::loadPlugin() + * @see Pico::getPlugin() + * @see Pico::getPlugins() + * @return void + * @throws RuntimeException thrown when a plugin couldn't be loaded + */ + protected function loadPlugins() + { + $this->loadLocalPlugins(); + $this->loadComposerPlugins(); + } + /** * Loads plugins from Pico::$pluginsDir in alphabetical order * @@ -459,19 +482,13 @@ class Pico * - 60 to 79: Plugins hooking into template or markdown parsing * - 80 to 99: Plugins using the `onPageRendered` event * - * Please note that Pico will change the processing order when needed to - * incorporate plugin dependencies. See {@see Pico::sortPlugins()} for - * details. - * - * @see Pico::loadPlugin() - * @see Pico::getPlugin() - * @see Pico::getPlugins() + * @see Pico::loadPlugins() + * @see Pico::loadComposerPlugins() * @return void * @throws RuntimeException thrown when a plugin couldn't be loaded */ - protected function loadPlugins() + protected function loadLocalPlugins() { - // discover plugin files $pluginFiles = array(); $files = scandir($this->getPluginsDir()); if ($files !== false) { @@ -504,9 +521,9 @@ class Pico } } - // scope isolated require_once() + // scope isolated require() $includeClosure = function ($pluginFile) { - require_once($pluginFile); + require($pluginFile); }; if (PHP_VERSION_ID >= 50400) { $includeClosure = $includeClosure->bindTo(null); @@ -537,6 +554,44 @@ class Pico } } + /** + * Loads plugins from vendor/pico-plugin.php + * + * This method loads all plugins installed using `composer` and Pico's + * `picocms/pico-composer` installer by reading the `pico-plugin.php` in + * composer's `vendor` dir. Using composer enables plugin developers to + * load multiple plugins and their dependencies using a single composer + * package. + * + * @see Pico::loadPlugins() + * @see Pico::loadLocalPlugins() + * @return void + */ + protected function loadComposerPlugins() + { + $composerPlugins = array(); + if (file_exists($this->vendorDir . 'vendor/pico-plugin.php')) { + // composer root package + $composerPlugins = require($this->vendorDir . 'vendor/pico-plugin.php') ?: array(); + } elseif (file_exists($this->vendorDir . '../../../vendor/pico-plugin.php')) { + // composer dependency package + $composerPlugins = require($this->vendorDir . '../../../vendor/pico-plugin.php') ?: array(); + } + + foreach ($composerPlugins as $package => $classNames) { + foreach ($classNames as $className) { + $plugin = new $className($this); + $this->plugins[$className] = $plugin; + + if ($plugin instanceof PicoPluginInterface) { + if (defined($className . '::API_VERSION') && ($className::API_VERSION >= static::API_VERSION)) { + $this->nativePlugins[$className] = $plugin; + } + } + } + } + } + /** * Manually loads a plugin * @@ -2043,7 +2098,7 @@ class Pico * Please note that {@see PicoDeprecated} also triggers custom events on * plugins using older API versions, thus you can safely use this method * to trigger custom events on all loaded plugins, no matter what API - * version - the event will be triggered in any case + * version - the event will be triggered in any case. * * You MUST NOT trigger events of Pico's core with a plugin! *