Login   Register  
PHP Classes
elePHPant
Icontem

File: lib/PluginManager.class.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of David N. Q. Duong  >  XIRE  >  lib/PluginManager.class.php  >  Download  
File: lib/PluginManager.class.php
Role: Class source
Content type: text/plain
Description: Plugin Manager Class
Class: XIRE
Template engine extensible with plug-in classes
Author: By
Last change:
Date: 8 years ago
Size: 10,587 bytes
 

Contents

Class file image Download
<?php
/* --------------------------------------------------------------------------
 * XIRE - eXtendable Information Rendering Engine
 * --------------------------------------------------------------------------
 * LICENSE
 * Copyright (C) 2006  David Duong
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 * -------------------------------------------------------------------------- */
/**
 * Handles the registration and utilization of plugins.
 *
 */
class XIRE_PluginManager {
    private $plugins;       // Registered plugins
    private $instances;
    private $directories;   // Registered plugin directories

    public function __construct () {
        $this->plugins = array();
        $this->directories = array(dirname(__FILE__) . '/plugins');
    }

    /**
     * Register a plugin with an editable node name
     *
     * @param string $name the local name of a node
     * @param string $filename the filename of the plugin class
     */
    public function set ($name, $filename) {
        $this->plugins[$name] = $filename;
    }

    /**
     * Register a plugin directory
     *
     * If a node is found without a registered plugin, all registered plugin directories 
     * will be searched for a plugin that handles the node.
     * @param string $directory
     */
    public function addDirectory ($directory) {
        $this->directories[] = $directory;
    }

    /**
     * Call the plugin that is associated with a node
     *
     * When a process finds a editable node, it will have this plugin manager locate and 
     * call the corresponding plugin for the node. Plugins, or directories containing a 
     * group of plugins, are registered so when a process finds a node that matches the 
     * registration, it will load, instantiate, and call the plugin, handing control of the 
     * node, and child nodes, to the plugin.
     * @param DOMNode $node this method will seek a plugin that is associated (by the 
     * node's local name) and have the plugin handle the node
     * @param XIRE_Template $sender the template making this request
     * @throws XIRE_MissingPluginException if a the plugin could not be found
     */
    public function call (DOMNode $node, XIRE_Process $sender) {
        isset($this->plugins[$node->localName]) or $this->load($node);
        $plugin = new $this->plugins[$node->localName]($node, $sender);
        $plugin->execute();
    }

    /**
     * @param string $name this method will search for a plugin that will handle the given
     * node
     * @throws XIRE_MissingPluginException if a the plugin could not be found
     */
    private function load (DOMNode $node) {
        // Convert element names to class names, ie. something like node-name to NodeName
        if (strpos($node->localName, '-') !== false) {
            $base_name = str_replace(' ', '', ucwords(strtr($node->localName, '-', ' ')));
        } else {
            $base_name = ucfirst($node->localName);
        }
        // Search each registered directory
        foreach ($this->directories as $directory) {
            if ($node instanceof DOMElement
              && file_exists("$directory/Element_$base_name.class.php")) {
                include "$directory/Element_$base_name.class.php";
                $class_name = "XIRE_Plugin_Element_$base_name";
                break;
            } elseif ($node instanceof DOMAttr
              && file_exists("$directory/Attribute_$base_name.class.php")) {
                include "$directory/Attribute_$base_name.class.php";
                $class_name = "XIRE_Plugin_Attribute_$base_name";
                break;
            } elseif (file_exists("$directory/$base_name.class.php")) {
                include "$directory/$base_name.class.php";
                $class_name = "XIRE_Plugin_$base_name";
                break;
            }
        }
        if (!isset($class_name)) {
            // Plugin file not found!
            throw new XIRE_MissingPluginException(
              "Missing plugin file for: {$node->localName}", $node, 0);
        } elseif (class_exists($class_name)) {
            $this->plugins[$node->localName] = $class_name;
        } elseif (class_exists($base_name)) {
            $this->plugins[$node->localName] = $base_name;
        } else {
            // Plugin class not found!
            throw new XIRE_MissingPluginException(
              "Missing plugin class for: {$node->localName}", $node, 1);
        }
    }
}

/**
 * Required superclass of all plugins
 */
abstract class XIRE_Plugin {
    protected $template;    // The template that is calling the plugin
    protected $document;
    protected $process;
    protected $node;
    protected $id;
    private static $ids;

    /**
     * This method is called when a node is to be parsed and must be implemented
     */
    abstract public function execute ();

    public function __construct (DOMNode $node, XIRE_Process $sender) {
        $this->node = $node;
        $this->process = $sender;
        $this->template = $sender->template;
        $this->document = $sender->template->document;

        // All XIRL elements must have a unique id
        if ($node instanceof DOMElement) {
            $current_id = $node->getAttribute('id');
            if (empty($current_id)
              || $this->template->document->getElementById($current_id) !== $node) {
                $current_id = $node->localName;
                if (isset(self::$ids[$node->localName])) {
                    $current_id .= '_' . self::$ids[$node->localName]++;
                } else {
                    self::$ids[$node->localName] = 1;
                }
                while ($this->template->document->getElementById($current_id) !== null) {
                    $current_id = "{$node->localName}_" . self::$ids[$node->localName]++;
                }
                $this->id = $current_id;
                $node->setAttribute('id', $current_id);
            }
        }
    }

    /**
     * Set a template variable called $name with the value $value within the scope of the
     * current node
     */
    protected function setVariable ($name, $value) {
        $this->template["{$this->id}::$name"] = $value;
    }

    /**
     * @param string $name
     * @param boolean $cascade if set to true, this function will also search parent nodes
     * @return bool true if the variable is found or false otherwise
     */
    protected function hasVariable ($name, $cascade = false) {
        if ($cumulative) {
            return $this->template->has($name);
        }
        $current = $this->node;
        do {
            if ($current->namespaceURI === XIRL_NAMESPACE) {
                $current_id = $current->getAttribute('id');
                if (isset($this->template["$current_id::$name"])) {
                    return true;
                }
            }
            $current = ($cumulative)? $current->parentNode : null;
        } while ($current instanceof DOMElement);
    }

    /**
     * @param string $name
     * @param mixed $default determine what should be returned if the variable is not 
     * found
     * @throws XIRE_MissingVariableException when $default is not set and the template 
     * variable is not set
     * @return the template variable with the given name in the current node's scope
     */
    protected function getVariable ($name, $default = null) {
        if (isset($this->template["{$this->id}::$name"])) {
            return $this->template["{$this->id}::$name"];
        } elseif (func_num_args() > 1) {
            return $default;
        }
        throw new XIRE_MissingVariableException("{$this->id}::$name");
    }

    /**
     * @param string $name
     * @param mixed $default determine what should be returned if the variable is not 
     * found
     * @return the template variable with the given name in the node or the closest closest 
     * ancestors' scope
     */
    protected function getVariable_cascade ($name, $default = null) {
        $current = $this->node;
        do {
            if ($current->namespaceURI === XIRL_NAMESPACE) {
                $current_id = $current->getAttribute('id');
                if (isset($this->template["$current_id::$name"])) {
                    return $this->template["$current_id::$name"];
                }
            }
            $current = $current->parentNode;
        } while ($current instanceof DOMElement);
        if (func_num_args() > 1) {
            return $this->template->get($name, $default);
        }
        return $this->template->get($name);
    }
}

class XIRE_MissingAttributeException extends XIRE_ProcessingNodeException
{
    private $name;

    public function __construct($name, DOMNode $node) {
        $this->name = $name;
        parent::__construct(
          "{$node->localName} is missing required attribute: $name", $node);
    }

    /**
     * @return the name of the missing required attribute
     */
    public function getName () {
        return $this->name;
    }
}

class XIRE_MissingPluginException extends XIRE_ProcessingNodeException
{
    private $template;

    public function __construct($message = null, DOMNode $node, $code = 0) {
        func_num_args() === 0 and $message = "Missing plugin: {$node->localName}";
        parent::__construct($message, $node, $code);
    }

    /**
     * @return the template that uses the missing plugin
     */
    public function getTemplate () {
        return $this->template;
    }
}

/**
 * Recomended superclass of exceptions originating from a plugin
 */
class XIRE_PluginException extends XIRE_ProcessingNodeException {}
?>