I like how Kohana 3 organizes the classes, and I thought the same thing may be applied to my Zend Framework experimental project. Basically what this means is that I can name the controller class according to PEAR naming convention, and deduce the location of the file by just parsing the class name.
Suppose the file structure of my experimental project as follows
-
private_files
- Model
- View
-
Controller
- Index.php
- Libraries
- public_html
I am expecting if I need to load a controller named Controller_Index, then it should be able to find the controller class file in private_files/Controller/Index.php. To do so, as hinted by Tim Lytie at stackoverflow, I wrote a dispatcher class that subclassed from Zend_Dispatcher_Standard as follows
class Coolsilon_Controller_Dispatcher
extends Zend_Controller_Dispatcher_Standard {
public function __construct() {
parent::__construct();
}
public function formatControllerName($unformatted) {
return sprintf(
'Controller_%s', ucfirst($this->_formatName($unformatted))
);
}
public function formatActionName($unformatted) {
$formatted = $this->_formatName($unformatted, true);
return strtolower(substr($formatted, 0, 1)) . substr($formatted, 1);
}
}
Then, in order to make the parameters passed in as method parameters, after reading through the code as posted here, I refactored it to (I <3 short methods).
abstract class Coolsilon_Controller_Base
extends Zend_Controller_Action {
public function dispatch($actionName) {
$parameters = array();
foreach($this->_parametersMeta($actionName) as $paramMeta) {
$parameters = array_merge(
$parameters,
$this->_parameter($paramMeta, $this->_getAllParams())
);
}
call_user_func_array(array(&$this, $actionName), $parameters);
}
private function _actionReference($className, $actionName) {
return new ReflectionMethod(
$className, $actionName
);
}
private function _classReference() {
return new ReflectionObject($this);
}
private function _constructParameter($paramMeta, $parameters) {
return array_key_exists($paramMeta->getName(), $parameters) ?
array($paramMeta->getName() => $parameters[$paramMeta->getName()]) :
array($paramMeta->getName() => $paramMeta->getDefaultValue());
}
private function _parameter($paramMeta, $parameters) {
return $this->_parameterIsValid($paramMeta, $parameters) ?
$this->_constructParameter($paramMeta, $parameters) :
$this->_throwParameterNotFoundException($paramMeta, $parameters);
}
private function _parameterIsValid($paramMeta, $parameters) {
return $paramMeta->isOptional() === FALSE
&& empty($parameters[$paramMeta->getName()]) === FALSE;
}
private function _parametersMeta($actionName) {
return $this->_actionReference(
$this->_classReference()->getName(),
$actionName
)
->getParameters();
}
private function _throwParameterNotFoundException($paramMeta, $parameters) {
throw new Exception("Parameter: {$paramMeta->getName()} Cannot be empty");
}
}
It may affect the performance but the code is much easier to read as I am the only one who is wokring on the project.