Location: PHPKode > projects > Mocovie web framework > mocovi/library/autoload/ControlFactory.php
<?php
/**
 *  Copyright (C) 2010  Kai Dorschner
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @author Kai Dorschner <the-hide@address.com>
 * @copyright Copyright 2010, Kai Dorschner
 * @license http://www.gnu.org/licenses/gpl.html GPLv3
 * @package mocovi
 */

/**
 * Require MVC Exception
 */
class_exists('MvcException') or require $GLOBALS['library'].'autoload/MvcException.php';

/**
 * Control-factory class.
 *
 * Responsible for the control creation.
 *
 * @package mocovi
 */
class ControlFactory
{
	/**
	 * Class name of the error control.
	 *
	 * @access public
	 * @static
	 */
	public static $errorcontrol	= 'error_control';
	public static $controlannex	= '_control';
	public static $extension	= '.php';

	protected static $controlPool		= array();
	protected static $controlPoolCache	= array();

	/**
	 * Registry for controls.
	 * You are able to map all XML Nodes ($control[$x]['node']) to the controls ($control[$x]['control'])
	 *
	 * @access public
	 * @static
	 * @var Array;
	 */
	public static $registry = array();

	protected function __construct()
	{
		throw new Exception(get_class($this).' cannot be instantiated. It\'s a static class.');
	}

	/**
	 * Instantiates a specific control and fills it with its options.
	 *
	 * At first all properties and variables are checked for their correctness
	 * and throw an exception on fault.
	 * Then the source class gets included and instantiated.
	 *
	 * @return object The instatiated control
	 * @param DomElement $sourceNode Contains the original model-node
	 * @throws MvcException
	 * @access public
	 * @static
	 */
	public static function create(DomNode $sourceNode)
	{
		if($position = self::findControlInRegistry($sourceNode))
			return self::$registry[$position]['control'];
		switch($sourceNode->nodeType)
		{
			case XML_ELEMENT_NODE:
				$name = $sourceNode->nodeName;
			break;
			case XML_TEXT_NODE:
				$name = 'inline';
			break;
			default:
				return self::createError(get_class(self), 'Cannot create Control from '.$sourceNode->nodeName);
			break;
		}
		if(count(self::$controlPool) == 0)
			throw new MvcException('Control pool is empty!');
		// @todo
		
		if($controlfile = self::findControl($name))
		{
			class_exists($name.self::$controlannex) or require $controlfile;
			$class = $name.self::$controlannex;
			if(!class_exists($class))
				throw new MvcException('Cannot find class "'.$class.'" in file "'.$controlfile.'". The class name must be the filename without extension but with appended "'.self::$controlannex.'". Example: foobar'.self::$controlannex.' in foobar'.self::$extension);
			self::register($sourceNode, $control = new $class($sourceNode));
			return $control;
		}
		return self::createError($name, 'Control "'.$name.'" not found in pools.');
	}

	/**
	 * Creates a control out of the normal context.
	 *
	 * It has no relation to the original DomDocument where all other controls
	 * are linked in.
	 *
	 * @access public
	 * @static
	 * @return Control
	 * @param String $name Control name
	 * @param Array $attributes List of control attributes (associative array)
	 */
	public static function createVirtual($name, Array $attributes = array())
	{
		$dom = new DomDocument();
		$node = $dom->createElement($name);
		foreach($attributes as $k => $v)
			$node->setAttribute($k, $v);
		return self::create($node);
	}

	public static function register(DomNode $node, Control $control)
	{
		self::$registry[] = array
			( 'node'	=> $node
			, 'control'	=> $control
			);
	}

	public static function getControl(DomNode $node)
	{
		$position = self::findControlInRegistry($node);
		return ($position ? self::$registry[$position]['control'] : self::create($node));
	}

	public static function findControlInRegistry(DomNode $node)
	{
		for($i = 0; $i < count(self::$registry); $i++)
			if(self::$registry[$i]['node'] === $node) // Same instance
				return $i;
		return null;
	}

	public static function getAllControls()
	{
		if(count(self::$controlPoolCache) > 0)
			return self::$controlPoolCache;
		foreach(self::$controlPool as $pool)
			if(is_dir($pool))
				foreach($pool as $element)
					if(!$element->isDot() && $element->isFile())
					{
						$name = preg_replace('/\\'.self::$extension.'$/', '', $element->getFilename());
						if(!array_key_exists($name, self::$controlPoolCache))
							self::$controlPoolCache[$name] = $element->getPathname();
					}
		return self::$controlPoolCache;
	}

	/**
	 * this method is normally called when something went wrong.
	 *
	 * @param String $context Context.
	 * @param String $message Error message.
	 * @return Control Error control.
	 * @static
	 */
	public static function createError($context, $message)
	{
		class_exists(self::$errorcontrol) or require $GLOBALS['commonControls']
				.substr
				( self::$errorcontrol
				, 0
				, strlen(self::$errorcontrol) - strlen(self::$controlannex)
				)
				.self::$extension
				;
		return self::createVirtual
			( 'error'
			, array
				( 'context' => $context
				, 'message' => $message
				)
			);
	}

	public static function addPool(DirectoryIterator $pool)
	{
		self::$controlPool[] = $pool;
	}

	public static function findControl($name)
	{
		if(isset(self::$controlPoolCache[$name]))
			return self::$controlPoolCache[$name]; // Return already used control from cache.
		for($i = (count(self::$controlPool) - 1); $i >= 0; $i--) // Search backwards (last added pool is checked first!)
		{
			foreach(self::$controlPool[$i] as $element)
				if(!$element->isDot() && $element->getFilename() == $name.self::$extension)
				{
					self::$controlPoolCache[$name] = $element->getPathname(); // Once it is found in one pool it is cached.
					return $element->getPathname();
				}
		}
		throw new Exception('Control with name "'.$name.'" could not be found in pools.');
	}

	public static function load($controlName)
	{
		class_exists($controlName.self::$controlannex) or require ControlFactory::findControl($controlName);
	}
}
Return current item: Mocovie web framework