1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- EN-Revision: 18940 -->
4 <sect1 id="zend.controller.router" xmlns:xi="http://www.w3.org/2001/XInclude">
5 <title>El Router Standard</title>
6 <sect2 id="zend.controller.router.introduction">
7 <title>Introducción</title>
9 <classname>Zend_Controller_Router_Rewrite</classname> Es el router
10 standard del Framework. Routing es el proceso de tomar la parte
11 final de una <acronym>URI</acronym> (la parte de la
12 <acronym>URI</acronym> que viene después de la
13 <acronym>URL</acronym> base) y la descomposición en parámetros
14 para determinar qué módulo, qué controlador y acción de ese
15 controlador debe recibir la solicitud. Estos valores del módulo,
16 controlador, acción y otros parámetros están enpaquetados en un
17 objeto <classname>Zend_Controller_Request_Http</classname> el cual
18 es procesado luego por
19 <classname>Zend_Controller_Dispatcher_Standard</classname> . El
20 routing ocurre sólo una vez: cuando se recibió inicialmente la
21 solicitud y antes del dispatch del primer controlador. </para>
24 <classname>Zend_Controller_Router_Rewrite</classname> está diseñado
25 para permitir que una funcionalidad tipo mod_rewrite se pueda usar
26 en estructuras <acronym>PHP</acronym> puras. Se basa muy vagamente
27 en el routing de Ruby on Rails (RoR) y no requiere ningún
28 conocimiento previo de reescritura de la <acronym>URL</acronym> del
29 webserver. Está diseñado para trabajar con solo una regla
30 mod_rewrite de Apache (one of): </para>
32 <programlisting language="php"><![CDATA[
34 RewriteRule !\.(js|ico|gif|jpg|png|css|html)$ index.php
37 <para> o (preferido): </para>
39 <programlisting language="php"><![CDATA[
41 RewriteCond %{REQUEST_FILENAME} -s [OR]
42 RewriteCond %{REQUEST_FILENAME} -l [OR]
43 RewriteCond %{REQUEST_FILENAME} -d
44 RewriteRule ^.*$ - [NC,L]
45 RewriteRule ^.*$ index.php [NC,L]
48 <para> El router rewrite también puede utilizarse con el
49 <acronym>IIS</acronym> webserver (versions <= 7.0) si
50 <ulink url="http://www.isapirewrite.com">Isapi_Rewrite</ulink>
51 se ha instalado como una extensión Isapi con la siguiente regla de
54 <programlisting language="php"><![CDATA[
55 RewriteRule ^[\w/\%]*(?:\.(?!(?:js|ico|gif|jpg|png|css|html)$)[\w\%]*$)? /index.php [I]
59 <title>IIS Isapi_Rewrite</title>
60 <para> Cuando se usa <acronym>IIS</acronym> ,
61 <varname>$_SERVER['REQUEST_URI']</varname> puede no existir,
62 o establecerlo como un string vacío. En este caso,
63 <classname>Zend_Controller_Request_Http</classname>
64 intentará usar el valor de
65 <varname>$_SERVER['HTTP_X_REWRITE_URL']</varname>
66 establecido por la extensión Isapi_Rewrite. </para>
69 <para> IIS 7.0 introduce un módulo nativo de reescribir la URL, y puede
70 ser configurado como sigue: </para>
72 <programlisting language="xml"><![CDATA[
73 <?xml version="1.0" encoding="UTF-8"?>
78 <rule name="Imported Rule 1" stopProcessing="true">
80 <conditions logicalGrouping="MatchAny">
81 <add input="{REQUEST_FILENAME}"
82 matchType="IsFile" pattern=""
84 <add input="{REQUEST_FILENAME}"
85 matchType="IsDirectory"
86 pattern="" ignoreCase="false" />
88 <action type="None" />
90 <rule name="Imported Rule 2" stopProcessing="true">
92 <action type="Rewrite" url="index.php" />
97 </configuration>]></programlisting>
100 Si está usando Lighttpd, la siguiente regla de reescritura es válida:
103 <programlisting language="lighttpd"><![CDATA[
105 ".*\?(.*)$" => "/index.php?$1",
106 ".*\.(js|ico|gif|jpg|png|css|html)$" => "$0",
112 <sect2 id="zend.controller.router.usage">
113 <title>Usando un Router</title>
115 <para> Para utilizar adecuadamente el router de reescritura debe
116 instanciarlo, agregar algunas rutas definidas por el usuario y luego
117 inyectarlo en el controlador. El siguiente código ilustra el
118 procedimiento: </para>
120 <programlisting language="php"><![CDATA[
123 $router = $ctrl->getRouter(); // returns a rewrite router by default
126 new Zend_Controller_Router_Route('user/:username',
127 array('controller' => 'user',
133 <sect2 id="zend.controller.router.basic">
134 <title>Operación Básica del Rewrite Router</title>
136 <para> El corazón del RewriteRouter es la definición de la rutas
137 definidas por el usuario. Las rutas se agregan llamando al método
138 addRoute de RewriteRouter y pasándole una nueva instancia de una
139 clase que implementó a
140 <classname>Zend_Controller_Router_Route_Interface</classname> .
143 <programlisting language="php"><![CDATA[
144 $router->addRoute('user',
145 new Zend_Controller_Router_Route('user/:username'));
148 <para> El Rewrite Router viene con seis tipos básicos de rutas (uno de
149 los cuales es especial): </para>
151 <itemizedlist mark="opencircle">
154 <link linkend="zend.controller.router.routes.standard"
155 >Zend_Controller_Router_Route</link>
160 <link linkend="zend.controller.router.routes.static"
161 >Zend_Controller_Router_Route_Static</link>
166 <link linkend="zend.controller.router.routes.regex"
167 >Zend_Controller_Router_Route_Regex</link>
172 <link linkend="zend.controller.router.routes.hostname"
173 >Zend_Controller_Router_Route_Hostname</link>
178 <link linkend="zend.controller.router.routes.chain"
179 >Zend_Controller_Router_Route_Chain</link>
184 <link linkend="zend.controller.router.default-routes"
185 >Zend_Controller_Router_Rewrite</link> * </para>
189 <para> Las rutas pueden ser utilizadas numerosas veces para crear una
190 cadena o un esquema de aplicación de ruteo definido por el usuario.
191 Puede usar cualquier número de rutas en cualquier configuración, con
192 la excepción de la ruta del Módulo, la cual debe ser utilizada una
193 vez y probablemente como la ruta más genérica (es decir, por
194 defecto). Cada ruta se describe en mayor detalle más adelante. </para>
196 <para> El primer parámetro a addRoute es el nombre de la ruta. Se
197 utiliza como un manejador para sacar las rutas del router (por
198 ejemplo, con fines de generación de <acronym>URL</acronym> ). El
199 segundo parámetro es la ruta misma. </para>
202 <para> El uso más común del nombre de ruta es por medio del ayudante
203 de <acronym>URL</acronym>
204 <classname>Zend_View</classname> : </para>
206 <programlisting language="php"><![CDATA[
208 "<?php echo $this->url(array('username' => 'martel'), 'user') ?>">Martel</a>
211 <para> Que resultaría en la href: <filename>user/martel</filename> .
215 <para> El routing es un simple proceso de iteración a través de todas
216 las rutas provistas y la equiparación de sus definiciones con la
217 petición actual de <acronym>URI</acronym> . Cuando se encuentra una
218 concordancia, se devuelven valores de variables desde la instancia
219 Route y se inyecta en el objeto
220 <classname>Zend_Controller_Request</classname> para su posterior
221 utilización en el dispatcher así también como en los controladores
222 creados por el usuario. En caso de no encontrar ninguna
223 concordancia, se comprobará la siguiente ruta en la cadena. </para>
225 <para> Si necesita determinar en qué ruta se encontró una concordancia,
226 puede usar el método <methodname>getCurrentRouteName()</methodname>
227 , que devolverá el identificador usado cuando registró la ruta con
228 el router. Si quiere el objeto de la ruta actual, puede usar
229 <methodname>getCurrentRoute()</methodname> . </para>
232 <title>Matching Inverso</title>
233 <para> Las rutas están equiparadas en orden inverso para asegurarse
234 que las rutas más genéricas se definan primero. </para>
238 <title>Valores Retornados</title>
239 <para> Los valores retornados del routing provienen de parámetros
240 <acronym>URL</acronym> o de rutas definidas por defecto por
241 el usuario. Estas variables son accesibles posteriormente a
242 través de los métodos
243 <methodname>Zend_Controller_Request::getParam()</methodname>
244 o <methodname>Zend_Controller_Action::_getParam()</methodname> .
248 <para> Hay tres variables que pueden utilizarse en las rutas - 'module',
249 'controller' y 'action'. Estas variables especiales son utilizados
250 por <classname>Zend_Controller_Dispatcher</classname> para encontrar
251 un controlador y una acción para hacer el dispatch. </para>
254 <title>Variables Especiales</title>
255 <para> Los nombres de estas variables especiales pueden ser
256 diferentes si elige alterar los valores por defecto en
257 <classname>Zend_Controller_Request_Http</classname> mediante
258 los métodos <methodname>setControllerKey()</methodname> y
259 <methodname>setActionKey()</methodname> . </para>
264 <sect2 id="zend.controller.router.default-routes">
265 <title>Routes por Defecto</title>
268 <classname>Zend_Controller_Router_Rewrite</classname> viene
269 preconfigurado con una ruta por defecto, que se comparará con
270 <acronym>URI</acronym> s en la forma de
271 <filename>controller/action</filename> . Además, se puede
272 especificar un nombre de módulo como primer elemento del path,
273 permitiendo <acronym>URI</acronym> s de la forma
274 <filename>module/controller/action</filename> . Por último,
275 también coincidrá con cualquier parámetro adicional agregado a la
276 <acronym>URI</acronym> por defecto -
277 <filename>controller/action/var1/value1/var2/value2</filename> . </para>
279 <para> Algunos ejemplos de cómo están equiparadas las rutas: </para>
281 <programlisting language="php"><![CDATA[
282 // Asumiendo lo siguiente:
283 $ctrl->setControllerDirectory(
285 'default' => '/path/to/default/controllers',
286 'news' => '/path/to/news/controllers',
287 'blog' => '/path/to/blog/controllers'
295 Modulo inválido mapea al nombre del controlador:
299 Módulo + controlador:
300 http://example/blog/archive
302 controller == archive
304 Módulo + controlador + accción:
305 http://example/blog/archive/list
307 controller == archive
310 Módulo + controlador + accción + parámetros:
311 http://example/blog/archive/list/sort/alpha/date/desc
313 controller == archive
319 <para> La ruta por defecto es simplemente un objeto
320 <classname>Zend_Controller_Router_Route_Module</classname>
321 almacenado bajo el nombre de (index) por 'default' en RewriteRouter.
322 Está generado más o menos así: </para>
324 <programlisting language="php"><![CDATA[
325 $compat = new Zend_Controller_Router_Route_Module(array(),
328 $this->addRoute('default', $compat);
331 <para> Si no quiere esta ruta en particular en su esquema por defecto de
332 routing, podrá anularla creando su propia ruta por 'defecto' (es
333 decir, almacenar bajo el nombre de 'default') o eliminarla por
334 completo usando <methodname>removeDefaultRoutes()</methodname> : </para>
336 <programlisting language="php"><![CDATA[
337 // Eliminar cualquier ruta por defecto
338 $router->removeDefaultRoutes();
343 <sect2 id="zend.controller.router.rewritebase">
344 <title>URL Base y Subdirectorios</title>
346 <para> El router rewrite puede ser utilizado en subdirectorios (por
348 <filename>http://domain.com/~user/application-root/</filename> )
349 en cuyo caso la <acronym>URL</acronym> base de la aplicación (
350 <filename>/user/application-root</filename> ) debe ser detectada
352 <classname>Zend_Controller_Request_Http</classname> y usada en
353 consecuencia. </para>
355 <para> Si la <acronym>URL</acronym> base se detecta incorrectamente se
356 la puede anular con su propio path de base usando
357 <classname>Zend_Controller_Request_Http</classname> y llamando
358 al método <methodname>setBaseUrl()</methodname> (ver <xref
359 linkend="zend.controller.request.http.baseurl"/> ): </para>
361 <programlisting language="php"><![CDATA[
362 $request->setBaseUrl('/~user/application-root/');
367 <sect2 id="zend.controller.router.global.parameters">
368 <title>Parámetros Globales</title>
370 <para> Puede establecer los parámetros globales en un router que se
371 proporcionan automáticamente a una ruta cuando se ensamblasn
372 mediante <methodname>setGlobalParam()</methodname> . Si se establece
373 un parámetro global pero también se lo entrega directamente al
374 método de ensamblaje, el parámetro del usuario sobreescribe al
375 parámetro global. Puede establecer un parámetro global esta forma: </para>
377 <programlisting language="php"><![CDATA[
378 $router->setGlobalParam('lang', 'en');
382 <sect2 id="zend.controller.router.routes">
383 <title>Tipos de Route</title>
384 <xi:include href="Zend_Controller-Router-Route.xml"/>
385 <xi:include href="Zend_Controller-Router-Route-Static.xml"/>
386 <xi:include href="Zend_Controller-Router-Route-Regex.xml"/>
387 <xi:include href="Zend_Controller-Router-Route-Hostname.xml"/>
388 <xi:include href="Zend_Controller-Router-Route-Chain.xml"/>
391 <sect2 id="zend.controller.router.add-config">
392 <title> Usando Zend_Config con RewriteRouter </title>
394 <para> A veces es más conveniente para actualizar un archivo de
395 configuración con nuevas rutas que modificar el código. Esto es
396 posible a través del método <methodname>addConfig()</methodname> .
397 Básicamente, se crea una configuración compatible con
398 <classname>Zend_Config</classname> . Y en su código lo lee y lo
399 pasa a RewriteRouter. </para>
401 <para> Como ejemplo, considere el siguiente archivo
402 <acronym>INI</acronym> : </para>
404 <programlisting language="php"><![CDATA[
406 routes.archive.route = "archive/:year/*"
407 routes.archive.defaults.controller = archive
408 routes.archive.defaults.action = show
409 routes.archive.defaults.year = 2000
410 routes.archive.reqs.year = "\d+"
412 routes.news.type = "Zend_Controller_Router_Route_Static"
413 routes.news.route = "news"
414 routes.news.defaults.controller = "news"
415 routes.news.defaults.action = "list"
417 routes.archive.type = "Zend_Controller_Router_Route_Regex"
418 routes.archive.route = "archive/(\d+)"
419 routes.archive.defaults.controller = "archive"
420 routes.archive.defaults.action = "show"
421 routes.archive.map.1 = "year"
422 ; O: routes.archive.map.year = 1
425 <para> Entonces el archivo <acronym>INI</acronym> puede ser leído por un
426 objeto <classname>Zend_Config</classname> como sigue: </para>
428 <programlisting language="php"><![CDATA[
429 $config = new Zend_Config_Ini('/path/to/config.ini', 'production');
430 $router = new Zend_Controller_Router_Rewrite();
431 $router->addConfig($config, 'routes');
434 <para> En el ejemplo de arriba, le decimos el router que utilice la
435 sección 'routes' del archivo <acronym>INI</acronym> para utilizarlo
436 en sus rutas. Cada clave de primer nivel en esa sección será
437 utilizada para definir un nombre de ruta; el ejemplo anterior define
438 las rutas 'archive' y 'news'. Entonces cada ruta requiere, como
439 mínimo, una entrada a la 'ruta' y una o más entradas por 'default';
440 opcionalmente puede proporcionarse una o más 'reqs' (abreviación de
441 'required'). Dicho todo esto, estos corresponden a los tres
442 argumentos que se le suministran al objeto
443 <classname>Zend_Controller_Router_Route_Interface</classname> .
444 Puede utilizarse una clave opcional 'type' para especificar el tipo
445 de clase de ruta a utilizar en esa ruta en particular; por defecto,
446 usa <classname>Zend_Controller_Router_Route</classname> . En el
447 ejemplo de arriba, la ruta 'news' está definida para usar
448 <classname>Zend_Controller_Router_Route_Static</classname> .
452 <sect2 id="zend.controller.router.subclassing">
453 <title>Subclassing del Router</title>
455 <para> El standard rewrite router debería proporcionarle más
456 funcionalidad si la necesita; más a menudo, sólo necesitará crear un
457 nuevo tipo de ruta a fin de ofrecer funcionalidades nuevas o
458 modificadas sobre las tutas provistas. </para>
460 <para> Dicho esto, en algún momento puede encontrarse a si mismo
461 deseando usar un paradigma diferente de routing. La intefaz
462 <classname>Zend_Controller_Router_Interface</classname>
463 proporciona la información mínima necesaria para crear un router, y
464 consiste en un único método. </para>
466 <programlisting language="php"><![CDATA[
467 interface Zend_Controller_Router_Interface
470 * @param Zend_Controller_Request_Abstract $request
471 * @throws Zend_Controller_Router_Exception
472 * @return Zend_Controller_Request_Abstract
474 public function route(Zend_Controller_Request_Abstract $request);
478 <para> El routing sólo ocurre una vez: cuando la petición es recibida
479 por primera vez en el sistema. El propósito del router es determinar
480 el controlador, la acción, y los parámetros opcionales sobre la base
481 del medio ambiente de la solicitud, y luego ajustarlos en la
482 solicitud. El objeto solicitud se pasa entonces al dispatcher. Si no
483 es posible trazar una ruta hacia un dispatch token, el router no
484 debe hacer nada con el objeto solicitud. </para>