标准路由器简介
RewriteEngine on RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php 或者: RewriteEngine on RewriteCond %{SCRIPT_FILENAME} !-f RewriteCond %{SCRIPT_FILENAME} !-d RewriteRule ^(.*)$ index.php/$1 如果» Isapi_Rewrite已经用下列的rewrite规则被安装为一个Isapi扩展, rewrite路由器也可以和IIS web服务器一起使用: RewriteRule ^[\w/\%]*(?:\.(?!(?:js|ico|gif|jpg|png|css)$)[\w\%]*$)? /index.php [I]
如果使用 Lighttpd,下面的 rewrite 规则有效: url.rewrite-once = ( ".*\?(.*)$" => "/index.php?$1", ".*\.(js|ico|gif|jpg|png|css)$" => "$0", "" => "/index.php" ) 使用路由器为正确使用rewrite路由器你必须初始化它,添加一些用户定义的路由并注入到控制器。下面的代码示例这个过程: // Create a router $router = $ctrl->getRouter(); // returns a rewrite router by default $router->addRoute( 'user', new Zend_Controller_Router_Route('user/:username', array('controller' => 'user', 'action' => 'info')) ); 基本的Rewrite路由器操作
RewriteRouter的核心是用户定义路由的定义。路由通过调用RewriteRouter的addRoute方法和传递一个由类实现的 $router->addRoute('user', new Zend_Controller_Router_Route('user/:username')); Rewrite 路由器带有四个基本类型的路由(其中一个是特殊的):
路由可以被使用无数次来创建链或用户定义的应用程序路由计划。你可以在任何配置中使用任何数量的路由,除了模块路由以外,它最好被用一次并作为通用路由(例如,作为缺省的)。每个路由将在稍后详细描述。 addRoute的第一个参数是路由名。它用来作为权柄从路由器中取得路由(例如,for URL generation purposes)。第二个参数是路由自己。
路由是一个简单的过程,这个过程通过所有提供的路由和匹配它的当前请求的URI定义来迭代。当一个正匹配被发现,变量值从路由实例返回并注入到
有三个特殊的变量可用于你的路由-'module'、 'controller' 和 'action'。这些特殊的变量被Zend_Controller_Dispatcher用来找出控制器和动作然后派遣过去。
缺省路由
Zend_Controller_Router_Rewrite 和缺省路由一起预先配置,它将以 一些路由如何匹配的例子: // 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'的简单的 $compat = new Zend_Controller_Router_Route_Module(array(), $dispatcher, $request); $this->addRoute('default', $compat);
如果你不想这个特别的缺省路由在你的路由计划中,你可以重写你自己的‘缺省’路由(例如,把它存储在'default'名下)或用 // Remove any default routes $router->removeDefaultRoutes(); 基本 URL 和子目录
rewrite路由器可以被用在子目录(例如,
如果基本URL被误删除,你可以通过 $request->setBaseUrl('/~user/application-root/'); Route TypesZend_Controller_Router_Route
让我们想象一下我们假设的应用程序将需要一些广域内容作者的信息页面。我们想能够把浏览器指向 $route = new Zend_Controller_Router_Route( 'author/:username', array( 'controller' => 'profile', 'action' => 'userinfo' ) ); $router->addRoute('user', $route);
在
当你把浏览器指向 $values = array( 'username' => 'martel', 'controller' => 'profile', 'action' => 'userinfo' );
稍后,基于这些值, 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/*', array('module' => 'default') ); $router->addRoute('default', $route); 变量缺省
在路由中每个变量可以有一个缺省值,这就是 $route = new Zend_Controller_Router_Route( 'archive/:year', array('year' => 2006) ); $router->addRoute('archive', $route);
上述路由将匹配象
这个例子将导致注入一个year变量给请求对象。应为没有路由信息出现(没有控制器和动作参数被定义),应用程序将被派遣给缺省的控制器和动作方法(它们都在 $route = new Zend_Controller_Router_Route( 'archive/:year', array( 'year' => 2006, 'controller' => 'archive', 'action' => 'show' ) ); $router->addRoute('archive', $route);
这个路由将导致派遣给 变量请求
当变量请求被设定,第三个参数可以加给 $route = new Zend_Controller_Router_Route( 'archive/:year', array( 'year' => 2006, 'controller' => 'archive', 'action' => 'show' ), array('year' => '\d+') ); $router->addRoute('archive', $route);
用上述定义的路由,路由器仅当year变量包含数字数据将匹配它,例如 主机名路由你也可以使用主机名做路由匹配。对简单的匹配使用静态主机名选项: $route = new Zend_Controller_Router_Route( array( 'host' => 'blog.mysite.com', 'path' => 'archive' ), array( 'module' => 'blog', 'controller' => 'archive', 'action' => 'index' ) ); $router->addRoute('archive', $route); 如果你想匹配参数在主机名里,使用 regex 选项。在下面例子中,子域为动作控制器被用作用户名参数。 当组装路由时,你可以给出用户名为参数,就像你用其它路径参数一样: $route = new Zend_Controller_Router_Route( array( 'host' => array( 'regex' => '([a-z]+).mysite.com', 'reverse' => '%s.mysite.com' 'params' => array( 1 => 'username' ) ), 'path' => '' ), array( 'module' => 'users', 'controller' => 'profile', 'action' => 'index' ) ); $router->addRoute('profile', $route); Zend_Controller_Router_Route_Static上面的例子都使用动态路由--包含模型来匹配的路由。然而有时候,特定的路由被设定成型,启动正则表达式引擎将有过渡的杀伤力。对这种情形的答案是使用静态路由: $route = new Zend_Controller_Router_Route_Static( 'login', array('controller' => 'auth', 'action' => 'login') ); $router->addRoute('login', $route);
上面的路由将匹配 Zend_Controller_Router_Route_Regex除了缺省的和静态的路由类型外,正则表达式路由类型也可用。这个路由比其它路由更强更灵活,只是稍微有点复杂。同时,它应该比标准路由快。 象标准路由一样,这个路由必须用路由定义和一些缺省条件来初始化。让我们创建一个archive路由作为例子,和先前定义的类似,这次只是用了Regex: $route = new Zend_Controller_Router_Route_Regex( 'archive/(\d+)', array( 'controller' => 'archive', 'action' => 'show' ) ); $router->addRoute('archive', $route);
每个定义的regex子模式将被注入到请求对象里。同上述的例子,再成功匹配 $values = array( 1 => '2006', 'controller' => 'archive', 'action' => 'show' );
你可以用通常的办法获得已定义的子模式的内容: public function showAction() { $request = $this->getRequest(); $year = $request->getParam(1); // $year = '2006'; }
因为'year'的缺省没有设置,这个路由将和它的标准路由副本不是非常精确地相同。即使我们为'year'声明一个缺省并使子模式可选,也不清楚是否会在拖尾斜杠(trailing slash)上还将有问题。方案是使整个'year'部分和斜杠一起可选但只抓取数字部分:(这段比较绕口,请校对者仔细看看,谢谢 Jason Qi) $route = new Zend_Controller_Router_Route_Regex( 'archive(?:/(\d+))?', array( 1 => '2006', 'controller' => 'archive', 'action' => 'show' ) ); $router->addRoute('archive', $route); 让我们看看你可能注意到的问题。 给参数使用基于整数的键不是容易管理的办法,今后可能会有问题。这就是为什么有第三个参数。这是个联合数组表示一个regex子模式到参数名键的映射。我们来看看一个简单的例子: $route = new Zend_Controller_Router_Route_Regex( 'archive/(\d+)', array( 'controller' => 'archive', 'action' => 'show' ), array( 1 => 'year' ) ); $router->addRoute('archive', $route); 这将导致下面的值被注入到请求: $values = array( 'year' => '2006', 'controller' => 'archive', 'action' => 'show' ); 这个映射被任何目录来定义使它能工作于任何环境。键可以包含变量名或子模式索引: $route = new Zend_Controller_Router_Route_Regex( 'archive/(\d+)', array( ... ), array(1 => 'year') ); // OR $route = new Zend_Controller_Router_Route_Regex( 'archive/(\d+)', array( ... ), array('year' => 1) );
注意在请求值中的数字索引不见了,代替的是一个名字变量。当然如果你愿意可以把数字和名字变量混合使用: $route = new Zend_Controller_Router_Route_Regex( 'archive/(\d+)/page/(\d+)', array( ... ), array('year' => 1) );
这将导致在请求中有混合的值可用。例如:URL $values = array( 'year' => '2006', 2 => 10, 'controller' => 'archive', 'action' => 'show' ); 因为regex模型不容易颠倒,如果你想用URL助手或这个类中的 assemble方法,你需要准备一个颠倒的URL。这个颠倒的路径用可由sprintf()解析的字符串来表示并定义为第四个构造参数: $route = new Zend_Controller_Router_Route_Regex( 'archive/(\d+)', array( ... ), array('year' => 1), 'archive/%s' );
所有这些都已经可能由标准路由对象完成,那么使用Regex路由的好处在哪里?首先,它允许你不受限制地描述任何类型的URL。想象一下你有一个博客并希望创建象 $route = new Zend_Controller_Router_Route_Regex( 'blog/archive/(\d+)-(.+)\.html', array( 'controller' => 'blog', 'action' => 'view' ), array( 1 => 'id', 2 => 'description' ), 'blog/archive/%d-%s.html' ); $router->addRoute('blogArchive', $route); 正如你所看到的,这个在标准路由上添加了巨大的灵活性。 使用 Zend_Config with the RewriteRouter
有时候,用新路由更新配置文件比修改代码更方便。这个可能通过 作为例子,考虑下面的 INI 文件: [production] routes.archive.route = "archive/:year/*" routes.archive.defaults.controller = archive routes.archive.defaults.action = show routes.archive.defaults.year = 2000 routes.archive.reqs.year = "\d+" routes.news.type = "Zend_Controller_Router_Route_Static" routes.news.route = "news" routes.news.defaults.controller = "news" routes.news.defaults.action = "list" routes.archive.type = "Zend_Controller_Router_Route_Regex" routes.archive.route = "archive/(\d+)" routes.archive.defaults.controller = "archive" routes.archive.defaults.action = "show" routes.archive.map.1 = "year" ; OR: routes.archive.map.year = 1
上述的INI文件可以被读进 $config = new Zend_Config_Ini('/path/to/config.ini', 'production'); $router = new Zend_Controller_Router_Rewrite(); $router->addConfig($config, 'routes');
在上面的例子中,我们告诉路由器去使用INI文件'routes'一节给它的路由。每个在这个节下的顶级键将用来定义路由名;上述例子定义了路由'archive'和'news'。每个路由接着要求,至少,一个'route'条目和一个或更多'defaults'条目;可选地,一个或更多'reqs'('required'的简写)可能要求提供。总之,这些相对应的三个参数提供给 Subclassing the Router标准的rewrite路由器应当最大限度提供你所需的功能;大多时候,为了通过已知的路由提供新的或修改的功能,你将只需要创建一个新的路由类型
那就是说,你可能想要用不同的路由范例。接口 interface Zend_Controller_Router_Interface { /** * @param Zend_Controller_Request_Abstract $request * @throws Zend_Controller_Router_Exception * @return Zend_Controller_Request_Abstract */ public function route(Zend_Controller_Request_Abstract $request); } 路由只发生一次:当请求第一次接收到系统。路由器的意图是基于请求的环境决定控制器、动作和可选的参数,并把它们发给请求。请求对象接着传递给派遣器。如果不可能映射一个路由到一个派遣令牌,路由器对请求对象就什么也不做。
|