Page 1 of 1

Front Controller & Command Execution

Posted: Wed Aug 09, 2006 4:29 pm
by Luke
I just whipped this up... please rip it to shreds. Let me know Every little nit-picky thing that is wrong with it.

EDIT: oh yea... almost forgot to say what it is... if it's not blatently obvious, it's a front controller and command resolver

I'm hoping that maybe with the community's help, I can perfect this and replace my current (more or less procedural) page controllers

Code: Select all

<?php
require_once 'C:\wamp\www\core\classes\Request.inc.php';

// COMMANDS

		class Front_Command{
			protected $action;
			public function execute(){
				echo "Error: Could not find specified command";
			}
			public function doExecute( Front_Command $command ){
				$command->execute();
			}
		}
		
		class Front_Command_default extends Front_Command{
			public function __construct(){
				$this->action = "Default";
			}
			public function execute(){
				echo $this->action . " was executed.";
			}
		}
		
		class Front_Command_login extends Front_Command{
			public function __construct(){
				$this->action = "Login";
			}
			public function execute(){
				echo $this->action . " was executed.";
			}
		}

// ENDCOMMANDS

// Request is just a class that gets request info (from url, forms, command line, etc.)
// Front request is specialized in that it returns information specific to the front controller
class Front_Request extends Request{
	protected $default;
	protected $error;
	public function __construct($default, $error){
		parent::__construct();
		$this->default = $default;
		$this->error   = $error;
	}
	public function getCommand(){
		return $this->action ? $this->action : $this->default;
	}
	public function getCommandDefault(){
		return $this->default;
	}
	public function getCommandError(){
		return $this->error;
	}
}

class Front_Command_Resolver{
	public function getCommandComponent( Front_Request $request ){
		// Get command from request object
		$command = $request->getCommand();
		
		// Assign class name with command appended
		$class_name = "Front_Command_{$command}";
		
		// If this specific class exists, return it
		if(class_exists($class_name)){
			return new $class_name();
		}
		
		// Otherwise return the standard command
		return new Front_Command();
	}
}

class Front_Controller{
	private static $instance = null;
	private function __construct(){
		// Some sort of initialization
	}
	
	public function getInstance(){
		// This shouldn't need an explanation, but I'll explain anyway... it ensures that only one instance of this can be instantiated
		if( ! self::$instance ) {
			self::$instance = new Front_Controller();
		}
		return self::$instance;
	}
	
	public function run(){
		// Get request from user (could be by url/command line... not up to this class to decide... left up to the front request object)
		$request = new Front_Request('default', 'error');
		
		// Get an instance of the command resolver
		$command_resolver = new Front_Command_Resolver();
		// Resolve the user's command into a command component (a descendant of our friend ^^ the Front_Command
		$command = $command_resolver->getCommandComponent( $request );
		
		// Execute the command
		$command->execute();
	}
}
$Controller = Front_Controller::getInstance();
$Controller->run();
?>

Posted: Wed Aug 09, 2006 5:20 pm
by Christopher
You are on your way. One note is that those Commands that are dispatched by your Front Controller are called "Actions" by most people. It is a convention that goes back to Struts and beyond. They are often named something like "LoginController" or "LoginAction".

Posted: Wed Aug 09, 2006 5:41 pm
by Luke
:D I think I'm finally starting to think OOP :D

Posted: Wed Aug 09, 2006 11:47 pm
by Luke
So how can I modify this to send the action to the model/view?

ModelResolver & ViewResolver? That may work. I'll work on it.

Posted: Thu Aug 10, 2006 12:55 am
by Christopher
The Ninja Space Goat wrote:So how can I modify this to send the action to the model/view?
You don't "send the action to the model/view", the Action is the Controller. It can create both the Model and the View -- passing the Model to the View, or the View can create the Model itself. But the Action takes over flow control once it is dispatched by the Front Controller.

Posted: Thu Aug 10, 2006 1:02 am
by Luke
good point... thanks. alright... I've modified it some more... what would be a better name for the action's execute method?
Action:

Code: Select all

<?php
abstract class Controller_Front_Action{
	protected $action;
	//protected $view; <-- this is just something I'm thinking about right now... see any problem with this methodology?
	//protected $model; <-- Same with this
	abstract public function execute();
}
?>
Action Resolver

Code: Select all

<?php
class Controller_Front_ActionResolver{
	protected $action;
	protected $path;
	protected $ext;
	public function __construct( Controller_Front_Request $request ){
		// Get action from request object
		$this->action = $request->getAction();
	}
	// Need to add autoloading functionality
	public function getComponent( $prefix='', $suffix='Action', $ext='.php' ){
		$path_name = $prefix . $this->action . $ext;

		if(file_exists($path_name)){
			require_once $path_name;
			$class_name = $this->action . $suffix;
			
			// If this specific class exists, return it
			if(class_exists($class_name, false)){
				return new $class_name();
			}
		}
		
		// Otherwise return the error action
		return new Front_Action_Error();
		
	}
}
?>
Front Controller

Code: Select all

<?php
class Controller_Front_Front{
	private static $instance = null;
	public function getInstance(){
		// This shouldn't need an explanation, but I'll explain anyway... it ensures that only one instance of this can be instantiated
		if( ! self::$instance ) {
			self::$instance = new Controller_Front_Front();
		}
		return self::$instance;
	}
	
	public function run($path){
		// Get request from user (could be by url/command line... not up to this class to decide... left up to the front request object)
		$request = new Controller_Front_Request('login');
		
		// Get an instance of the command resolver
		$action_resolver = new Controller_Front_ActionResolver( $request );
		// Resolve the users action into a command component (a descendant of our friend ^^ the Front_Action
		$action = $action_resolver->getComponent( $path );
		
		// Execute the action
		$action->execute();
	}
}
?>
Front Request

Code: Select all

<?php
// Request is just a class that gets request info (from url, forms, command line, etc.)
// Front request is specialized in that it returns information specific to the front controller
class Controller_Front_Request extends Request{
	protected $default;
	public function __construct($default){
		parent::__construct();
		$this->default = $default;
	}
	public function getAction(){
		return $this->action ? $this->action : $this->default;
	}
	public function getActionDefault(){
		return $this->default;
	}
}
?>