本文实例讲述了Zend framework教程之路由功能Zend_Controller_Router用法。分享给大家供大家参考,具体如下:
Zend framework的路由提供了两个主要功能路由和创建路由。
Zend_Controller_Router的Route类和相应Route目录下的类定义常见的路由操作。
接口Zend_Controller_Router_Interface,类Zend_Controller_Router_Abstract和Zend_Controller_Router_Rewrite完成了基本的路由,创建路由,删除路由的功能。
└── Router
├── Abstract.php
├── Exception.php
├── Interface.php
├── Rewrite.php
├── Route
│ ├── Abstract.php
│ ├── Chain.php
│ ├── Hostname.php
│ ├── Interface.php
│ ├── Module.php
│ ├── Regex.php
│ └── Static.php
└── Route.php
Zend_Controller_Router路由功能的实现
Zend_Controller_Router_Interface
Zend_Controller_Router_Abstract
setParams($params); } public function setParam($name, $value) { $name = (string) $name; $this->_invokeParams[$name] = $value; return $this; } public function setParams(array $params) { $this->_invokeParams = array_merge($this->_invokeParams, $params); return $this; } public function getParam($name) { if(isset($this->_invokeParams[$name])) { return $this->_invokeParams[$name]; } return null; } public function getParams() { return $this->_invokeParams; } public function clearParams($name = null) { if (null === $name) { $this->_invokeParams = array(); } elseif (is_string($name) && isset($this->_invokeParams[$name])) { unset($this->_invokeParams[$name]); } elseif (is_array($name)) { foreach ($name as $key) { if (is_string($key) && isset($this->_invokeParams[$key])) { unset($this->_invokeParams[$key]); } } } return $this; } public function getFrontController() { // Used cache version if found if (null !== $this->_frontController) { return $this->_frontController; } require_once 'Zend/Controller/Front.php'; $this->_frontController = Zend_Controller_Front::getInstance(); return $this->_frontController; } public function setFrontController(Zend_Controller_Front $controller) { $this->_frontController = $controller; return $this; } }Zend_Controller_Router_Rewrite
hasRoute('default')) { $dispatcher = $this->getFrontController()->getDispatcher(); $request = $this->getFrontController()->getRequest(); require_once 'Zend/Controller/Router/Route/Module.php'; $compat = new Zend_Controller_Router_Route_Module(array(), $dispatcher, $request); $this->_routes = array('default' => $compat) + $this->_routes; } return $this; } public function addRoute($name, Zend_Controller_Router_Route_Interface $route) { if (method_exists($route, 'setRequest')) { $route->setRequest($this->getFrontController()->getRequest()); } $this->_routes[$name] = $route; return $this; } public function addRoutes($routes) { foreach ($routes as $name => $route) { $this->addRoute($name, $route); } return $this; } public function addConfig(Zend_Config $config, $section = null) { if ($section !== null) { if ($config->{$section} === null) { require_once 'Zend/Controller/Router/Exception.php'; throw new Zend_Controller_Router_Exception("No route configuration in section '{$section}'"); } $config = $config->{$section}; } foreach ($config as $name => $info) { $route = $this->_getRouteFromConfig($info); if ($route instanceof Zend_Controller_Router_Route_Chain) { if (!isset($info->chain)) { require_once 'Zend/Controller/Router/Exception.php'; throw new Zend_Controller_Router_Exception("No chain defined"); } if ($info->chain instanceof Zend_Config) { $childRouteNames = $info->chain; } else { $childRouteNames = explode(',', $info->chain); } foreach ($childRouteNames as $childRouteName) { $childRoute = $this->getRoute(trim($childRouteName)); $route->chain($childRoute); } $this->addRoute($name, $route); } elseif (isset($info->chains) && $info->chains instanceof Zend_Config) { $this->_addChainRoutesFromConfig($name, $route, $info->chains); } else { $this->addRoute($name, $route); } } return $this; } protected function _getRouteFromConfig(Zend_Config $info) { $class = (isset($info->type)) ? $info->type : 'Zend_Controller_Router_Route'; if (!class_exists($class)) { require_once 'Zend/Loader.php'; Zend_Loader::loadClass($class); } $route = call_user_func(array($class, 'getInstance'), $info); if (isset($info->abstract) && $info->abstract && method_exists($route, 'isAbstract')) { $route->isAbstract(true); } return $route; } protected function _addChainRoutesFromConfig($name, Zend_Controller_Router_Route_Interface $route, Zend_Config $childRoutesInfo) { foreach ($childRoutesInfo as $childRouteName => $childRouteInfo) { if (is_string($childRouteInfo)) { $childRouteName = $childRouteInfo; $childRoute = $this->getRoute($childRouteName); } else { $childRoute = $this->_getRouteFromConfig($childRouteInfo); } if ($route instanceof Zend_Controller_Router_Route_Chain) { $chainRoute = clone $route; $chainRoute->chain($childRoute); } else { $chainRoute = $route->chain($childRoute); } $chainName = $name . $this->_chainNameSeparator . $childRouteName; if (isset($childRouteInfo->chains)) { $this->_addChainRoutesFromConfig($chainName, $chainRoute, $childRouteInfo->chains); } else { $this->addRoute($chainName, $chainRoute); } } } public function removeRoute($name) { if (!isset($this->_routes[$name])) { require_once 'Zend/Controller/Router/Exception.php'; throw new Zend_Controller_Router_Exception("Route $name is not defined"); } unset($this->_routes[$name]); return $this; } public function removeDefaultRoutes() { $this->_useDefaultRoutes = false; return $this; } public function hasRoute($name) { return isset($this->_routes[$name]); } public function getRoute($name) { if (!isset($this->_routes[$name])) { require_once 'Zend/Controller/Router/Exception.php'; throw new Zend_Controller_Router_Exception("Route $name is not defined"); } return $this->_routes[$name]; } public function getCurrentRoute() { if (!isset($this->_currentRoute)) { require_once 'Zend/Controller/Router/Exception.php'; throw new Zend_Controller_Router_Exception("Current route is not defined"); } return $this->getRoute($this->_currentRoute); } public function getCurrentRouteName() { if (!isset($this->_currentRoute)) { require_once 'Zend/Controller/Router/Exception.php'; throw new Zend_Controller_Router_Exception("Current route is not defined"); } return $this->_currentRoute; } public function getRoutes() { return $this->_routes; } public function route(Zend_Controller_Request_Abstract $request) { if (!$request instanceof Zend_Controller_Request_Http) { require_once 'Zend/Controller/Router/Exception.php'; throw new Zend_Controller_Router_Exception('Zend_Controller_Router_Rewrite requires a Zend_Controller_Request_Http-based request object'); } if ($this->_useDefaultRoutes) { $this->addDefaultRoutes(); } // Find the matching route $routeMatched = false; foreach (array_reverse($this->_routes, true) as $name => $route) { // TODO: Should be an interface method. Hack for 1.0 BC if (method_exists($route, 'isAbstract') && $route->isAbstract()) { continue; } // TODO: Should be an interface method. Hack for 1.0 BC if (!method_exists($route, 'getVersion') || $route->getVersion() == 1) { $match = $request->getPathInfo(); } else { $match = $request; } if ($params = $route->match($match)) { $this->_setRequestParams($request, $params); $this->_currentRoute = $name; $routeMatched = true; break; } } if (!$routeMatched) { require_once 'Zend/Controller/Router/Exception.php'; throw new Zend_Controller_Router_Exception('No route matched the request', 404); } if($this->_useCurrentParamsAsGlobal) { $params = $request->getParams(); foreach($params as $param => $value) { $this->setGlobalParam($param, $value); } } return $request; } protected function _setRequestParams($request, $params) { foreach ($params as $param => $value) { $request->setParam($param, $value); if ($param === $request->getModuleKey()) { $request->setModuleName($value); } if ($param === $request->getControllerKey()) { $request->setControllerName($value); } if ($param === $request->getActionKey()) { $request->setActionName($value); } } } public function assemble($userParams, $name = null, $reset = false, $encode = true) { if (!is_array($userParams)) { require_once 'Zend/Controller/Router/Exception.php'; throw new Zend_Controller_Router_Exception('userParams must be an array'); } if ($name == null) { try { $name = $this->getCurrentRouteName(); } catch (Zend_Controller_Router_Exception $e) { $name = 'default'; } } // Use UNIOn (+) in order to preserve numeric keys $params = $userParams + $this->_globalParams; $route = $this->getRoute($name); $url = $route->assemble($params, $reset, $encode); if (!preg_match('|^[a-z]+://|', $url)) { $url = rtrim($this->getFrontController()->getbaseUrl(), self::URI_DELIMITER) . self::URI_DELIMITER . $url; } return $url; } public function setGlobalParam($name, $value) { $this->_globalParams[$name] = $value; return $this; } public function setChainNameSeparator($separator) { $this->_chainNameSeparator = $separator; return $this; } public function getChainNameSeparator() { return $this->_chainNameSeparator; } public function useRequestParametersAsGlobal($use = null) { if($use === null) { return $this->_useCurrentParamsAsGlobal; } $this->_useCurrentParamsAsGlobal = (bool) $use; return $this; } }添加路由的操作方法
public function addRoute($name, Zend_Controller_Router_Route_Interface $route)
public function addRoutes($routes)$router = $ctrl->getRouter(); // returns a rewrite router by default $router->addRoute('user', new Zend_Controller_Router_Route('user/:username'));addRoute的第一个参数是路由名。第二个参数是路由自己。路由名最普通的用法是通过Zend_View_Url助手的方法:
"= $this->url(array('username' => 'martel'), 'user') ?>">Martel它将导致在 href: user/martel.
路由是一个简单的过程,这个过程通过所有提供的路由和匹配它的当前请求的URI定义来迭代。当一个正匹配被发现,变量值从路由实例返回并注入到Zend_Controller_Request对象以备将来在派遣器和用户创建的控制器中使用。如果是负匹配,在链中的下个路由被检查。
Note: 倒序匹配
用倒序来匹配路由确保最通用的路由被首先定义。
Note: 返回的值
从路由返回的值来自于URL参数或用于定义的缺省值。这些变量以后可通过Zend_Controller_Request::getParam() 或 Zend_Controller_Action::_getParam() 方法来访问。
有三个特殊的变量可用于你的路由-'module'、 'controller' 和 'action'。这些特殊的变量被Zend_Controller_Dispatcher用来找出控制器和动作然后派遣过去。
Note: 特殊变量
如果你选择通过 setControllerKey 和 setActionKey方法的方式来改变缺省值,这些特殊变量的名字可能会不同。
缺省路由
Zend_Controller_Router_Rewrite 和缺省路由一起预先配置,它将以controller/action的形式匹配URIs。另外,模块名可以被指定作为第一个路径参数,允许这种module/controller/action形式的URIs。最后,它也将缺省地匹配任何另外的追加到URI的参数-controller/action/var1/value1/var2/value2。
一些路由如何匹配的例子:
// Assuming the following: $ctrl->setControllerDirectory( array( 'default' => '/path/to/default/controllers', 'news' => '/path/to/news/controllers', 'blog' => '/path/to/blog/controllers' ) ); Module only: http://example/news module == news Invalid module maps to controller name: http://example/foo controller == foo Module + controller: http://example/blog/archive module == blog controller == archive Module + controller + action: http://example/blog/archive/list module == blog controller == archive action == list Module + controller + action + params: http://example/blog/archive/list/sort/alpha/date/desc module == blog controller == archive action == list sort == alpha date == desc缺省路由是存储在RewriteRouter名(index)为'default'的简单的Zend_Controller_Router_Route_Module对象。它被创建多多少少象下面这样:
$compat = new Zend_Controller_Router_Route_Module(array(), $dispatcher, $request); $this->addRoute('default', $compat);如果你不想这个特别的缺省路由在你的路由计划中,你可以重写你自己的‘缺省'路由(例如,把它存储在'default'名下)或用removeDefaultRoutes()完全清除它:
// Remove any default routes $router->removeDefaultRoutes();为了增加路由的灵活性,方便自定义新的路由类型,Zend_Controller_Router定义了Zend_Controller_Router_Route_Interface接口和类Zend_Controller_Router_Route_Abstract,实现相应的类方法即可定义路由类型,为开发提供了便利。
Zend_Controller_Router的路由类型
Zend_Controller_Router默认提供了以下路由类型,分别为:
Zend_Controller_Router_Route
Zend_Controller_Router_Route_Static
Zend_Controller_Router_Route_Regex
Zend_Controller_Router_Route_Hostname
Zend_Controller_Router_Route_Module
Zend_Controller_Router_Route_Chain
Zend_Controller_Router_RouteZend_Controller_Router_Route是标准的框架路由。它结合了灵活路由定义的易用性。每个路由包含了基本的URL映射(静态的和动态的部分(变量))并且可以被缺省地初始化,也可以根据不同的要求初始化。
让我们想象一下我们假设的应用程序将需要一些广域内容作者的信息页面。我们想能够把浏览器指向http://domain.com/author/martel去看一个叫"martel"的信息。有这样功能的路由看起来是这样的:
$route = new Zend_Controller_Router_Route( 'author/:username', array( 'controller' => 'profile', 'action' => 'userinfo' ) ); $router->addRoute('user', $route);在Zend_Controller_Router_Route里构造函数的第一个参数是路由的定义,它将匹配一个URL。路由定义包含静态的和动态部分,它们由正斜杠('/')符分开。静态部分只是简单的字符:author。动态部分,被叫做变量,用预设的冒号来标记变量名::username。
Note: 字符的的用法
当前的实现允许你使用任何字符(正斜杠除外)作为变量标识符,但强烈建议只使用PHP使用的变量标识符。将来的实现也许会改变这个行为,它可能会导致在你的代码里有隐藏的bugs。
当你把浏览器指向http://domain.com/author/martel这个例子的路由应该被匹配,它所有的变量将被注入到Zend_Controller_Request对象并在ProfileController可访问。由这个例子返回的变量可能会被表示为如下键和值配对的数组:
$values = array( 'username' => 'martel', 'controller' => 'profile', 'action' => 'userinfo' );稍后,基于这些值,Zend_Controller_Dispatcher_Standard应该调用ProfileController类(在缺省模块中)中的userinfoAction()方法。你将依靠Zend_Controller_Action::_getParam()或者Zend_Controller_Request::getParam()方法能够访问所有的变量:
public function userinfoAction() { $request = $this->getRequest(); $username = $request->getParam('username'); $username = $this->_getParam('username'); }路由定义可以包一个额外的特别字符-通配符-表示为'*'号。它被用来取得参数,和缺省模块路由类似(在URI中定义的var=>value)。下面的路由多多少少地模仿了模块路由的行为:
$route = new Zend_Controller_Router_Route( ':module/:controller/:action public function route(Zend_Controller_Request_Abstract $request); }路由只发生一次:当请求第一次接收到系统。路由器的意图是基于请求的环境决定控制器、动作和可选的参数,并把它们发给请求。请求对象接着传递给派遣器。如果不可能映射一个路由到一个派遣令牌,路由器对请求对象就什么也不做。
更多关于zend相关内容感兴趣的读者可查看本站专题:《Zend frameWork框架入门教程》、《php优秀开发框架总结》、《Yii框架入门及常用技巧总结》、《ThinkPHP入门教程》、《php面向对象程序设计入门教程》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总》
希望本文所述对大家PHP程序设计有所帮助。



