Perforce Chronicle 2012.2/486814
API Documentation
|
Overrides the Zend module router to support shorter and cleaner urls. More...
Public Member Functions | |
assemble ($data=array(), $reset=false, $encode=true, $partial=false) | |
Override parent implementation to produce shorter paths. | |
isValidAction ($action, $controller, $module) | |
Determine if the given action/module/controller represent a valid action in the system. | |
isValidController ($controller, $module) | |
Determine if the given controller exists in the given module. | |
isValidModule ($module) | |
Determine if the given module is valid. | |
match ($path, $partial=false) | |
Matches a user submitted path. | |
Static Public Member Functions | |
static | formatRouteParam ($param) |
Get the route formatted (lower-case, dash-separated) version of a CamelCase identifier. | |
Protected Member Functions | |
_isActionParamRequired ($params, $action, $pathParam) | |
Determine if the action parameter is required to assemble the path. | |
_isControllerParamRequired ($params, $controller, $action) | |
Determine if the controller parameter is required to assemble the path. | |
_isDispatchable ($params) | |
Determine if given route parameters are dispatchable. |
Overrides the Zend module router to support shorter and cleaner urls.
With Zend's default router, the default ('index') controller must always be specified when an action is specified. This derivative allows the 'index' controller to be left out when specifying an action, provided that the action itself does not resolve to a controller. This derivative also allows the 'index' action to be left out, provided that any following parameters do not resolve to an action.
For example: '/default/foo' is equivalent to '/default/index/index/foo' provided that there is no 'foo' controller in the default module, or 'foo' action in the default module.
P4Cms_Controller_Router_Route_Module::_isActionParamRequired | ( | $ | params, |
$ | action, | ||
$ | pathParam | ||
) | [protected] |
Determine if the action parameter is required to assemble the path.
Not required if action parameter is the default action and there are no more parameters or the following parameter cannot be confused with a controller.
array | $params | the route parameters to test against. |
string | $action | the action to consider |
string | $pathParam | the current path (or path fragment) |
{ // required if not default. if ($params[$this->_actionKey] !== $this->_defaults[$this->_actionKey]) { return true; } // not required if no following parameters if (!isset($pathParam)) { return false; } // required if action name matches a controller name. // we test this by setting the controller parameter to // the given action and seeing if it is dispatchable. $params[$this->_actionKey] = $pathParam; if ($this->_isDispatchable($params)) { return true; } return false; }
P4Cms_Controller_Router_Route_Module::_isControllerParamRequired | ( | $ | params, |
$ | controller, | ||
$ | action | ||
) | [protected] |
Determine if the controller parameter is required to assemble the path.
Not required if controller parameter is the default controller and there is no action parameter or the action can not be confused with a controller.
array | $params | the route parameters to test against. |
string | $controller | the controller to consider |
string | $action | the action within the controller |
{ // required if not default. if ($params[$this->_controllerKey] !== $this->_defaults[$this->_controllerKey]) { return true; } // not required if no action component. if (!isset($action)) { return false; } // required if action name matches a controller name. // we test this by setting the controller parameter to // the given action and seeing if it is dispatchable. $params[$this->_controllerKey] = $action; unset($params[$this->_actionKey]); if ($this->_isDispatchable($params)) { return true; } return false; }
P4Cms_Controller_Router_Route_Module::_isDispatchable | ( | $ | params | ) | [protected] |
Determine if given route parameters are dispatchable.
This is accomplished by creating and populating a request object with params and passing it to the dispatcher's isDispatchable() method.
array | $params | the route parameters to check. |
{ // construct request object from route params. $request = new Zend_Controller_Request_Http; $moduleName = ''; $actionName = ''; foreach ($params as $param => $value) { $request->setParam($param, $value); if ($param === $this->_moduleKey) { $request->setModuleName($value); $moduleName = $value; } if ($param === $this->_controllerKey) { $request->setControllerName($value); } if ($param === $this->_actionKey) { $request->setActionName($value); $actionName = $value; } } $dispatcher = $this->_dispatcher; $dispatchable = $dispatcher->isDispatchable($request); // if dispatchable, we now want to determine whether the specified // action exists. if ($dispatchable and $actionName) { $controllerClass = $dispatcher->getControllerClass($request); if (!$controllerClass) { $controllerClass = $dispatcher->getDefaultControllerClass($request); } if (!$moduleName) { $moduleName = $this->_defaults[$this->_moduleKey]; } $className = $dispatcher->formatClassName(ucfirst($moduleName), $controllerClass); // if controller class doesn't exist, attempt to include it. if (!class_exists($className)) { $file = $dispatcher->getDispatchDirectory() . '/' . $dispatcher->classToFilename($controllerClass); if (Zend_Loader::isReadable($file)) { include $file; } } // verify controller is valid, return false otherwise. if (!class_exists($className) || !is_subclass_of($className, 'Zend_Controller_Action_Interface') ) { return false; } // determine whether the action exists $action = $dispatcher->getActionMethod($request); $dispatchable = method_exists($className, $action) ? true : false; } return $dispatchable; }
P4Cms_Controller_Router_Route_Module::assemble | ( | $ | data = array() , |
$ | reset = false , |
||
$ | encode = true , |
||
$ | partial = false |
||
) |
Override parent implementation to produce shorter paths.
Specifically, excludes the controller segment if it is the default controller and there is no action segment or the action does not match a controller.
array | $data | An array of variable and value pairs used as parameters. |
bool | $reset | Whether to reset the current params. |
bool | $encode | Zend provides no documentation for this param. |
bool | $partial | Zend provides no documentation for this param. |
{ // move parameters to the query string if: // - any parameters contain a slash '/' // (this is a work-around for apache whereby it chokes on %2f in path info) // - any parameters are a single dot '.' // (work-around to prevent situations where uri segments containing only // a single dot are dropped; seems its not connected with the apache) $queryParams = array(); foreach ($data as $key => $value) { if (strpos((string) $key, '/') !== false || strpos((string) $value, '/') !== false || $key === '.' || $value === '.' ) { $queryParams[$key] = $value; unset($data[$key]); } } $path = parent::assemble($data, $reset, $encode, $partial); // blend given router params with current params and defaults. $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; $segments = explode(self::URI_DELIMITER, $path); // while attempting to remove segments, if a non-default module is being used, // removals must begin at the second segment. $offset = 0; if (isset($params[$this->_moduleKey]) && $params[$this->_moduleKey] !== $this->_defaults[$this->_moduleKey] ) { $offset = 1; } $controller = isset($segments[0 + $offset]) ? $segments[0 + $offset] : null; $action = isset($segments[1 + $offset]) ? $segments[1 + $offset] : null; $pathParam = isset($segments[2 + $offset]) ? $segments[2 + $offset] : null; // determine if the action can be removed if (isset($action) && !$this->_isActionParamRequired($params, $action, $pathParam)) { $segments[1 + $offset] = null; $action = $pathParam; } // determine if the controller can be removed if (isset($controller) && !$this->_isControllerParamRequired($params, $controller, $action)) { $segments[$offset] = null; } // compose possibly-revised path $newSegments = array(); foreach ($segments as $segment) { if (isset($segment)) { $newSegments[] = $segment; } } $path = implode(self::URI_DELIMITER, $newSegments); // tack on any query params. if (count($queryParams)) { $path .= "?" . http_build_query($queryParams); } return $path; }
static P4Cms_Controller_Router_Route_Module::formatRouteParam | ( | $ | param | ) | [static] |
Get the route formatted (lower-case, dash-separated) version of a CamelCase identifier.
string | $param | the camel case string. |
{ return strtolower(preg_replace("/(.)([A-Z])/", "\\1-\\2", $param)); }
P4Cms_Controller_Router_Route_Module::isValidAction | ( | $ | action, |
$ | controller, | ||
$ | module | ||
) |
Determine if the given action/module/controller represent a valid action in the system.
The identified controller must exist and the action must match a method in the controller.
string | $action | the (route-formatted) action to check for |
string | $controller | the (route-formatted) controller containing the action |
string | $module | the (route-formatted) module containing the controller |
{ if (!$this->isValidModule($module) || !$this->isValidController($controller, $module) ) { return false; } $dispatcher = $this->_dispatcher; $action = $dispatcher->formatActionName($action); $controller = $dispatcher->formatControllerName($controller); $className = $dispatcher->formatClassName(ucfirst($module), $controller); // determine whether the action exists return method_exists($className, $action); }
P4Cms_Controller_Router_Route_Module::isValidController | ( | $ | controller, |
$ | module | ||
) |
Determine if the given controller exists in the given module.
string | $controller | the (route-formatted) controller to check for. |
string | $module | the (route-formatted) module to look in. |
{ if (!$this->isValidModule($module)) { return false; } $dispatcher = $this->_dispatcher; $controller = $dispatcher->formatControllerName($controller); $className = $dispatcher->formatClassName(ucfirst($module), $controller); // verify controller is valid, return false otherwise. return class_exists($className) && is_subclass_of($className, 'Zend_Controller_Action_Interface'); }
P4Cms_Controller_Router_Route_Module::isValidModule | ( | $ | module | ) |
Determine if the given module is valid.
Alias for dispatcher's isValidModule().
string | $module | the (route-formatted) module to check for. |
{
return $this->_dispatcher->isValidModule($module);
}
P4Cms_Controller_Router_Route_Module::match | ( | $ | path, |
$ | partial = false |
||
) |
Matches a user submitted path.
Assigns and returns an array of variables on a successful match.
Extends Zend's module route to support ommitting the default module, default controller and default action from the path.
string | $path | Path used to match against this routing map. |
bool | $partial | Zend provides no documentation for this param. |
{ $this->_setRequestKeys(); $this->_values = array(); if (!$partial) { $path = trim($path, self::URI_DELIMITER); } else { $this->setMatchedPath($path); } // an empty path matches defaults. if ($path === '') { return $this->getDefaults(); } // break path into segments. $path = explode(self::URI_DELIMITER, $path); $defaultModule = $this->getDefault($this->_moduleKey); $defaultController = $this->getDefault($this->_controllerKey); $defaultAction = $this->getDefault($this->_actionKey); // if the first path segment does not match a valid module, // it must match a controller in the default module or a action // in the default module's default controller. if (!$this->isValidModule($path[0])) { if ($this->isValidController($path[0], $defaultModule)) { array_unshift($path, $defaultModule); } else if ($this->isValidAction($path[0], $defaultController, $defaultModule)) { array_unshift($path, $defaultController); array_unshift($path, $defaultModule); } else { return false; } } // if the second path segment doesn't match a valid controller, // assume the default controller in that module. if (!isset($path[1]) || !$this->isValidController($path[1], $path[0])) { array_splice($path, 1, 0, array($defaultController)); } // if the third path segment doesn't match a valid action, // assume the default action in that module/controller. if (!isset($path[2]) || !$this->isValidAction($path[2], $path[1], $path[0])) { array_splice($path, 2, 0, array($defaultAction)); } // verify we now reference a valid module/controller/action if ($this->isValidAction($path[2], $path[1], $path[0])) { $values = array( $this->_moduleKey => $path[0], $this->_controllerKey => $path[1], $this->_actionKey => $path[2] ); } else { return false; } // process all remaining path segments as parameters. $params = array(); for ($i = 3; $i < count($path); $i = $i + 2) { $key = urldecode($path[$i]); $value = isset($path[$i + 1]) ? urldecode($path[$i + 1]) : null; $params[$key] = (isset($params[$key]) ? (array_merge((array) $params[$key], array($value))) : $value); } $this->_values = $values + $params; return $this->_values + $this->_defaults; }