Browse Source

Load plugins from <plugin name>.php and <plugin name>/<plugin name>.php only

Daniel Rudolf 8 years ago
parent
commit
9254240
1 changed files with 49 additions and 18 deletions
  1. 49 18
      lib/Pico.php

+ 49 - 18
lib/Pico.php

@@ -426,15 +426,18 @@ class Pico
     /**
      * Loads plugins from Pico::$pluginsDir in alphabetical order
      *
+     * Pico tries to load plugins from `<plugin name>/<plugin name>.php` and
+     * `<plugin name>.php` only. Plugin names are treated case insensitive.
+     * Pico will throw a RuntimeException if it can't load a plugin.
+     *
      * Plugin files MAY be prefixed by a number (e.g. 00-PicoDeprecated.php)
      * to indicate their processing order. Plugins without a prefix will be
-     * loaded last. If you want to use a prefix, you MUST consider the
-     * following directives:
-     * - 00 to 19: Reserved
-     * - 20 to 39: Low level code helper plugins
-     * - 40 to 59: Plugins manipulating routing or the pages array
-     * - 60 to 79: Plugins hooking into template or markdown parsing
-     * - 80 to 99: Plugins using the `onPageRendered` event
+     * loaded last. If you want to use a prefix, you MUST NOT use the reserved
+     * prefixes `00` to `09`.
+     *
+     * 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()
@@ -444,6 +447,41 @@ class Pico
      */
     protected function loadPlugins()
     {
+        $this->plugins = array();
+
+        // discover plugin files
+        $pluginFiles = array();
+        $files = scandir($this->getPluginsDir());
+        if ($files !== false) {
+            foreach ($files as $file) {
+                if ($file[0] === '.') {
+                    continue;
+                }
+
+                if (is_dir($this->getPluginsDir() . $file)) {
+                    $className = preg_replace('/^[0-9]+-/', '', $file);
+
+                    $subdirFiles = $this->getFilesGlob($this->getPluginsDir() . $file . '/?*.php', self::SORT_NONE);
+                    foreach ($subdirFiles as $subdirFile) {
+                        $subdirFile = basename($subdirFile, '.php');
+                        if (strcasecmp($className, $subdirFile) === 0) {
+                            $pluginFiles[$className] = $file . '/' . $subdirFile . '.php';
+                        }
+                    }
+
+                    if (!isset($pluginFiles[$className])) {
+                        throw new RuntimeException(
+                            "Unable to load plugin '" . $className . "' from "
+                            . "'" . $file . "/" . $className . ".php': File not found"
+                        );
+                    }
+                } elseif (substr($file, -4) === '.php') {
+                    $className = preg_replace('/^[0-9]+-/', '', substr($file, 0, -4));
+                    $pluginFiles[$className] = $file;
+                }
+            }
+        }
+
         // scope isolated require_once()
         $includeClosure = function ($pluginFile) {
             require_once($pluginFile);
@@ -452,27 +490,20 @@ class Pico
             $includeClosure = $includeClosure->bindTo(null);
         }
 
-        $this->plugins = array();
-        $pluginFiles = $this->getFiles($this->getPluginsDir(), '.php');
-        foreach ($pluginFiles as $pluginFile) {
-            $includeClosure($pluginFile);
+        foreach ($pluginFiles as $className => $pluginFile) {
+            $includeClosure($this->getPluginsDir() . $pluginFile);
 
-            $className = preg_replace('/^[0-9]+-/', '', basename($pluginFile, '.php'));
-            if (class_exists($className)) {
+            if (class_exists($className, false)) {
                 // class name and file name can differ regarding case sensitivity
                 $plugin = new $className($this);
                 $className = get_class($plugin);
 
                 $this->plugins[$className] = $plugin;
             } else {
-                // TODO: breaks backward compatibility
-                /*
-                $pluginFileName = substr($pluginFile, strlen($this->getPluginsDir()));
                 throw new RuntimeException(
                     "Unable to load plugin '" . $className . "' "
-                    . "from '" . $pluginFileName . "'"
+                    . "from '" . $pluginFile . "'"
                 );
-                */
             }
         }
     }