<?xml version="1.0" encoding="UTF-8"?>
<!-- EN-Revision: 15103 -->
<!-- Reviewed: no -->
<sect1 id="zend.controller.router"  xmlns:xi="http://www.w3.org/2001/XInclude">
    <title>El Router Standard</title>
    <sect2 id="zend.controller.router.introduction">
        <title>Introducción</title>
        <para>
            <classname>Zend_Controller_Router_Rewrite</classname> Es el router 
            standard del Framework. Routing es el proceso de tomar la parte 
            final de una URI (la parte de la URI que viene después de la URL 
            base) y la descomposición en parámetros para determinar qué módulo, 
            qué controlador y acción de ese controlador debe recibir la solicitud. 
            Estos valores del módulo, controlador, acción y otros parámetros 
            están enpaquetados en un objeto 
            <classname>Zend_Controller_Request_Http</classname> el cual es 
            procesado luego por <classname>Zend_Controller_Dispatcher_Standard</classname>. 
            El routing ocurre sólo una vez: cuando se recibió inicialmente la 
            solicitud y antes del dispatch del primer controlador.
        </para>

        <para>
            <classname>Zend_Controller_Router_Rewrite</classname> está diseñado 
            para permitir que una funcionalidad tipo mod_rewrite se pueda usar 
            en estructuras PHP puras. Se basa muy vagamente en el routing de 
            Ruby on Rails (RoR) y no requiere ningún conocimiento previo de 
            reescritura de la URL del webserver. Está diseñado para trabajar 
            con solo una regla mod_rewrite de Apache (one of):
        </para>

         <programlisting language="php"><![CDATA[
RewriteEngine on
RewriteRule !\.(js|ico|gif|jpg|png|css|html)$ index.php
]]></programlisting>

        <para>
            o (preferido):
        </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>
            El router rewrite también puede utilizarse con el IIS webserver (versions &lt;= 7.0) si <ulink
                url="http://www.isapirewrite.com">Isapi_Rewrite</ulink> 
                se ha instalado como una extensión Isapi con la siguiente 
                regla de reescribir:
        </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>
                Cuando se usa IIS, <methodname>$_SERVER['REQUEST_URI']</methodname> puede 
                no existir, o establecerlo como un string vacío. En este caso,
                <classname>Zend_Controller_Request_Http</classname> 
                intentará usar el valor de 
                <methodname>$_SERVER['HTTP_X_REWRITE_URL']</methodname> 
                establecido por la extensión Isapi_Rewrite.
            </para>
        </note>

        <para>
            IIS 7.0 introduce un módulo nativo de reescribir la URL, y puede ser 
            configurado como sigue:
        </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>
            Si está usando Lighttpd, la siguiente regla de reescritura es válida:
        </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>Usando un Router</title>

        <para>
            Para utilizar adecuadamente el router de reescritura debe 
            instanciarlo, agregar algunas rutas definidas por el usuario y 
            luego inyectarlo en el controlador. El siguiente código ilustra el 
            procedimiento:
        </para>

         <programlisting language="php"><![CDATA[
// Crear un 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'))
);
]]></programlisting>
    </sect2>

    <sect2 id="zend.controller.router.basic">
        <title>Operación Básica del Rewrite Router</title>

        <para>
            El corazón del RewriteRouter es la definición de la rutas definidas 
            por el usuario. Las rutas se agregan llamando al método addRoute 
            de RewriteRouter y pasándole una nueva instancia de una clase que 
            implementó a 
            <classname>Zend_Controller_Router_Route_Interface</classname>. Eg.:
        </para>

         <programlisting language="php"><![CDATA[
$router->addRoute('user',
                  new Zend_Controller_Router_Route('user/:username'));
]]></programlisting>

        <para>
            El Rewrite Router viene con seis tipos básicos de rutas (uno de los 
            cuales es especial):
        </para>

        <itemizedlist mark="opencircle">
            <listitem><para><xref linkend="zend.controller.router.routes.standard" /></para></listitem>
            <listitem><para><xref linkend="zend.controller.router.routes.static" /></para></listitem>
            <listitem><para><xref linkend="zend.controller.router.routes.regex" /></para></listitem>
            <listitem><para><xref linkend="zend.controller.router.routes.hostname" /></para></listitem>
            <listitem><para><xref linkend="zend.controller.router.routes.chain" /></para></listitem>
            <listitem><para><xref linkend="zend.controller.router.default-routes" /> *</para></listitem>
        </itemizedlist>

        <para>
            Las rutas pueden ser utilizadas numerosas veces para crear una cadena 
            o un esquema de aplicación de ruteo definido por el usuario.  
            Puede usar cualquier número de rutas en cualquier configuración, 
            con la excepción de la ruta del Módulo, la cual debe ser utilizada 
            una vez y probablemente como la ruta más genérica (es decir, 
            por defecto). Cada ruta se describe en mayor detalle más adelante.
        </para>

        <para>
            El primer parámetro a addRoute es el nombre de la ruta. 
            Se utiliza como un manejador para sacar las rutas del router 
            (por ejemplo, con fines de generación de URL). 
            El segundo parámetro es la ruta misma.
        </para>

        <note>
            <para>
                El uso más común del nombre de ruta es por medio del 
                ayudante de url <classname>Zend_View</classname>:
            </para>

             <programlisting language="php"><![CDATA[
<a href=
"<?php echo $this->url(array('username' => 'martel'), 'user') ?>">Martel</a>
]]></programlisting>

            <para>
                Que resultaría en la href: <methodname>user/martel</methodname>.
            </para>
        </note>

        <para>
            El routing es un simple proceso de iteración a través de todas las 
            rutas provistas y la equiparación de sus definiciones con la petición 
            actual de URI. Cuando se encuentra una concordancia, se devuelven 
            valores de variables desde la instancia Route y se inyecta en el 
            objeto <classname>Zend_Controller_Request</classname>  
            para su posterior utilización en el dispatcher así también como en 
            los controladores creados por el usuario. En caso de no encontrar 
            ninguna concordancia, se comprobará la siguiente ruta en la cadena.
        </para>

        <para>
            Si necesita determinar en qué ruta se encontró una concordancia, 
            puede usar el método <methodname>getCurrentRouteName()</methodname>, que devolverá 
            el identificador usado cuando registró la ruta con el router. 
            Si quiere el objeto de la ruta actual, puede usar 
            <methodname>getCurrentRoute()</methodname>.
        </para>

        <note>
            <title>Matching Inverso</title>
            <para>
                Las rutas están equiparadas en orden inverso para asegurarse 
                que las rutas más genéricas se definan primero.
            </para>
        </note>

        <note>
            <title>Valores Retornados</title>
            <para>
                Los valores retornados del routing provienen de parámetros URL 
                o de rutas definidas por defecto por el usuario. 
                Estas variables son accesibles posteriormente a través de los métodos 
                <classname>Zend_Controller_Request::getParam()</classname> o
                <classname>Zend_Controller_Action::_getParam()</classname>.
            </para>
        </note>

        <para>
            Hay tres variables que pueden utilizarse en las rutas - 'module', 
            'controller' y 'action'. Estas variables especiales son utilizados por 
            <classname>Zend_Controller_Dispatcher</classname> para encontrar un 
            controlador y una acción para hacer el dispatch.
        </para>

        <note>
            <title>Variables Especiales</title>
            <para>
                Los nombres de estas variables especiales pueden ser diferentes 
                si elige alterar los valores por defecto en
                <classname>Zend_Controller_Request_Http</classname> mediante los 
                métodos 
                <methodname>setControllerKey</methodname> y <methodname>setActionKey</methodname>.
            </para>
        </note>

    </sect2>

    <sect2 id="zend.controller.router.default-routes">
        <title>Routes por Defecto</title>

        <para>
            <classname>Zend_Controller_Router_Rewrite</classname> viene 
            preconfigurado con una ruta por defecto, que se comparará con URIs 
            en la forma de <methodname>controller/action</methodname>. 
            Además, se puede especificar un nombre de módulo como primer 
            elemento del path, permitiendo URIs de la forma            
            <methodname>module/controller/action</methodname>. Por último, también coincidrá  
            con cualquier parámetro adicional agregado a la URI por defecto -
            <methodname>controller/action/var1/value1/var2/value2</methodname>.
        </para>

        <para>
            Algunos ejemplos de cómo están equiparadas las rutas:
        </para>

         <programlisting language="php"><![CDATA[
// Asumiendo lo siguiente:
$ctrl->setControllerDirectory(
    array(
        'default' => '/path/to/default/controllers',
        'news'    => '/path/to/news/controllers',
        'blog'    => '/path/to/blog/controllers'
    )
);

Módulo únicamente:
http://example/news
    module == news

Modulo inválido mapea al nombre del controlador:
http://example/foo
    controller == foo

Módulo + controlador:
http://example/blog/archive
    module     == blog
    controller == archive

Módulo + controlador + accción:
http://example/blog/archive/list
    module     == blog
    controller == archive
    action     == list

Módulo + controlador + accción + parámetros:
http://example/blog/archive/list/sort/alpha/date/desc
    module     == blog
    controller == archive
    action     == list
    sort       == alpha
    date       == desc
]]></programlisting>

        <para>
            La ruta por defecto es simplemente un objeto 
            <classname>Zend_Controller_Router_Route_Module</classname> 
            almacenado bajo el nombre de (index) por 'default' en RewriteRouter. 
            Está generado más o menos así:
        </para>

         <programlisting language="php"><![CDATA[
$compat = new Zend_Controller_Router_Route_Module(array(),
                                                  $dispatcher,
                                                  $request);
$this->addRoute('default', $compat);
]]></programlisting>

        <para>
            Si no quiere esta ruta en particular en su esquema por defecto de
            routing, podrá anularla creando su propia ruta por 'defecto'  
            (es decir, almacenar bajo el nombre de 'default') o eliminarla por 
            completo usando <methodname>removeDefaultRoutes()</methodname>:
        </para>

         <programlisting language="php"><![CDATA[
// Eliminar cualquier ruta por defecto
$router->removeDefaultRoutes();
]]></programlisting>

    </sect2>

    <sect2 id="zend.controller.router.rewritebase">
        <title>URL Base y Subdirectorios</title>

        <para>
            El router rewrite puede ser utilizado en subdirectorios (por 
            ejemplo <methodname>http://domain.com/~user/application-root/</methodname>) 
            en cuyo caso la URL base de la aplicación 
            (<methodname>/~user/application-root</methodname>) debe ser detectada 
            automáticamente por <classname>Zend_Controller_Request_Http</classname> 
            y usada en consecuencia.
        </para>

        <para>
            Si la URL base se detecta incorrectamente se la puede anular con su 
            propio path de base usando
            <classname>Zend_Controller_Request_Http</classname> y llamando al 
            método <methodname>setBaseUrl()</methodname> (ver <xref
                linkend="zend.controller.request.http.baseurl" />):
        </para>

         <programlisting language="php"><![CDATA[
$request->setBaseUrl('/~user/application-root/');
]]></programlisting>

    </sect2>

    <sect2 id="zend.controller.router.global.parameters">
        <title>Parámetros Globales</title>

        <para>
            Puede establecer los parámetros globales en un router que se 
            proporcionan automáticamente a una ruta cuando se ensamblasn mediante  
            <methodname>setGlobalParam</methodname>. Si se establece un parámetro global 
            pero también se lo entrega directamente al método de ensamblaje, 
            el parámetro del usuario sobreescribe al parámetro global. 
            Puede establecer un parámetro global esta forma:
        </para>

         <programlisting language="php"><![CDATA[
$router->setGlobalParam('lang', 'en');
]]></programlisting>
    </sect2>

    <sect2 id="zend.controller.router.routes">
        <title>Tipos de Route</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" />
    </sect2>

    <sect2 id="zend.controller.router.add-config">
        <title>Usando <classname>Zend_Config</classname> con RewriteRouter</title>

        <para>
            A veces es más conveniente para actualizar un archivo de 
            configuración con nuevas rutas que modificar el código. 
            Esto es posible a través del método <methodname>addConfig()</methodname>.
            Básicamente, se crea una configuración compatible con 
            <classname>Zend_Config</classname>. 
            Y en su código lo lee y lo pasa a RewriteRouter.
        </para>

        <para>
            Como ejemplo, considere el siguiente archivo INI:
        </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"
; O: routes.archive.map.year = 1
]]></programlisting>

        <para>
            Entonces el archivo INI puede ser leído por un objeto
            <classname>Zend_Config</classname> como sigue:
        </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>
            En el ejemplo de arriba, le decimos el router que utilice la 
            sección 'routes' del archivo INI para utilizarlo en sus rutas. 
            Cada clave de primer nivel en esa sección será utilizada para definir 
            un nombre de ruta; el ejemplo anterior define las rutas 'archive' y 
            'news'. Entonces cada ruta requiere, como mínimo, una entrada a la 
            'ruta' y una o más entradas por 'default'; opcionalmente puede 
            proporcionarse una o más 'reqs' (abreviación de 'required'). 
            Dicho todo esto, estos corresponden a los tres argumentos que se le 
            suministran al objeto 
            <classname>Zend_Controller_Router_Route_Interface</classname>. 
            Puede utilizarse una clave opcional 'type' para especificar el 
            tipo de clase de ruta a utilizar en esa ruta en particular; 
            por defecto, usa 
            <classname>Zend_Controller_Router_Route</classname>. 
            En el ejemplo de arriba, la ruta 'news' está definida para usar 
            <classname>Zend_Controller_Router_Route_Static</classname>.
        </para>
    </sect2>

    <sect2 id="zend.controller.router.subclassing">
        <title>Subclassing del Router</title>

        <para>
            El standard rewrite router debería proporcionarle más funcionalidad 
            si la necesita; más a menudo, sólo necesitará crear un nuevo 
            tipo de ruta a fin de ofrecer funcionalidades nuevas o modificadas  
            sobre las tutas provistas.
        </para>

        <para>
            Dicho esto, en algún momento puede encontrarse a si mismo deseando 
            usar un paradigma diferente de routing. La intefaz  
            <classname>Zend_Controller_Router_Interface</classname> proporciona 
            la información mínima necesaria para crear un router, y consiste en 
            un único método.
        </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>
            El routing sólo ocurre una vez: cuando la petición es recibida por 
            primera vez en el sistema. El propósito del router es determinar el 
            controlador, la acción, y los parámetros opcionales sobre la base 
            del medio ambiente de la solicitud, y luego ajustarlos en la solicitud. 
            El objeto solicitud se pasa entonces al dispatcher. 
            Si no es posible trazar una ruta hacia un dispatch token, 
            el router no debe hacer nada con el objeto solicitud.
        </para>
    </sect2>
</sect1>
<!--
vim:se ts=4 sw=4 et:
-->
