Created
October 31, 2011 13:53
-
-
Save ashleydw/1327542 to your computer and use it in GitHub Desktop.
Cascading module directory file structure for Zend Framework
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Cascading module directory file structure | |
* | |
* @version 1 | |
* @author Ashley White, www.needathinkle.com | |
* @license @license http://creativecommons.org/licenses/by-sa/3.0/ | |
*/ | |
final class Thinkle_Controller_Dispatcher_Cascading extends Zend_Controller_Dispatcher_Standard { | |
/** | |
* Class name prefixes | |
* @see addControllerDirectory | |
* @see formatClassName | |
* @var array | |
*/ | |
protected $_prefixes = array(); | |
/** | |
* Add multiple directories of controllers for modules. This should really be extended with other functions for unshift_ etc | |
* | |
* @param string $path | |
* @param string $module | |
* @param string $prefix The prefix for the non default classes | |
* @return Thinkle_Controller_Dispatcher_Cascading | |
*/ | |
public function addControllerDirectory($path, $module = null, $prefix = null) { | |
if (null === $module) { | |
$module = $this->_defaultModule; | |
} | |
$module = (string) $module; | |
$path = rtrim((string) $path, '/\\'); | |
if(!array_key_exists($module, $this->_controllerDirectory)) { | |
$this->_controllerDirectory[$module] = array(); | |
} | |
if(!in_array($path, $this->_controllerDirectory[$module])) { | |
$this->_controllerDirectory[$module][] = $path; | |
if($prefix) { | |
$this->_prefixes[$path] = $prefix; | |
} | |
} | |
return $this; | |
} | |
/** | |
* Gets the controller class as the Standard dispatcher does, but checks the module controller directories for the file | |
* | |
* @param Zend_Controller_Request_Abstract $request | |
* @return type | |
*/ | |
public function getControllerClass(Zend_Controller_Request_Abstract $request) { | |
$className = parent::getControllerClass($request); | |
$module = $request->getModuleName(); | |
$fileSpec = $this->classToFilename($className); | |
foreach($this->getControllerDirectory($module) as $directory) { | |
$test = $directory . DIRECTORY_SEPARATOR . $fileSpec; | |
if(Zend_Loader::isReadable($test)) { | |
$this->_curDirectory = $directory; | |
break; | |
} | |
} | |
return $className; | |
} | |
/** | |
* Same as parent, but we loop the dispatchDirectory(ies) testing each | |
* | |
* @param Zend_Controller_Request_Abstract $request | |
* @return type | |
*/ | |
public function isDispatchable(Zend_Controller_Request_Abstract $request) | |
{ | |
$className = $this->getControllerClass($request); | |
if (!$className) { | |
return false; | |
} | |
$finalClass = $className; | |
if (($this->_defaultModule != $this->_curModule) | |
|| $this->getParam('prefixDefaultModule')) | |
{ | |
$finalClass = $this->formatClassName($this->_curModule, $className); | |
} | |
if (class_exists($finalClass, false)) { | |
return true; | |
} | |
$fileSpec = $this->classToFilename($className); | |
$dispatchDir = $this->getDispatchDirectory(); | |
if(!is_array($dispatchDir)) | |
$dispatchDir = array($dispatchDir); | |
foreach($dispatchDir as $directory) { | |
$test = $directory . DIRECTORY_SEPARATOR . $fileSpec; | |
if(Zend_Loader::isReadable($test)) { | |
return true; | |
} | |
} | |
return false; | |
} | |
/** | |
* Format action class name with prefix | |
* | |
* @param string $moduleName Name of the current module | |
* @param string $className Name of the action class | |
* @return string Formatted class name | |
*/ | |
public function formatClassNameWithPrefix($moduleName, $className) { | |
if(array_key_exists($this->getDispatchDirectory(), $this->_prefixes)) | |
return $this->_prefixes[$this->getDispatchDirectory()].'_'.$this->formatModuleName($moduleName) . '_' . $className; | |
return $this->formatModuleName($moduleName) . '_' . $className; | |
} | |
/** | |
* Same as the Standard function, but we check for prefixes. | |
* Only difference is: formatClassNameWithPrefix() not formatClassName(); | |
* | |
* @param string $className | |
* @return string Class name loaded | |
* @throws Zend_Controller_Dispatcher_Exception if class not loaded | |
*/ | |
public function loadClass($className) | |
{ | |
$finalClass = $className; | |
if (($this->_defaultModule != $this->_curModule) | |
|| $this->getParam('prefixDefaultModule')) | |
{ | |
$finalClass = $this->formatClassNameWithPrefix($this->_curModule, $className); | |
} | |
if (class_exists($finalClass, false)) { | |
return $finalClass; | |
} | |
$dispatchDir = $this->getDispatchDirectory(); | |
$loadFile = $dispatchDir . DIRECTORY_SEPARATOR . $this->classToFilename($className); | |
if (Zend_Loader::isReadable($loadFile)) { | |
include_once $loadFile; | |
} else { | |
require_once 'Zend/Controller/Dispatcher/Exception.php'; | |
throw new Zend_Controller_Dispatcher_Exception('Cannot load controller class "' . $className . '" from file "' . $loadFile . "'"); | |
} | |
if (!class_exists($finalClass, false)) { | |
require_once 'Zend/Controller/Dispatcher/Exception.php'; | |
throw new Zend_Controller_Dispatcher_Exception('Invalid controller class ("' . $finalClass . '")'); | |
} | |
return $finalClass; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* To go with the cascading file directory structure disaptcher | |
* | |
* @version 1 | |
* @author Ashley White, www.needathinkle.com | |
* @license @license http://creativecommons.org/licenses/by-sa/3.0/ | |
*/ | |
class Thinkle_Application_Resource_Modules extends Zend_Application_Resource_Modules { | |
public function init() | |
{ | |
$bootstraps = array(); | |
$bootstrap = $this->getBootstrap(); | |
$bootstrap->bootstrap('FrontController'); | |
$front = $bootstrap->getResource('FrontController'); | |
$modules = $front->getControllerDirectory(); | |
$default = $front->getDefaultModule(); | |
$curBootstrapClass = get_class($bootstrap); | |
foreach ($modules as $module => $moduleDirectory) { | |
//Thinkle: | |
//Difference to standard resource loader, here we loop the directories | |
$bootstrapClass = $this->_formatModuleName($module) . '_Bootstrap'; | |
foreach($moduleDirectory as $controllerDirectory) { | |
if (!class_exists($bootstrapClass, false)) { | |
$bootstrapPath = dirname($controllerDirectory) . '/Bootstrap.php'; | |
if (file_exists($bootstrapPath)) { | |
$eMsgTpl = 'Bootstrap file found for module "%s" but bootstrap class "%s" not found'; | |
include_once $bootstrapPath; | |
if (($default != $module) | |
&& !class_exists($bootstrapClass, false) | |
) { | |
throw new Zend_Application_Resource_Exception(sprintf( | |
$eMsgTpl, $module, $bootstrapClass | |
)); | |
} elseif ($default == $module) { | |
if (!class_exists($bootstrapClass, false)) { | |
$bootstrapClass = 'Bootstrap'; | |
if (!class_exists($bootstrapClass, false)) { | |
throw new Zend_Application_Resource_Exception(sprintf( | |
$eMsgTpl, $module, $bootstrapClass | |
)); | |
} | |
} | |
} | |
} else { | |
continue; | |
} | |
} | |
//Thinkle: | |
//Move inside of the foreach to avoid looking for bootstraps that don't exist | |
if ($bootstrapClass == $curBootstrapClass) { | |
// If the found bootstrap class matches the one calling this | |
// resource, don't re-execute. | |
continue; | |
} | |
$bootstraps[$module] = $bootstrapClass; | |
} | |
} | |
return $this->_bootstraps = $this->bootstrapBootstraps($bootstraps); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* To go with the cascading file directory structure disaptcher | |
* | |
* @version 1 | |
* @author Ashley White, www.needathinkle.com | |
* @license @license http://creativecommons.org/licenses/by-sa/3.0/ | |
*/ | |
class Thinkle_Controller_Action_Helper_ViewRenderer extends Zend_Controller_Action_Helper_ViewRenderer { | |
/** | |
* For the cascading file structure, we check the module directories | |
* | |
* @return type | |
*/ | |
public function getModuleDirectory() | |
{ | |
$module = $this->getModule(); | |
$moduleDir = $this->getFrontController()->getControllerDirectory($module); | |
if(is_array($moduleDir)) { | |
foreach($moduleDir as $directory) { | |
if(is_dir($directory)) { | |
$moduleDir = $directory; | |
break; | |
} | |
} | |
} | |
if ((null === $moduleDir)) { | |
/** | |
* @see Zend_Controller_Action_Exception | |
*/ | |
require_once 'Zend/Controller/Action/Exception.php'; | |
throw new Zend_Controller_Action_Exception('ViewRenderer cannot locate module directory for module "' . $module . '"'); | |
} | |
$this->_moduleDir = dirname($moduleDir); | |
return $this->_moduleDir; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment