xref: /dokuwiki/inc/Extension/PluginController.php (revision c47e666521a91dba7c802073af36cad88c8d9244)
13a7140a1SAndreas Gohr<?php
2c904b9fbSAndreas Gohr
3c904b9fbSAndreas Gohrnamespace dokuwiki\Extension;
4c904b9fbSAndreas Gohr
53a7140a1SAndreas Gohr/**
63a7140a1SAndreas Gohr * Class to encapsulate access to dokuwiki plugins
73a7140a1SAndreas Gohr *
83a7140a1SAndreas Gohr * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
93a7140a1SAndreas Gohr * @author     Christopher Smith <chris@jalakai.co.uk>
103a7140a1SAndreas Gohr */
113a7140a1SAndreas Gohrclass PluginController
123a7140a1SAndreas Gohr{
131935a891SAndreas Gohr    /** @var array the types of plugins DokuWiki supports */
141935a891SAndreas Gohr    const PLUGIN_TYPES = ['auth', 'admin', 'syntax', 'action', 'renderer', 'helper', 'remote', 'cli'];
153a7140a1SAndreas Gohr
16c904b9fbSAndreas Gohr    protected $listByType = [];
17c904b9fbSAndreas Gohr    /** @var array all installed plugins and their enabled state [plugin=>enabled] */
18c904b9fbSAndreas Gohr    protected $masterList = [];
19c904b9fbSAndreas Gohr    protected $pluginCascade = ['default' => [], 'local' => [], 'protected' => []];
20c904b9fbSAndreas Gohr    protected $lastLocalConfigFile = '';
213a7140a1SAndreas Gohr
223a7140a1SAndreas Gohr    /**
233a7140a1SAndreas Gohr     * Populates the master list of plugins
243a7140a1SAndreas Gohr     */
253a7140a1SAndreas Gohr    public function __construct()
263a7140a1SAndreas Gohr    {
273a7140a1SAndreas Gohr        $this->loadConfig();
28c904b9fbSAndreas Gohr        $this->populateMasterList();
293a7140a1SAndreas Gohr    }
303a7140a1SAndreas Gohr
313a7140a1SAndreas Gohr    /**
323a7140a1SAndreas Gohr     * Returns a list of available plugins of given type
333a7140a1SAndreas Gohr     *
343a7140a1SAndreas Gohr     * @param $type  string, plugin_type name;
353a7140a1SAndreas Gohr     *               the type of plugin to return,
363a7140a1SAndreas Gohr     *               use empty string for all types
373a7140a1SAndreas Gohr     * @param $all   bool;
383a7140a1SAndreas Gohr     *               false to only return enabled plugins,
393a7140a1SAndreas Gohr     *               true to return both enabled and disabled plugins
403a7140a1SAndreas Gohr     *
413a7140a1SAndreas Gohr     * @return       array of
423a7140a1SAndreas Gohr     *                  - plugin names when $type = ''
433a7140a1SAndreas Gohr     *                  - or plugin component names when a $type is given
443a7140a1SAndreas Gohr     *
453a7140a1SAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
463a7140a1SAndreas Gohr     */
473a7140a1SAndreas Gohr    public function getList($type = '', $all = false)
483a7140a1SAndreas Gohr    {
493a7140a1SAndreas Gohr
503a7140a1SAndreas Gohr        // request the complete list
513a7140a1SAndreas Gohr        if (!$type) {
52c904b9fbSAndreas Gohr            return $all ? array_keys($this->masterList) : array_keys(array_filter($this->masterList));
533a7140a1SAndreas Gohr        }
543a7140a1SAndreas Gohr
55c904b9fbSAndreas Gohr        if (!isset($this->listByType[$type]['enabled'])) {
56c904b9fbSAndreas Gohr            $this->listByType[$type]['enabled'] = $this->getListByType($type, true);
573a7140a1SAndreas Gohr        }
58c904b9fbSAndreas Gohr        if ($all && !isset($this->listByType[$type]['disabled'])) {
59c904b9fbSAndreas Gohr            $this->listByType[$type]['disabled'] = $this->getListByType($type, false);
603a7140a1SAndreas Gohr        }
613a7140a1SAndreas Gohr
623a7140a1SAndreas Gohr        return $all
63c904b9fbSAndreas Gohr            ? array_merge($this->listByType[$type]['enabled'], $this->listByType[$type]['disabled'])
64c904b9fbSAndreas Gohr            : $this->listByType[$type]['enabled'];
653a7140a1SAndreas Gohr    }
663a7140a1SAndreas Gohr
673a7140a1SAndreas Gohr    /**
683a7140a1SAndreas Gohr     * Loads the given plugin and creates an object of it
693a7140a1SAndreas Gohr     *
703a7140a1SAndreas Gohr     * @param  $type     string type of plugin to load
713a7140a1SAndreas Gohr     * @param  $name     string name of the plugin to load
723a7140a1SAndreas Gohr     * @param  $new      bool   true to return a new instance of the plugin, false to use an already loaded instance
733a7140a1SAndreas Gohr     * @param  $disabled bool   true to load even disabled plugins
743a7140a1SAndreas Gohr     * @return PluginInterface|null  the plugin object or null on failure
75c904b9fbSAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
76c904b9fbSAndreas Gohr     *
773a7140a1SAndreas Gohr     */
783a7140a1SAndreas Gohr    public function load($type, $name, $new = false, $disabled = false)
793a7140a1SAndreas Gohr    {
803a7140a1SAndreas Gohr
813a7140a1SAndreas Gohr        //we keep all loaded plugins available in global scope for reuse
823a7140a1SAndreas Gohr        global $DOKU_PLUGINS;
833a7140a1SAndreas Gohr
84c904b9fbSAndreas Gohr        list($plugin, /* $component */) = $this->splitName($name);
853a7140a1SAndreas Gohr
863a7140a1SAndreas Gohr        // check if disabled
87c904b9fbSAndreas Gohr        if (!$disabled && !$this->isEnabled($plugin)) {
883a7140a1SAndreas Gohr            return null;
893a7140a1SAndreas Gohr        }
903a7140a1SAndreas Gohr
913a7140a1SAndreas Gohr        $class = $type . '_plugin_' . $name;
923a7140a1SAndreas Gohr
933a7140a1SAndreas Gohr        //plugin already loaded?
943a7140a1SAndreas Gohr        if (!empty($DOKU_PLUGINS[$type][$name])) {
953a7140a1SAndreas Gohr            if ($new || !$DOKU_PLUGINS[$type][$name]->isSingleton()) {
963a7140a1SAndreas Gohr                return class_exists($class, true) ? new $class : null;
973a7140a1SAndreas Gohr            }
98c904b9fbSAndreas Gohr
99c904b9fbSAndreas Gohr            return $DOKU_PLUGINS[$type][$name];
1003a7140a1SAndreas Gohr        }
1013a7140a1SAndreas Gohr
1023a7140a1SAndreas Gohr        //construct class and instantiate
1033a7140a1SAndreas Gohr        if (!class_exists($class, true)) {
1043a7140a1SAndreas Gohr
1053a7140a1SAndreas Gohr            # the plugin might be in the wrong directory
106f219f385SAndreas Gohr            $inf = confToHash(DOKU_PLUGIN . "$plugin/plugin.info.txt");
1073a7140a1SAndreas Gohr            if ($inf['base'] && $inf['base'] != $plugin) {
1083a7140a1SAndreas Gohr                msg(
1093a7140a1SAndreas Gohr                    sprintf(
1103a7140a1SAndreas Gohr                        "Plugin installed incorrectly. Rename plugin directory '%s' to '%s'.",
1113a7140a1SAndreas Gohr                        hsc($plugin),
1123a7140a1SAndreas Gohr                        hsc(
1133a7140a1SAndreas Gohr                            $inf['base']
1143a7140a1SAndreas Gohr                        )
1153a7140a1SAndreas Gohr                    ), -1
1163a7140a1SAndreas Gohr                );
1173a7140a1SAndreas Gohr            } elseif (preg_match('/^' . DOKU_PLUGIN_NAME_REGEX . '$/', $plugin) !== 1) {
1183a7140a1SAndreas Gohr                msg(
1193a7140a1SAndreas Gohr                    sprintf(
1203a7140a1SAndreas Gohr                        "Plugin name '%s' is not a valid plugin name, only the characters a-z and 0-9 are allowed. " .
1213a7140a1SAndreas Gohr                        'Maybe the plugin has been installed in the wrong directory?', hsc($plugin)
1223a7140a1SAndreas Gohr                    ), -1
1233a7140a1SAndreas Gohr                );
1243a7140a1SAndreas Gohr            }
1253a7140a1SAndreas Gohr            return null;
1263a7140a1SAndreas Gohr        }
1273a7140a1SAndreas Gohr
1283a7140a1SAndreas Gohr        $DOKU_PLUGINS[$type][$name] = new $class;
1293a7140a1SAndreas Gohr        return $DOKU_PLUGINS[$type][$name];
1303a7140a1SAndreas Gohr    }
1313a7140a1SAndreas Gohr
1323a7140a1SAndreas Gohr    /**
1333a7140a1SAndreas Gohr     * Whether plugin is disabled
1343a7140a1SAndreas Gohr     *
1353a7140a1SAndreas Gohr     * @param string $plugin name of plugin
1363a7140a1SAndreas Gohr     * @return bool  true disabled, false enabled
137fbccc3e6SAndreas Gohr     * @deprecated in favor of the more sensible isEnabled where the return value matches the enabled state
1383a7140a1SAndreas Gohr     */
139fbccc3e6SAndreas Gohr    public function isDisabled($plugin)
1403a7140a1SAndreas Gohr    {
141fbccc3e6SAndreas Gohr        dbg_deprecated('isEnabled()');
142fbccc3e6SAndreas Gohr        return !$this->isEnabled($plugin);
143fbccc3e6SAndreas Gohr    }
144fbccc3e6SAndreas Gohr
145fbccc3e6SAndreas Gohr    /**
146fbccc3e6SAndreas Gohr     * Check whether plugin is disabled
147fbccc3e6SAndreas Gohr     *
148fbccc3e6SAndreas Gohr     * @param string $plugin name of plugin
149fbccc3e6SAndreas Gohr     * @return bool  true enabled, false disabled
150fbccc3e6SAndreas Gohr     */
151fbccc3e6SAndreas Gohr    public function isEnabled($plugin)
152fbccc3e6SAndreas Gohr    {
153c904b9fbSAndreas Gohr        return !empty($this->masterList[$plugin]);
1543a7140a1SAndreas Gohr    }
1553a7140a1SAndreas Gohr
1563a7140a1SAndreas Gohr    /**
1573a7140a1SAndreas Gohr     * Disable the plugin
1583a7140a1SAndreas Gohr     *
1593a7140a1SAndreas Gohr     * @param string $plugin name of plugin
1603a7140a1SAndreas Gohr     * @return bool  true saving succeed, false saving failed
1613a7140a1SAndreas Gohr     */
1623a7140a1SAndreas Gohr    public function disable($plugin)
1633a7140a1SAndreas Gohr    {
164c904b9fbSAndreas Gohr        if (array_key_exists($plugin, $this->pluginCascade['protected'])) return false;
165c904b9fbSAndreas Gohr        $this->masterList[$plugin] = 0;
1663a7140a1SAndreas Gohr        return $this->saveList();
1673a7140a1SAndreas Gohr    }
1683a7140a1SAndreas Gohr
1693a7140a1SAndreas Gohr    /**
1703a7140a1SAndreas Gohr     * Enable the plugin
1713a7140a1SAndreas Gohr     *
1723a7140a1SAndreas Gohr     * @param string $plugin name of plugin
1733a7140a1SAndreas Gohr     * @return bool  true saving succeed, false saving failed
1743a7140a1SAndreas Gohr     */
1753a7140a1SAndreas Gohr    public function enable($plugin)
1763a7140a1SAndreas Gohr    {
177c904b9fbSAndreas Gohr        if (array_key_exists($plugin, $this->pluginCascade['protected'])) return false;
178c904b9fbSAndreas Gohr        $this->masterList[$plugin] = 1;
1793a7140a1SAndreas Gohr        return $this->saveList();
1803a7140a1SAndreas Gohr    }
1813a7140a1SAndreas Gohr
1823a7140a1SAndreas Gohr    /**
1833a7140a1SAndreas Gohr     * Returns cascade of the config files
1843a7140a1SAndreas Gohr     *
1853a7140a1SAndreas Gohr     * @return array with arrays of plugin configs
1863a7140a1SAndreas Gohr     */
1873a7140a1SAndreas Gohr    public function getCascade()
1883a7140a1SAndreas Gohr    {
189c904b9fbSAndreas Gohr        return $this->pluginCascade;
1903a7140a1SAndreas Gohr    }
1913a7140a1SAndreas Gohr
192c904b9fbSAndreas Gohr    /**
193c904b9fbSAndreas Gohr     * Read all installed plugins and their current enabled state
194c904b9fbSAndreas Gohr     */
195c904b9fbSAndreas Gohr    protected function populateMasterList()
1963a7140a1SAndreas Gohr    {
1973a7140a1SAndreas Gohr        if ($dh = @opendir(DOKU_PLUGIN)) {
1983a7140a1SAndreas Gohr            $all_plugins = array();
1993a7140a1SAndreas Gohr            while (false !== ($plugin = readdir($dh))) {
200c904b9fbSAndreas Gohr                if ($plugin[0] === '.') continue;               // skip hidden entries
2013a7140a1SAndreas Gohr                if (is_file(DOKU_PLUGIN . $plugin)) continue;    // skip files, we're only interested in directories
2023a7140a1SAndreas Gohr
203c904b9fbSAndreas Gohr                if (array_key_exists($plugin, $this->masterList) && $this->masterList[$plugin] == 0) {
2043a7140a1SAndreas Gohr                    $all_plugins[$plugin] = 0;
2053a7140a1SAndreas Gohr
206c904b9fbSAndreas Gohr                } elseif (array_key_exists($plugin, $this->masterList) && $this->masterList[$plugin] == 1) {
2073a7140a1SAndreas Gohr                    $all_plugins[$plugin] = 1;
2083a7140a1SAndreas Gohr                } else {
2093a7140a1SAndreas Gohr                    $all_plugins[$plugin] = 1;
2103a7140a1SAndreas Gohr                }
2113a7140a1SAndreas Gohr            }
212c904b9fbSAndreas Gohr            $this->masterList = $all_plugins;
213c904b9fbSAndreas Gohr            if (!file_exists($this->lastLocalConfigFile)) {
2143a7140a1SAndreas Gohr                $this->saveList(true);
2153a7140a1SAndreas Gohr            }
2163a7140a1SAndreas Gohr        }
2173a7140a1SAndreas Gohr    }
2183a7140a1SAndreas Gohr
2193a7140a1SAndreas Gohr    /**
2203a7140a1SAndreas Gohr     * Includes the plugin config $files
2213a7140a1SAndreas Gohr     * and returns the entries of the $plugins array set in these files
2223a7140a1SAndreas Gohr     *
2233a7140a1SAndreas Gohr     * @param array $files list of files to include, latter overrides previous
2243a7140a1SAndreas Gohr     * @return array with entries of the $plugins arrays of the included files
2253a7140a1SAndreas Gohr     */
2263a7140a1SAndreas Gohr    protected function checkRequire($files)
2273a7140a1SAndreas Gohr    {
2283a7140a1SAndreas Gohr        $plugins = array();
2293a7140a1SAndreas Gohr        foreach ($files as $file) {
2303a7140a1SAndreas Gohr            if (file_exists($file)) {
2313a7140a1SAndreas Gohr                include_once($file);
2323a7140a1SAndreas Gohr            }
2333a7140a1SAndreas Gohr        }
2343a7140a1SAndreas Gohr        return $plugins;
2353a7140a1SAndreas Gohr    }
2363a7140a1SAndreas Gohr
2373a7140a1SAndreas Gohr    /**
2383a7140a1SAndreas Gohr     * Save the current list of plugins
2393a7140a1SAndreas Gohr     *
2403a7140a1SAndreas Gohr     * @param bool $forceSave ;
2413a7140a1SAndreas Gohr     *              false to save only when config changed
2423a7140a1SAndreas Gohr     *              true to always save
2433a7140a1SAndreas Gohr     * @return bool  true saving succeed, false saving failed
2443a7140a1SAndreas Gohr     */
2453a7140a1SAndreas Gohr    protected function saveList($forceSave = false)
2463a7140a1SAndreas Gohr    {
2473a7140a1SAndreas Gohr        global $conf;
2483a7140a1SAndreas Gohr
249c904b9fbSAndreas Gohr        if (empty($this->masterList)) return false;
2503a7140a1SAndreas Gohr
2513a7140a1SAndreas Gohr        // Rebuild list of local settings
2523a7140a1SAndreas Gohr        $local_plugins = $this->rebuildLocal();
253c904b9fbSAndreas Gohr        if ($local_plugins != $this->pluginCascade['local'] || $forceSave) {
254c904b9fbSAndreas Gohr            $file = $this->lastLocalConfigFile;
2553a7140a1SAndreas Gohr            $out = "<?php\n/*\n * Local plugin enable/disable settings\n" .
2563a7140a1SAndreas Gohr                " * Auto-generated through plugin/extension manager\n *\n" .
2573a7140a1SAndreas Gohr                " * NOTE: Plugins will not be added to this file unless there " .
2583a7140a1SAndreas Gohr                "is a need to override a default setting. Plugins are\n" .
2593a7140a1SAndreas Gohr                " *       enabled by default.\n */\n";
2603a7140a1SAndreas Gohr            foreach ($local_plugins as $plugin => $value) {
2613a7140a1SAndreas Gohr                $out .= "\$plugins['$plugin'] = $value;\n";
2623a7140a1SAndreas Gohr            }
2633a7140a1SAndreas Gohr            // backup current file (remove any existing backup)
2643a7140a1SAndreas Gohr            if (file_exists($file)) {
2653a7140a1SAndreas Gohr                $backup = $file . '.bak';
2663a7140a1SAndreas Gohr                if (file_exists($backup)) @unlink($backup);
2673a7140a1SAndreas Gohr                if (!@copy($file, $backup)) return false;
2683a7140a1SAndreas Gohr                if (!empty($conf['fperm'])) chmod($backup, $conf['fperm']);
2693a7140a1SAndreas Gohr            }
2703a7140a1SAndreas Gohr            //check if can open for writing, else restore
2713a7140a1SAndreas Gohr            return io_saveFile($file, $out);
2723a7140a1SAndreas Gohr        }
2733a7140a1SAndreas Gohr        return false;
2743a7140a1SAndreas Gohr    }
2753a7140a1SAndreas Gohr
2763a7140a1SAndreas Gohr    /**
2773a7140a1SAndreas Gohr     * Rebuild the set of local plugins
2783a7140a1SAndreas Gohr     *
2793a7140a1SAndreas Gohr     * @return array array of plugins to be saved in end($config_cascade['plugins']['local'])
2803a7140a1SAndreas Gohr     */
2813a7140a1SAndreas Gohr    protected function rebuildLocal()
2823a7140a1SAndreas Gohr    {
2833a7140a1SAndreas Gohr        //assign to local variable to avoid overwriting
284c904b9fbSAndreas Gohr        $backup = $this->masterList;
2853a7140a1SAndreas Gohr        //Can't do anything about protected one so rule them out completely
286c904b9fbSAndreas Gohr        $local_default = array_diff_key($backup, $this->pluginCascade['protected']);
2873a7140a1SAndreas Gohr        //Diff between local+default and default
2883a7140a1SAndreas Gohr        //gives us the ones we need to check and save
289c904b9fbSAndreas Gohr        $diffed_ones = array_diff_key($local_default, $this->pluginCascade['default']);
2903a7140a1SAndreas Gohr        //The ones which we are sure of (list of 0s not in default)
2913a7140a1SAndreas Gohr        $sure_plugins = array_filter($diffed_ones, array($this, 'negate'));
2923a7140a1SAndreas Gohr        //the ones in need of diff
2933a7140a1SAndreas Gohr        $conflicts = array_diff_key($local_default, $diffed_ones);
2943a7140a1SAndreas Gohr        //The final list
295c904b9fbSAndreas Gohr        return array_merge($sure_plugins, array_diff_assoc($conflicts, $this->pluginCascade['default']));
2963a7140a1SAndreas Gohr    }
2973a7140a1SAndreas Gohr
2983a7140a1SAndreas Gohr    /**
2993a7140a1SAndreas Gohr     * Build the list of plugins and cascade
3003a7140a1SAndreas Gohr     *
3013a7140a1SAndreas Gohr     */
3023a7140a1SAndreas Gohr    protected function loadConfig()
3033a7140a1SAndreas Gohr    {
3043a7140a1SAndreas Gohr        global $config_cascade;
3053a7140a1SAndreas Gohr        foreach (array('default', 'protected') as $type) {
3063a7140a1SAndreas Gohr            if (array_key_exists($type, $config_cascade['plugins'])) {
307c904b9fbSAndreas Gohr                $this->pluginCascade[$type] = $this->checkRequire($config_cascade['plugins'][$type]);
3083a7140a1SAndreas Gohr            }
3093a7140a1SAndreas Gohr        }
3103a7140a1SAndreas Gohr        $local = $config_cascade['plugins']['local'];
311c904b9fbSAndreas Gohr        $this->lastLocalConfigFile = array_pop($local);
312c904b9fbSAndreas Gohr        $this->pluginCascade['local'] = $this->checkRequire(array($this->lastLocalConfigFile));
3133a7140a1SAndreas Gohr        if (is_array($local)) {
314c904b9fbSAndreas Gohr            $this->pluginCascade['default'] = array_merge(
315c904b9fbSAndreas Gohr                $this->pluginCascade['default'],
3163a7140a1SAndreas Gohr                $this->checkRequire($local)
3173a7140a1SAndreas Gohr            );
3183a7140a1SAndreas Gohr        }
319c904b9fbSAndreas Gohr        $this->masterList = array_merge(
320c904b9fbSAndreas Gohr            $this->pluginCascade['default'],
321c904b9fbSAndreas Gohr            $this->pluginCascade['local'],
322c904b9fbSAndreas Gohr            $this->pluginCascade['protected']
3233a7140a1SAndreas Gohr        );
3243a7140a1SAndreas Gohr    }
3253a7140a1SAndreas Gohr
3263a7140a1SAndreas Gohr    /**
3273a7140a1SAndreas Gohr     * Returns a list of available plugin components of given type
3283a7140a1SAndreas Gohr     *
3293a7140a1SAndreas Gohr     * @param string $type plugin_type name; the type of plugin to return,
3303a7140a1SAndreas Gohr     * @param bool $enabled true to return enabled plugins,
3313a7140a1SAndreas Gohr     *                          false to return disabled plugins
3323a7140a1SAndreas Gohr     * @return array of plugin components of requested type
3333a7140a1SAndreas Gohr     */
334c904b9fbSAndreas Gohr    protected function getListByType($type, $enabled)
3353a7140a1SAndreas Gohr    {
3363a7140a1SAndreas Gohr        $master_list = $enabled
337c904b9fbSAndreas Gohr            ? array_keys(array_filter($this->masterList))
338c904b9fbSAndreas Gohr            : array_keys(array_filter($this->masterList, array($this, 'negate')));
3393a7140a1SAndreas Gohr        $plugins = array();
3403a7140a1SAndreas Gohr
3413a7140a1SAndreas Gohr        foreach ($master_list as $plugin) {
3423a7140a1SAndreas Gohr
343f219f385SAndreas Gohr            if (file_exists(DOKU_PLUGIN . "$plugin/$type.php")) {
3443a7140a1SAndreas Gohr                $plugins[] = $plugin;
3453a7140a1SAndreas Gohr                continue;
3463a7140a1SAndreas Gohr            }
3473a7140a1SAndreas Gohr
348f219f385SAndreas Gohr            $typedir = DOKU_PLUGIN . "$plugin/$type/";
3493a7140a1SAndreas Gohr            if (is_dir($typedir)) {
3503a7140a1SAndreas Gohr                if ($dp = opendir($typedir)) {
3513a7140a1SAndreas Gohr                    while (false !== ($component = readdir($dp))) {
352*c47e6665SAndreas Gohr                        if (strpos($component, '.') === 0 || strtolower(substr($component, -4)) !== '.php') continue;
3533a7140a1SAndreas Gohr                        if (is_file($typedir . $component)) {
3543a7140a1SAndreas Gohr                            $plugins[] = $plugin . '_' . substr($component, 0, -4);
3553a7140a1SAndreas Gohr                        }
3563a7140a1SAndreas Gohr                    }
3573a7140a1SAndreas Gohr                    closedir($dp);
3583a7140a1SAndreas Gohr                }
3593a7140a1SAndreas Gohr            }
3603a7140a1SAndreas Gohr
3613a7140a1SAndreas Gohr        }//foreach
3623a7140a1SAndreas Gohr
3633a7140a1SAndreas Gohr        return $plugins;
3643a7140a1SAndreas Gohr    }
3653a7140a1SAndreas Gohr
3663a7140a1SAndreas Gohr    /**
3673a7140a1SAndreas Gohr     * Split name in a plugin name and a component name
3683a7140a1SAndreas Gohr     *
3693a7140a1SAndreas Gohr     * @param string $name
3703a7140a1SAndreas Gohr     * @return array with
3713a7140a1SAndreas Gohr     *              - plugin name
3723a7140a1SAndreas Gohr     *              - and component name when available, otherwise empty string
3733a7140a1SAndreas Gohr     */
374c904b9fbSAndreas Gohr    protected function splitName($name)
3753a7140a1SAndreas Gohr    {
376*c47e6665SAndreas Gohr        if (!isset($this->masterList[$name])) {
3773a7140a1SAndreas Gohr            return explode('_', $name, 2);
3783a7140a1SAndreas Gohr        }
3793a7140a1SAndreas Gohr
3803a7140a1SAndreas Gohr        return array($name, '');
3813a7140a1SAndreas Gohr    }
3823a7140a1SAndreas Gohr
3833a7140a1SAndreas Gohr    /**
3843a7140a1SAndreas Gohr     * Returns inverse boolean value of the input
3853a7140a1SAndreas Gohr     *
3863a7140a1SAndreas Gohr     * @param mixed $input
3873a7140a1SAndreas Gohr     * @return bool inversed boolean value of input
3883a7140a1SAndreas Gohr     */
3893a7140a1SAndreas Gohr    protected function negate($input)
3903a7140a1SAndreas Gohr    {
3913a7140a1SAndreas Gohr        return !(bool)$input;
3923a7140a1SAndreas Gohr    }
3933a7140a1SAndreas Gohr}
394