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