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