<?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>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 <acronym>URI</acronym> (la parte de la
                <acronym>URI</acronym> que viene después de la
                <acronym>URL</acronym> 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 <acronym>PHP</acronym> puras. Se basa muy vagamente
            en el routing de Ruby on Rails (RoR) y no requiere ningún
            conocimiento previo de reescritura de la <acronym>URL</acronym> 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
                <acronym>IIS</acronym> 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 <acronym>IIS</acronym> ,
                    <varname>$_SERVER['REQUEST_URI']</varname> puede no existir,
                o establecerlo como un string vacío. En este caso,
                    <classname>Zend_Controller_Request_Http</classname>
                intentará usar el valor de
                    <varname>$_SERVER['HTTP_X_REWRITE_URL']</varname>
                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>
                    <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> 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 <acronym>URL</acronym> ). 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 <acronym>URL</acronym>
                <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: <filename>user/martel</filename> .
            </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 <acronym>URI</acronym> . 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
                    <acronym>URL</acronym> o de rutas definidas por defecto por
                el usuario. Estas variables son accesibles posteriormente a
                través de los métodos
                    <methodname>Zend_Controller_Request::getParam()</methodname>
                o <methodname>Zend_Controller_Action::_getParam()</methodname> .
            </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
                <acronym>URI</acronym> s en la forma de
                <filename>controller/action</filename> . Además, se puede
            especificar un nombre de módulo como primer elemento del path,
            permitiendo <acronym>URI</acronym> s de la forma
                <filename>module/controller/action</filename> . Por último,
            también coincidrá con cualquier parámetro adicional agregado a la
                <acronym>URI</acronym> por defecto -
                <filename>controller/action/var1/value1/var2/value2</filename> . </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
                <filename>http://domain.com/~user/application-root/</filename> )
            en cuyo caso la <acronym>URL</acronym> base de la aplicación (
                <filename>/user/application-root</filename> ) debe ser detectada
            automáticamente por
                <classname>Zend_Controller_Request_Http</classname> y usada en
            consecuencia. </para>

        <para> Si la <acronym>URL</acronym> 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 Zend_Config 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
                <acronym>INI</acronym> : </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 <acronym>INI</acronym> 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 <acronym>INI</acronym> 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>
