Reputation: 83173
I am currently figuring out a way to the the above.
My current application structure is as follows:
/modules
/ modulename
/controllers
/ProjectController.php
The application has 3 different user roles, each with functionality contained within these modules. I'd like to prevent having multiple actions for each user role in one controller as I think it makes my code less readable and ugly. So, I was thinking about a structure like this:
/modules
/ modulename
/controllers
/ProjectController.php
/EmployeeProjectController.php
/ExecutiveProjectController.php
This should work as follows:
Of course, I could relatively easy a different URL scheme to provide for this for each user role, but I do not want this. I want a uniform URL scheme.
Next step would then be to create routes for each of the controllers to rewrite them to another controller. I'd like to prevent this as well.
I want a way to globally tell the router to prefix controllers with 'Executive' or 'Employee' or whatever, based on the user role.
What would be the best way to this?
Upvotes: 0
Views: 164
Reputation: 83173
I have spent quite some time figuring out how to use Zend_Controller_Router_Route to do this and have come up with as solution that works:
class App_Controller_Router_Route_Rolebasedcontroller extends Zend_Controller_Router_Route_Module
{
/**
* Roles that should be rewritten automatically
*
* @var array
*/
protected $_rewriteRoles = array('employee', 'executive');
/**
* Matches a user submitted path. Assigns and returns an array of variables
* on a successful match.
*
* If a request object is registered, it uses its setModuleName(),
* setControllerName(), and setActionName() accessors to set those values.
* Always returns the values as an array.
*
* @param string $path Path used to match against this routing map
* @return array An array of assigned values or a false on a mismatch
*/
public function match($path, $partial = false)
{
$result = parent::match($path, $partial);
$role = Plano_Acl::getInstance()->getCurrentRole();
if (null !== $role && in_array($role, $this->_rewriteRoles))
{
if (isset($result[$this->_controllerKey]))
{
$result[$this->_controllerKey] = $role . ucfirst($result[$this->_controllerKey]);
}
}
return $result;
}
/**
* Assembles user submitted parameters forming a URL path defined by this route
* Removes fole prefixes when required
*
* @param array $data An array of variable and value pairs used as parameters
* @param bool $reset Weither to reset the current params
* @return string Route path with user submitted parameters
*/
public function assemble($data = array(), $reset = false, $encode = true, $partial = false)
{
if (!$this->_keysSet) {
$this->_setRequestKeys();
}
$params = (!$reset) ? $this->_values : array();
foreach ($data as $key => $value) {
if ($value !== null) {
$params[$key] = $value;
} elseif (isset($params[$key])) {
unset($params[$key]);
}
}
$params += $this->_defaults;
$url = '';
if ($this->_moduleValid || array_key_exists($this->_moduleKey, $data)) {
if ($params[$this->_moduleKey] != $this->_defaults[$this->_moduleKey]) {
$module = $params[$this->_moduleKey];
}
}
unset($params[$this->_moduleKey]);
$controller = $params[$this->_controllerKey];
// remove role prefix from url when required
$role = Plano_Acl::getInstance()->getCurrentRole();
if (null !== $role && in_array($role, $this->_rewriteRoles))
{
if (substr($params[$this->_controllerKey], 0, strlen($role)) == $role)
{
$controller = lcfirst(substr($params[$this->_controllerKey], strlen($role)));
}
}
unset($params[$this->_controllerKey]);
$action = $params[$this->_actionKey];
unset($params[$this->_actionKey]);
foreach ($params as $key => $value) {
$key = ($encode) ? urlencode($key) : $key;
if (is_array($value)) {
foreach ($value as $arrayValue) {
$arrayValue = ($encode) ? urlencode($arrayValue) : $arrayValue;
$url .= '/' . $key;
$url .= '/' . $arrayValue;
}
} else {
if ($encode) $value = urlencode($value);
$url .= '/' . $key;
$url .= '/' . $value;
}
}
if (!empty($url) || $action !== $this->_defaults[$this->_actionKey]) {
if ($encode) $action = urlencode($action);
$url = '/' . $action . $url;
}
if (!empty($url) || $controller !== $this->_defaults[$this->_controllerKey]) {
if ($encode) $controller = urlencode($controller);
$url = '/' . $controller . $url;
}
if (isset($module)) {
if ($encode) $module = urlencode($module);
$url = '/' . $module . $url;
}
return ltrim($url, self::URI_DELIMITER);
}
}
Upvotes: 1
Reputation: 14184
Sounds like you could use a front controller plugin with a routeStartup()
method that examines the Zend_Auth
instance and adds the role-specific routes (from INI or XML file, for example).
Something like this:
class My_Controller_Plugin_RouteByAuth extends Zend_Controller_Plugin_Abstract
{
public function routeStartup()
{
$auth = Zend_Auth::getInstance();
if (!$auth->hasIdentity()){
return;
}
$identity = $auth->getIdentity();
if ($identity->isAdmin()){
$this->_addRoutes('routes_admin.ini');
} else if ($identity->isEmployee()){
$this->_addRoutes('routes_employee.ini');
} else if ($identity->isExecutive()){
$this->_addRoutes('routes_executive.ini');
} else {
return;
}
}
protected function _addRoutes($file)
{
$front = Zend_Controller_Front::getInstance();
$router = $front->getRouter();
$routes = new Zend_Config_Ini(APPLICATION_PATH . '/configs/ ' . $file);
$router->addConfig($routes);
}
}
Not tested, but I hope this conveys a core of a workable idea.
Upvotes: 1