Page 1 of 1

My Composite Controller

Posted: Tue Oct 30, 2007 10:42 am
by blueyon
I have created a controller that implements the composite pattern and does pre actions.

I have documented most of it except the action controller.

The problem is it seems to mix up the controller / view pattern. I'm trying to keep things spearate.

These are the 3 classes I have come up with:


Base Controller:

Code: Select all

<?php
/**
 *
 * Controller
 *
 * The base controller used for forwarding to other controllers and accessing the registry.
 *
 * @subpackage	Library 
 * @category	Controller
 * @author		Daniel Kerr
 * @license     http://www.opensource.org/licenses/mit-license.php The MIT License
 * @since 		0.8 
 *
 */
class Controller {	

	/**
     * 
     * The registry object.
     * 
     * @var object
     * 
     */	
	var $registry;

	/**
     * 
     * Sets the registry as a class attribute.
     * 
     * @param object $registry The registry object.
	 *
	 * @return void
     * 
     */		
	function __construct(&$registry) {
		$this->registry =& $registry; 
	}

	/**
     * 
     * Callback method for setting a attribute.
     * 
     * @param string $key The registry key.
	 * @param mixed $value The registry value.
	 *
	 * @return void
     * 
     */			
	function __set($key, $value) {
		$this->registry->set($key, $value);
	}
	
	/**
     * 
     * Callback method for getting a attribute.
     * 
     * @param string $key The registry key.
	 *
	 * @return object Returns object from the registry.
     * 
     */		
	function __get($key) {
		return $this->registry->get($key);
	}

	/**
     * 
     * The magic method __call() allows to capture invocation of non existing methods. 
     * 
     * @param string $method Method to call.
	 * @param array $args Arguments used when calling the method.
	 *
	 * @return mixed The value returned from the __call() method will be returned to the caller of the method. 
     * 
     */			
	function __call($method, $args) {
		switch ($method) {
			case 'create':
				return call_user_func_array(array(&$this->registry, 'create'), $args);
				break;
			case 'load':
				call_user_func_array(array(&$this->registry, 'load'), $args);
				break;
			default;
				exit('Error: could not!');
				break;
		}
		
	}

	/**
     * 
     * Creates an action and returns it in an array.
     * 
     * @param string $class The registry object.
	 * @param string $method The registry object.
	 *
	 * @return array Returns the action array ready to be executed.
     * 
     */				
	function forward($class, $method) {
		$action = array(
			'class'  => $class,
			'method' => $method
		);
		
		return $action;
  	}
}
?>

Front Controller:

Code: Select all

<?php
/**
 *
 * Front Controller
 *
 * Loads the page controller and executes the request.
 *
 * @subpackage	Library 
 * @category	Controller
 * @author		Daniel Kerr
 * @license     http://www.opensource.org/licenses/mit-license.php The MIT License
 * @since 		0.8 
 *
 */
class Front extends Controller {
    
	/**
     * 
     * The controller directory.
     * 
     * @var string
     * 
     */	
	var $directory;

    /**
     * 
     * The default controller action.
     * 
     * @var array
     * 
     */	
	var $default;

    /**
     * 
     * The error controller action.
     * 
     * @var array
     * 
     */	
	var $error;

    /**
     * 
     * The pre controller action.
     * 
     * @var array
     * 
     */		
	var $pre_action = array();

	/**
     * 
     * Sets the controller directory.
     * 
     * @param string $directory The directory path.
     * 
     */	
	function setDirectory($directory) {
		$this->directory = $directory;
	}

	/**
     * 
     * Sets the controller default action.
     * 
     * @param string $class The class to call.
	 * @param string $method The method to dispatch.
	 *
	 * @return void
     * 
     */	
	function setDefault($class, $method) {
		$this->default = $this->forward($class, $method);
	}

	/**
     * 
     * Sets the controller error action.
     * 
     * @param string $class The class to call.
	 * @param string $method The method to dispatch.
	 *
	 * @return void
     * 
     */	
	function setError($class, $method) {
		$this->error = $this->forward($class, $method);
	}

	/**
     * 
     * Sets the controller error controller action.
     * 
     * @param string $class The class to call.
	 * @param string $method The method to dispatch.
	 *
	 * @return void
     * 
     */		
	function addPreAction($class, $method) {
		$this->pre_action[] = $this->forward($class, $method);
	}

	/**
     * 
     * Dispatches the pre actions and page controller class.
     * 
     * @param object $request The request object.
	 *
     * @return void
     * 
     */	
  	function dispatch(&$request) {
		$action = $this->requestHandler($request);
		
		while ($action) {
			foreach ($this->pre_action as $pre_action) {
				$result = $this->execute($pre_action);
						
				if ($result) {
					$action = $result;
						 
					break;
				}
			}
			
			$action = $this->execute($action);
		}
  	}
    
	/**
     * 
     * Executes a controller class.
     * 
     * @param array $action The action to be executed.
	 *
     * @return array $action Returns another action so the controller can be forwarded. If there is no foward action NULL is returned.
     * 
     */	
	function execute($action) {
		$file = $this->directory . basename($action['class']) . '.php';
		
		if (file_exists($file)) {
			include_once($file);
			
			 $controller = 'Controller' . preg_replace('/[^a-zZ-Z0-9]/', NULL, $action['class']);
			
			 $class = new $controller($this->registry);

			if (method_exists($class, $action['method'])) {
				$action = $class->{$action['method']}($this->registry);
			} else {
				$action = $this->error;
				
				$this->error = NULL;
			}
		} else {
			$action = $this->error;
			
			$this->error = NULL;
		}
		
		return $action;
	}

	/**
     * 
     * Handles the request and creates an action ready for dispatch.
     * 
     * @param object $request The request object to is used to build the action to be executed.
	 *
     * @return array $action Returns an action so the controller can be forwarded.
     * 
     */		
	function requestHandler(&$request) {
	    if ($request->has('controller')) {
			$class = $request->get('controller');
			
			if ($request->has('action')) {
				$method = $request->get('action');
			} else {
				$method = 'index';
			}

			return $this->forward($class, $method);
	    } else {
	        return $this->default;
	    }
	}		
}
?>

Action Controller

Code: Select all

<?php
/**
 *
 * Action Controller
 *
 * Action executes all the logic for the current request.
 *
 * @subpackage	Library 
 * @category	Controller
 * @author		Daniel Kerr
 * @license     http://www.opensource.org/licenses/mit-license.php The MIT License
 * @since 		0.8
 *
 */
class Action extends Controller {
	var $id;
	var $data     = array();
    var $children = array();
	
	function setId($value) {
		$this->id = $value;
	}
	
	function getId() {
		return $this->id;
	}

	function set($key, $value) {
		return $this->data[$key] = $value;
	}
	
	function get($key) {
		return (isset($this->data[$key]) ? $this->data[$key] : NULL);
	}
	
	function render($filename) {
		$this->traverse($this);
		
		$this->response->set($this->fetch($filename));
	}
		
	function fetch($filename) {
    	$file = DIR_VIEW . $filename;
    
		if (file_exists($file)) {
      		extract($this->data);

      		ob_start();
      
	  		include($file);
      
	  		$content = ob_get_contents();

      		ob_end_clean();

      		return $content;
    	} else {
      		exit('Error: View ' . $file . ' not found!');
    	}
	}
		
	function attach(&$child) {
		$this->children[$child->getId()] =& $child;
	}

	function getChildren() {
		return $this->children;
	}
	
	function traverse(&$controller) {
		$children = $controller->getChildren();
		
		foreach ($children as $child) {
			$this->traverse($child);
			
			ob_start();
			
			$child->execute();
			
			$controller->set($child->getId(), ob_get_clean());
		}	
	}		
}
?>