Zend_Controller-Router.xml 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 15103 -->
  3. <!-- Reviewed: no -->
  4. <sect1 id="zend.controller.router" xmlns:xi="http://www.w3.org/2001/XInclude">
  5. <title>Der Standard Router</title>
  6. <sect2 id="zend.controller.router.introduction">
  7. <title>Einführung</title>
  8. <para>
  9. <classname>Zend_Controller_Router_Rewrite</classname> ist der Standard Router des Frameworks.
  10. Routing ist der Prozess der Übernahme und Zerteilung einer URI, um zu
  11. ermitteln, welches Modul, welcher Controller und welche Aktion des Controllers die
  12. Anfrage erhalten soll. Die Definition des Moduls, des Controllers, der Aktion sowie
  13. weiterer Parameter wird in einem Objekt mit Namen
  14. <classname>Zend_Controller_Dispatcher_Token</classname> gekapselt, das dann vom
  15. <classname>Zend_Controller_Dispatcher_Standard</classname> verarbeitet wird. Das Routing
  16. geschieht nur einmal: wenn zu Beginn die Anfrage erhalten wird und bevor der erste
  17. Controller aufgerufen wird.
  18. </para>
  19. <para>
  20. <classname>Zend_Controller_Router_Rewrite</classname> wurde entwickelt, um mit reinen PHP
  21. Strukturen eine mod_rewrite ähnliche Funktionalität zu erlauben. Es richtet sich
  22. sehr frei nach dem Ruby on Rails Routing und benötigt kein tieferes Wissen über
  23. URL Weiterleitung des Webservers. Es wurde entwickelt, um mit einer einzigen
  24. mod_rewrite Regel zu arbeiten.
  25. </para>
  26. <programlisting role="php"><![CDATA[
  27. RewriteEngine on
  28. RewriteRule !\.(js|ico|gif|jpg|png|css|html)$ index.php
  29. ]]>
  30. </programlisting>
  31. <para>
  32. oder (bevorzugt):
  33. </para>
  34. <programlisting role="php"><![CDATA[
  35. RewriteEngine On
  36. RewriteCond %{REQUEST_FILENAME} -s [OR]
  37. RewriteCond %{REQUEST_FILENAME} -l [OR]
  38. RewriteCond %{REQUEST_FILENAME} -d
  39. RewriteRule ^.*$ - [NC,L]
  40. RewriteRule ^.*$ index.php [NC,L]
  41. ]]>
  42. </programlisting>
  43. <para>
  44. Der Rewrite Router kann auch mit dem IIS Webserver verwendet werden (Versionen &lt;= 7.0), wenn
  45. <ulink url="http://www.isapirewrite.com">Isapi_Rewrite</ulink> als Isapi
  46. Erweiterung installiert wurde und folgende Umschreibungsregel verwendet wird:
  47. </para>
  48. <programlisting role="php"><![CDATA[
  49. RewriteRule ^[\w/\%]*(?:\.(?!(?:js|ico|gif|jpg|png|css|html)$)[\w\%]*$)? /index.php [I]
  50. ]]>
  51. </programlisting>
  52. <note>
  53. <title>IIS Isapi_Rewrite</title>
  54. <para>
  55. Bei Verwendung von IIS, wird <code>$_SERVER['REQUEST_URI']</code> entweder nicht
  56. vorhanden oder auf einen leeren String gesetzt sein. In diesem Fall wird
  57. <classname>Zend_Controller_Request_Http</classname> versuchen, den durch die Isapi_Rewrite
  58. Erweiterung gesetzten Wert <code>$_SERVER['HTTP_X_REWRITE_URL']</code> zu
  59. verwenden.
  60. </para>
  61. </note>
  62. <para>
  63. IIS 7.0 führt ein natives URL Rewriting Modul ein, und kann wie folgt konfiguriert werden:
  64. </para>
  65. <programlisting role="xml"><![CDATA[
  66. <?xml version="1.0" encoding="UTF-8"?>
  67. <configuration>
  68. <system.webServer>
  69. <rewrite>
  70. <rules>
  71. <rule name="Imported Rule 1" stopProcessing="true">
  72. <match url="^.*$" />
  73. <conditions logicalGrouping="MatchAny">
  74. <add input="{REQUEST_FILENAME}"
  75. matchType="IsFile" pattern=""
  76. ignoreCase="false" />
  77. <add input="{REQUEST_FILENAME}"
  78. matchType="IsDirectory"
  79. pattern="" ignoreCase="false" />
  80. </conditions>
  81. <action type="None" />
  82. </rule>
  83. <rule name="Imported Rule 2" stopProcessing="true">
  84. <match url="^.*$" />
  85. <action type="Rewrite" url="index.php" />
  86. </rule>
  87. </rules>
  88. </rewrite>
  89. </system.webServer>
  90. </configuration>
  91. ]]></programlisting>
  92. <para>
  93. Bei der Verwendung von Lighttpd, ist folgende Umschreibungsregel gültig:
  94. </para>
  95. <programlisting role="lighttpd"><![CDATA[
  96. url.rewrite-once = (
  97. ".*\?(.*)$" => "/index.php?$1",
  98. ".*\.(js|ico|gif|jpg|png|css|html)$" => "$0",
  99. "" => "/index.php"
  100. )
  101. ]]>
  102. </programlisting>
  103. </sect2>
  104. <sect2 id="zend.controller.router.usage">
  105. <title>Einen Router verwenden</title>
  106. <para>
  107. Um den Rewrite Router richtig zu verwenden, muß er instanziiert, einige
  108. benutzerdefinierte Routen hinzufügt und in den Controller einbunden werden. Der folgende
  109. Code veranschaulicht die Vorgehensweise:
  110. </para>
  111. <programlisting role="php"><![CDATA[
  112. // Einen Router erstellen
  113. $router = $ctrl->getRouter(); // gibt standardmäßig einen Rewrite Router zurück
  114. $router->addRoute(
  115. 'user',
  116. new Zend_Controller_Router_Route('user/:username',
  117. array('controller' => 'user',
  118. 'action' => 'info'))
  119. );
  120. ]]>
  121. </programlisting>
  122. </sect2>
  123. <sect2 id="zend.controller.router.basic">
  124. <title>Grundsätzliche Rewrite Router Operationen</title>
  125. <para>
  126. Das Herz des RewriteRouters ist die Definition von Benutzerdefinierten Routen. Routen werden durch
  127. aufruf der addRoute Methode des RewriteRouters hinzugefügt und übergeben eine neue Instanz einer
  128. Klasse die <classname>Zend_Controller_Router_Route_Interface</classname> implementiert. Z.B.:
  129. </para>
  130. <programlisting role="php"><![CDATA[
  131. $router->addRoute('user',
  132. new Zend_Controller_Router_Route('user/:username'));
  133. ]]>
  134. </programlisting>
  135. <para>
  136. Der Rewrite Router kommt mit sechs Basistypen von Routen (eine von denen ist speziell):
  137. is special):
  138. </para>
  139. <itemizedlist mark="opencircle">
  140. <listitem><para><xref linkend="zend.controller.router.routes.standard" /></para></listitem>
  141. <listitem><para><xref linkend="zend.controller.router.routes.static" /></para></listitem>
  142. <listitem><para><xref linkend="zend.controller.router.routes.regex" /></para></listitem>
  143. <listitem><para><xref linkend="zend.controller.router.routes.hostname" /></para></listitem>
  144. <listitem><para><xref linkend="zend.controller.router.routes.chain" /></para></listitem>
  145. <listitem><para><xref linkend="zend.controller.router.default-routes" /> *</para></listitem>
  146. </itemizedlist>
  147. <para>
  148. Routen können unzählige Male verwendet werden um eine Kette oder benutzerdefinierte Routing Schemas
  149. von Anwendungen zu erstellen. Es kann jede beliebige Anzahl von Routen in jeder beliebigen Konfiguration
  150. verwendet werden, mit Ausnahme der Modul Route, welche nur einmal verwendet werden sollte, und
  151. möglicherweise die am meisten standardmäßige Route ist (z.B., als ein Standard). Jede Route wird
  152. später detailiert beschrieben.
  153. </para>
  154. <para>
  155. Der erste Parameter für addRoute ist der Name der Route. Er wird als Handle verwendet um die Route
  156. außerhalb des Routers zu erhalten (z.B. für den Zweck der URL Erzeugung). Der zweite Parameter ist
  157. die Route selbst.
  158. </para>
  159. <note>
  160. <para>
  161. Die gewöhnlichste Verwendung des Namens der Route ist gegeben durch die Zwecke des <classname>Zend_View</classname>
  162. Url Helfers:
  163. </para>
  164. <programlisting role="php"><![CDATA[
  165. <a href=
  166. "<?php echo $this->url(array('username' => 'martel'), 'user') ?>">Martel</a>
  167. ]]>
  168. </programlisting>
  169. <para>
  170. Was zu folgender href führt: <code>user/martel</code>.
  171. </para>
  172. </note>
  173. <para>
  174. Routen ist ein einfacher Prozess des Durchlaufens aller vorhandenen Routen und Vergleichens deren
  175. Definitionen mit der aktuellen Anfrage URI. Wenn ein positiver Vergleich gefunden wird, werden
  176. variable Werte von der Instanz des Routers zurückgegeben, und werden für die spätere Verwendung im
  177. Dispatcher in das <classname>Zend_Controller_Request</classname> Objekt iniziiert, sowie in von Benutzern
  178. erstellten Controllern. Bei einem negativen Ergebnis des Vergleiches, wird die nächste Route in der
  179. Kette geprüft.
  180. </para>
  181. <para>
  182. Wenn man herausfinden will welche Route gepasst hat, kann man die <code>getCurrentRouteName()</code>
  183. Methode verwenden, die den Identifikator zurückgibt der verwendet wurde als die Route im
  184. Router registriert wurde. Wenn man das aktuelle Route Objekt benötigt, kann
  185. <code>getCurrentRoute()</code> verwendet werden.
  186. </para>
  187. <note>
  188. <title>Umgekehrter Vergleich</title>
  189. <para>
  190. Routen werden in umgekehrter Reihenfolge verglichen. Deswegen muß sichergestellt werden das die
  191. generellen Routen zuerst definiert werden.
  192. </para>
  193. </note>
  194. <note>
  195. <title>Zurückgegebene Werte</title>
  196. <para>
  197. Werte die vom Routen zurückgegeben werden kommen von URL Parametern oder Benutzerdefinierten
  198. Router Standards. Diese Variablen sind später durch die
  199. <classname>Zend_Controller_Request::getParam()</classname> oder
  200. <classname>Zend_Controller_Action::_getParam()</classname>Methoden verwendbar.
  201. </para>
  202. </note>
  203. <para>
  204. Es gibt drei spezielle Variablen welche in den Routen verwendet werden können - 'module', 'controller'
  205. und 'action'. Diese speziellen Variablen werden durch <classname>Zend_Controller_Dispatcher</classname> verwendet um
  206. einen Kontroller und die Aktion zu funden zu der verwiesen wird.
  207. </para>
  208. <note>
  209. <title>Spezielle Variablen</title>
  210. <para>
  211. Die Namen dieser speziellen Variablen kann unterschiedlich sein wenn entschieden wird die
  212. Standards in <classname>Zend_Controller_Request_Http</classname> mithilfe der <code>setControllerKey</code>
  213. und <code>setActionKey</code> Methode zu Ändern.
  214. </para>
  215. </note>
  216. </sect2>
  217. <sect2 id="zend.controller.router.default-routes">
  218. <title>Standard Routen</title>
  219. <para>
  220. <classname>Zend_Controller_Router_Rewrite</classname> kommt mit einer Standard Route vorkonfiguriert, welche URIs im Sinn
  221. von <code>controller/action</code> entspricht. Zusätzlich kann ein Modul Name als erstes Pfad Element
  222. definiert werden, welches URIs in der Form von <code>module/controller/action</code> erlaubt.
  223. Letztendlich wird es auch allen zusätzlichen Parametern entsprechen die der URI standardmäßig
  224. hinzugefügt wurden - <code>controller/action/var1/value1/var2/value2</code>.
  225. </para>
  226. <para>
  227. Einige Beispiele wie solche Routen verglichen werden:
  228. </para>
  229. <programlisting role="php"><![CDATA[
  230. // Folgende Annahme:
  231. $ctrl->setControllerDirectory(
  232. array(
  233. 'default' => '/path/to/default/controllers',
  234. 'news' => '/path/to/news/controllers',
  235. 'blog' => '/path/to/blog/controllers'
  236. )
  237. );
  238. Nur Modul:
  239. http://example/news
  240. module == news
  241. Ungültiges Modul, geht an den Controller Namen:
  242. http://example/foo
  243. controller == foo
  244. Modul + Controller:
  245. http://example/blog/archive
  246. module == blog
  247. controller == archive
  248. Modul + Controller + Aktion:
  249. http://example/blog/archive/list
  250. module == blog
  251. controller == archive
  252. action == list
  253. Modul + Controller + Aktion + Parameter:
  254. http://example/blog/archive/list/sort/alpha/date/desc
  255. module == blog
  256. controller == archive
  257. action == list
  258. sort == alpha
  259. date == desc
  260. ]]>
  261. </programlisting>
  262. <para>
  263. Die Standardroute ist einfach ein <classname>Zend_Controller_Router_Route_Module</classname> Objekt welches unter
  264. dem Namen (Index) 'default' im RewriteRouter gespeichert ist. Es wird mehr oder weniger wie folgt
  265. erstellt:
  266. </para>
  267. <programlisting role="php"><![CDATA[
  268. $compat = new Zend_Controller_Router_Route_Module(array(),
  269. $dispatcher,
  270. $request);
  271. $this->addRoute('default', $compat);
  272. ]]>
  273. </programlisting>
  274. <para>
  275. Wenn diese spezielle Standard Route im eigenen Routing Schema nicht gewünscht ist, kann Sie durch
  276. Erstellung einer eigenen 'default' Route überschrieben werden (z.B. durch Speichern unter dem Namen
  277. 'default') oder dem kompletten Entfernen durch verwenden von <code>removeDefaultRoutes()</code>:
  278. </para>
  279. <programlisting role="php"><![CDATA[
  280. // Löschen aller Standard Routen
  281. $router->removeDefaultRoutes();
  282. ]]>
  283. </programlisting>
  284. </sect2>
  285. <sect2 id="zend.controller.router.rewritebase">
  286. <title>Basis URL und Unterverzeichnisse</title>
  287. <para>
  288. Der Rewrite Router kann in Unterverzeichnissen verwendet werden (z.B.
  289. <code>http://domain.com/~user/application-root/</code>) und in diesem Fall sollte die Basis URL der
  290. Anwendung (<code>/~user/application-root</code>) automatisch durch
  291. <classname>Zend_Controller_Request_Http</classname> erkannt und auch verwendet werden.
  292. </para>
  293. <para>
  294. Sollte die Basis URL nicht richtig erkannt werden kann diese mit eigenen Basispfad überschrieben werden
  295. durch Verwendung von <classname>Zend_Controller_Request_Http</classname> und Auruf der <code>setBaseUrl()</code>
  296. Methode (siehe <xref linkend="zend.controller.request.http.baseurl" />):
  297. </para>
  298. <programlisting role="php"><![CDATA[
  299. $request->setBaseUrl('/~user/application-root/');
  300. ]]>
  301. </programlisting>
  302. </sect2>
  303. <sect2 id="zend.controller.router.global.parameters">
  304. <title>Globale Parameter</title>
  305. <para>
  306. Man kann in einem Router globale Parameter setzen die der Route automatisch zur Verfügung stehen
  307. wenn Sie durch <code>setGlobalParam</code> eingefügt werden. Wenn ein globaler Parameter
  308. gesetzt ist, aber auch direkt an die Assemble Methode gegeben wird, überschreibt der
  309. Benutzer-Parameter den Globalen-Parameter. Globale Parameter können auf folgendem Weg gesetzt werden:
  310. </para>
  311. <programlisting role="php"><![CDATA[
  312. $router->setGlobalParam('lang', 'en');
  313. ]]>
  314. </programlisting>
  315. </sect2>
  316. <sect2 id="zend.controller.router.routes">
  317. <title>Router Typen</title>
  318. <xi:include href="Zend_Controller-Router-Route.xml" />
  319. <xi:include href="Zend_Controller-Router-Route-Static.xml" />
  320. <xi:include href="Zend_Controller-Router-Route-Regex.xml" />
  321. <xi:include href="Zend_Controller-Router-Route-Hostname.xml" />
  322. <xi:include href="Zend_Controller-Router-Route-Chain.xml" />
  323. </sect2>
  324. <sect2 id="zend.controller.router.add-config">
  325. <title><classname>Zend_Config</classname> mit dem RewriteRouter verwenden</title>
  326. <para>
  327. Manchmal ist es praktischer, eine Konfigurationsdatei mit neuen Routen zu
  328. aktualisieren, als den Code zu ändern. Dies ist mit Hilfe der
  329. <code>addConfig()</code> Methode möglich. Im Wesentlichen kann man eine
  330. <classname>Zend_Config</classname> kompatible Konfiguration erstellen, in seinem Code einlesen und an den
  331. RewriteRouter übergeben:
  332. </para>
  333. <para>
  334. Als Beispiel wird die folgende INI Datei angenommen:
  335. </para>
  336. <programlisting role="php"><![CDATA[
  337. [production]
  338. routes.archive.route = "archive/:year/*"
  339. routes.archive.defaults.controller = archive
  340. routes.archive.defaults.action = show
  341. routes.archive.defaults.year = 2000
  342. routes.archive.reqs.year = "\d+"
  343. routes.news.type = "Zend_Controller_Router_Route_Static"
  344. routes.news.route = "news"
  345. routes.news.defaults.controller = "news"
  346. routes.news.defaults.action = "list"
  347. routes.archive.type = "Zend_Controller_Router_Route_Regex"
  348. routes.archive.route = "archive/(\d+)"
  349. routes.archive.defaults.controller = "archive"
  350. routes.archive.defaults.action = "show"
  351. routes.archive.map.1 = "year"
  352. ; OR: routes.archive.map.year = 1
  353. ]]>
  354. </programlisting>
  355. <para>
  356. Die oben angeführte INI Datei kann dann wie folgt in ein
  357. <classname>Zend_Config</classname> Objekt eingelesen werden:
  358. </para>
  359. <programlisting role="php"><![CDATA[
  360. $config = new Zend_Config_Ini('/path/to/config.ini', 'production');
  361. $router = new Zend_Controller_Router_Rewrite();
  362. $router->addConfig($config, 'routes');
  363. ]]>
  364. </programlisting>
  365. <para>
  366. Im oberen Beispiel teilen wir dem Router mit, den 'routes' Bereich der INI Datei
  367. für seine Routen zu verwenden. Jeder Schlüssel auf erster Ebene in diesem Bereich
  368. wird verwendet, um den Namen der Routen zu definieren; das obige Beispiel definiert
  369. die Routen 'archive' und 'news'. Jede Route erfordert dann mindestens einen 'route'
  370. Eintrag und einen oder mehrere 'defaults' Einträge; optional können eine oder
  371. mehrere 'reqs' (kurz für 'required', d.h. erforderlich) Einträge angegeben werden.
  372. Alles in allem entspricht dies den drei Argumenten, die an ein
  373. <classname>Zend_Controller_Router_Route_Interface</classname> Objekt übergeben werden. Ein
  374. Optionsschlüssel 'type' kann verwendet werden, um den Typ der Routenklasse für
  375. diese Route anzugeben; standardmäßig wird <classname>Zend_Controller_Router_Route</classname>
  376. verwendet. Im obigen Beispiel wird die 'news' Route definiert, um
  377. <classname>Zend_Controller_Router_Route_Static</classname> zu verwenden.
  378. </para>
  379. </sect2>
  380. <sect2 id="zend.controller.router.subclassing">
  381. <title>Erben vom Router</title>
  382. <para>
  383. Der Standard Rewrite Router sollte die meisten Funktionalitäten die benötigt werden zur Verfügung
  384. stellen; meistens wird es nur notwendig sein einen neuen Router Typen zu erstellen um neue oder
  385. modifizierte Funktionalitäten für die verfügbaren Routen zu bieten.
  386. </para>
  387. <para>
  388. So gesehen, wird man in einigen Fällen ein anderes Routing Paradigma verwenden wollen. Das Interface
  389. <classname>Zend_Controller_Router_Interface</classname> bietet die minimalen Information die benötigt werden um
  390. einen Router er erstellen und besteht aus einer einzigen Methode.
  391. </para>
  392. <programlisting role="php"><![CDATA[
  393. interface Zend_Controller_Router_Interface
  394. {
  395. /**
  396. * @param Zend_Controller_Request_Abstract $request
  397. * @throws Zend_Controller_Router_Exception
  398. * @return Zend_Controller_Request_Abstract
  399. */
  400. public function route(Zend_Controller_Request_Abstract $request);
  401. }
  402. ]]>
  403. </programlisting>
  404. <para>
  405. Das Routing findet nur einmal statt, wenn die Anfrage das erste Mal vom System erhalten
  406. wird. Der Zweck des Routers ist es, Controller, Aktion und optionale Parameter auf Basis
  407. der Anfrageumgebung zu ermitteln und im Request zu setzen. Das Request Objekt wird dann
  408. an den Dispatcher übergeben. Wenn es nicht möglich ist, eine Route auf einen Dispatch
  409. Token abzubilden, soll der Router nichts mit dem Request Objekt machen.
  410. </para>
  411. </sect2>
  412. </sect1>
  413. <!--
  414. vim:se ts=4 sw=4 et:
  415. -->