Zend_Controller-Router-Route-Regex.xml 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. <sect3 id="zend.controller.router.routes.regex">
  2. <title>Zend_Controller_Router_Route_Regex</title>
  3. <para>
  4. 除了缺省的和静态的路由类型外,正则表达式路由类型也可用。这个路由比其它路由更强更灵活,只是稍微有点复杂。同时,它应该比标准路由快。
  5. </para>
  6. <para>
  7. 象标准路由一样,这个路由必须用路由定义和一些缺省条件来初始化。让我们创建一个archive路由作为例子,和先前定义的类似,这次只是用了Regex:
  8. </para>
  9. <programlisting role="php"><![CDATA[
  10. $route = new Zend_Controller_Router_Route_Regex(
  11. 'archive/(\d+)',
  12. array(
  13. 'controller' => 'archive',
  14. 'action' => 'show'
  15. )
  16. );
  17. $router->addRoute('archive', $route);
  18. ]]>
  19. </programlisting>
  20. <para>
  21. 每个定义的regex子模式将被注入到请求对象里。同上述的例子,再成功匹配<code>http://domain.com/archive/2006</code>之后,结果值的数组看起来象这样:
  22. </para>
  23. <programlisting role="php"><![CDATA[
  24. $values = array(
  25. 1 => '2006',
  26. 'controller' => 'archive',
  27. 'action' => 'show'
  28. );
  29. ]]>
  30. </programlisting>
  31. <note>
  32. <para>
  33. 在匹配之前,开头和结尾的斜杠从路由器里的URL中去除掉了。结果,匹配<code>http://domain.com/foo/bar/</code>,需要<code>foo/bar</code>这样的regex,而不是<code>/foo/bar</code>。
  34. </para>
  35. </note>
  36. <note>
  37. <para>
  38. 行开头和行结尾符号(分别为'^' 和 '$')被自动预先追加到所有表达式。这样,你不需要在你的正则表达式里用它们,你应该匹配整个字符串。
  39. </para>
  40. </note>
  41. <note>
  42. <para>
  43. 这个路由类使用<code>#</code>符作为分隔符。这意味着你将需要避免哈希符('#')但不是正斜杠('/')在你的路由定义里。因为'#'符(名称为锚)很少被传给webserver,你将几乎不需要在你的regex里使用它。
  44. </para>
  45. </note>
  46. <para>
  47. 你可以用通常的办法获得已定义的子模式的内容:
  48. </para>
  49. <programlisting role="php"><![CDATA[
  50. public function showAction()
  51. {
  52. $request = $this->getRequest();
  53. $year = $request->getParam(1); // $year = '2006';
  54. }
  55. ]]>
  56. </programlisting>
  57. <note>
  58. <para>注意这个键是整数(1) 而不是字符串('1')。</para>
  59. </note>
  60. <para>
  61. 因为'year'的缺省没有设置,这个路由将和它的标准路由副本不是非常精确地相同。即使我们为'year'声明一个缺省并使子模式可选,也不清楚是否会在拖尾斜杠(trailing slash)上还将有问题。方案是使整个'year'部分和斜杠一起可选但只抓取数字部分:(这段比较绕口,请校对者仔细看看,谢谢 Jason Qi)
  62. </para>
  63. <programlisting role="php"><![CDATA[
  64. $route = new Zend_Controller_Router_Route_Regex(
  65. 'archive(?:/(\d+))?',
  66. array(
  67. 1 => '2006',
  68. 'controller' => 'archive',
  69. 'action' => 'show'
  70. )
  71. );
  72. $router->addRoute('archive', $route);
  73. ]]>
  74. </programlisting>
  75. <para>
  76. 让我们看看你可能注意到的问题。 给参数使用基于整数的键不是容易管理的办法,今后可能会有问题。这就是为什么有第三个参数。这是个联合数组表示一个regex子模式到参数名键的映射。我们来看看一个简单的例子:
  77. </para>
  78. <programlisting role="php"><![CDATA[
  79. $route = new Zend_Controller_Router_Route_Regex(
  80. 'archive/(\d+)',
  81. array(
  82. 'controller' => 'archive',
  83. 'action' => 'show'
  84. ),
  85. array(
  86. 1 => 'year'
  87. )
  88. );
  89. $router->addRoute('archive', $route);
  90. ]]>
  91. </programlisting>
  92. <para>
  93. 这将导致下面的值被注入到请求:
  94. </para>
  95. <programlisting role="php"><![CDATA[
  96. $values = array(
  97. 'year' => '2006',
  98. 'controller' => 'archive',
  99. 'action' => 'show'
  100. );
  101. ]]>
  102. </programlisting>
  103. <para>
  104. 这个映射被任何目录来定义使它能工作于任何环境。键可以包含变量名或子模式索引:
  105. </para>
  106. <programlisting role="php"><![CDATA[
  107. $route = new Zend_Controller_Router_Route_Regex(
  108. 'archive/(\d+)',
  109. array( ... ),
  110. array(1 => 'year')
  111. );
  112. // OR
  113. $route = new Zend_Controller_Router_Route_Regex(
  114. 'archive/(\d+)',
  115. array( ... ),
  116. array('year' => 1)
  117. );
  118. ]]>
  119. </programlisting>
  120. <note>
  121. <para>
  122. 子模式键必须用整数表示。
  123. </para>
  124. </note>
  125. <para>
  126. 注意在请求值中的数字索引不见了,代替的是一个名字变量。当然如果你愿意可以把数字和名字变量混合使用:
  127. </para>
  128. <programlisting role="php"><![CDATA[
  129. $route = new Zend_Controller_Router_Route_Regex(
  130. 'archive/(\d+)/page/(\d+)',
  131. array( ... ),
  132. array('year' => 1)
  133. );
  134. ]]>
  135. </programlisting>
  136. <para>
  137. 这将导致在请求中有混合的值可用。例如:URL<code>http://domain.com/archive/2006/page/10</code>将在下列结果中:
  138. </para>
  139. <programlisting role="php"><![CDATA[
  140. $values = array(
  141. 'year' => '2006',
  142. 2 => 10,
  143. 'controller' => 'archive',
  144. 'action' => 'show'
  145. );
  146. ]]>
  147. </programlisting>
  148. <para>
  149. 因为regex模型不容易颠倒,如果你想用URL助手或这个类中的 assemble方法,你需要准备一个颠倒的URL。这个颠倒的路径用可由sprintf()解析的字符串来表示并定义为第四个构造参数:
  150. </para>
  151. <programlisting role="php"><![CDATA[
  152. $route = new Zend_Controller_Router_Route_Regex(
  153. 'archive/(\d+)',
  154. array( ... ),
  155. array('year' => 1),
  156. 'archive/%s'
  157. );
  158. ]]>
  159. </programlisting>
  160. <para>
  161. 所有这些都已经可能由标准路由对象完成,那么使用Regex路由的好处在哪里?首先,它允许你不受限制地描述任何类型的URL。想象一下你有一个博客并希望创建象<code>http://domain.com/blog/archive/01-Using_the_Regex_Router.html</code>这样的URLs,还有把解析它路径元素中的最后部分,<code>01-Using_the_Regex_Router.html</code>,到一个文章的ID和文章的标题/描述;这不可能由标准路由完成。用Regex路由,你可以做象下面的方案:
  162. </para>
  163. <programlisting role="php"><![CDATA[
  164. $route = new Zend_Controller_Router_Route_Regex(
  165. 'blog/archive/(\d+)-(.+)\.html',
  166. array(
  167. 'controller' => 'blog',
  168. 'action' => 'view'
  169. ),
  170. array(
  171. 1 => 'id',
  172. 2 => 'description'
  173. ),
  174. 'blog/archive/%d-%s.html'
  175. );
  176. $router->addRoute('blogArchive', $route);
  177. ]]>
  178. </programlisting>
  179. <para>
  180. 正如你所看到的,这个在标准路由上添加了巨大的灵活性。
  181. </para>
  182. </sect3>
  183. <!--
  184. vim:se ts=4 sw=4 et:
  185. -->