<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: 17227 -->
<!-- Reviewed: no -->
<sect1 id="zend.controller.router" xmlns:xi="http://www.w3.org/2001/XInclude">
    <title>Routeur Standard</title>

    <sect2 id="zend.controller.router.introduction">
        <title>Introduction</title>

        <para>
            <classname>Zend_Controller_Router_Rewrite</classname> est le routeur par défaut
            du framework. Le routage consiste à analyser l'URI définie (la partie après l'URL de
            base) et la décomposer en valeurs déterminant quels module, contrôleur et action
            doivent recevoir la requête. Ces valeurs sont encapsulées dans un objet de requête
            <classname>Zend_Controller_Request_Http</classname> qui est alors injecté dans
            <classname>Zend_Controller_Dispatcher_Standard</classname> pour y être traité Le
            routage n'est effectué qu'une seule fois par requête&#160;: juste avant que le premier
            contrôleur ne soit traité (distribué)
        </para>

        <para>
            <classname>Zend_Controller_Router_Rewrite</classname> intervient pour fournir un
            environnement de requête similaire à "mod_rewrite", tout en utilisant uniquement du
            <acronym>PHP</acronym>. Il est désigné sur les principes de Ruby on Rails et ne requière pas de
            connaissances particulières en réécriture d'URL. Il est destiné à fonctionner avec une
            seule règle de réécriture Apache, dont voici des exemples&#160;:
        </para>

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

        <para>ou (recommandé) :</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>
            Le routeur de réécriture peut aussi être utilisé avec un serveur Web <acronym>IIS</acronym>
            (versions &lt;= 7.0) si <ulink url="http://www.isapirewrite.com">Isapi_Rewrite</ulink>
            a été installée comme une extension Isap avec la règle suivante&#160;:
        </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>
                Lorsque <acronym>IIS</acronym> est utilisé, <varname>$_SERVER['REQUEST_URI']</varname> n'existera pas
                ou vaudra une chaîne vide. Dans ce cas,
                <classname>Zend_Controller_Request_Http</classname> essaiera d'utiliser la valeur
                de <varname>$_SERVER['HTTP_X_REWRITE_URL']</varname>, initialisée par l'extension
                Isapi_Rewrite.
            </para>
        </note>

        <para>
            <acronym>IIS</acronym> 7.0 introduit un moodule de réécriture d'URL natif, et il peut être configuré
            comme ceci&#160;:
        </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 vous utilisez Lighttpd, la règle de réécriture suivante est valide&#160;:</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>Utilisation d'un routeur</title>

        <para>
            Pour utiliser un routeur et le configurer, vous devez le récupérer et ajouter des
            routes&#160;:
        </para>

        <programlisting language="php"><![CDATA[
/* Créer un routeur */
$router = $frontctrl->getRouter();
// retourne un routeur de réécriture par défaut
$router->addRoute(
    'user',
    new Zend_Controller_Router_Route('user/:username',
                                     array('controller' => 'user',
                                           'action' => 'info'))
);
]]></programlisting>

    </sect2>

    <sect2 id="zend.controller.router.basic">

        <title>Utilisation basique du routeur de réécriture</title>

        <para>
            Le coeur de ce routeur repose sur le concept de routes personnalisées. Les routes
            sont ajoutées en appelant la méthode <methodname>addRoute()</methodname> et en lui passant une
            instance implémentant <classname>Zend_Controller_Router_Route_Interface</classname>.
            Exemple&#160;:
        </para>

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

        <para>
            Le routeur de réécriture est fourni avec six types de route, dont une
            spéciale&#160;:
        </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>
            Chaque route peut être utilisée plusieurs fois pour créer un chaîne de routes
            représentant un schéma de routage personnalisé. La route du module, en revanche, ne
            devrait être utilisée qu'une seule fois, elle est en générale la route la plus
            générique (par défaut). Chaque route sera définie un peu plus tard.
        </para>

        <para>
            Le premier paramètre de <code>addRoute</code> est le nom de la route. Il sera
            utilisé plus tard pour la sélectionner (par exemple pour générer un <acronym>URL</acronym>. Le deuxième
            paramètre étant l'objet route lui-même.
        </para>

        <note>
            <para>
                L'utilisation la plus plausible du nom de la route est illustrée dans l'aide
                vue "url"&#160;:
            </para>
            <programlisting language="php"><![CDATA[
<a href="<?= $this->url(array('username' => 'martel'), 'user') ?>">
Martel
</a>
]]></programlisting>
            <para>Ce qui donnera un "href"&#160;: <code>user/martel</code>.</para>
        </note>

        <para>
            Le routage consiste simplement à itérer toutes les routes reçues et à les faire
            correspondre à l'URI de la requête courante. Dès qu'une correspondance est établie, les
            variables sont injectées dans l'objet <classname>Zend_Controller_Request</classname>
            utilisé après dans le distributeur et dans les contrôleurs. Si aucune correspondance
            n'est trouvée, la route suivante dans la pile est analysée.
        </para>

        <para>
            Si vous devez déterminer quelle route a été trouvée, vous pouvez utilisez la
            méthode <methodname>getCurrentRouteName()</methodname>, qui vous retournera l'identifiant utilisé
            pour enregistrer la route dans le routeur. Si vous souhaitez récupérer l'objet de la
            route actuelle, vous pouvez utiliser <methodname>getCurrentRoute()</methodname>.
        </para>

        <note>
            <title>Pile LIFO</title>
            <para>
                Les routes sont analysées dans l'ordre LIFO : dernière fournie, première
                analysée. Veillez à définir les routes les génériques en premier donc.
            </para>
        </note>

        <note>
            <title>Paramètres de la requête</title>
            <para>
                Les paramètres de la requête proviennent de l'utilisateur, ou des routes
                définies. Ils seront plus tard accessibles via
                <methodname>Zend_Controller_Request::getParam()</methodname> ou la méthode
                <methodname>Zend_Controller_Action::_getParam()</methodname>.
            </para>
        </note>

        <para>
            Il y a trois valeurs spéciales qui peuvent être utilisées dans la définition de
            vos routes&#160;: - "module", "controller" et "action" -. Ces valeurs sont utilisées par
            <classname>Zend_Controller_Dispatcher</classname> pour trouver les contrôleurs et
            action à distribuer.
        </para>

        <note>
            <title>Valeurs spéciales</title>
            <para>
                Le nom de ces valeurs peut être changé dans
                <classname>Zend_Controller_Request_Http</classname> avec les méthodes
                <code>setControllerKey</code> et <code>setActionKey</code>.
            </para>
        </note>

    </sect2>

    <sect2 id="zend.controller.router.default-routes">

        <title>Routes par défaut</title>

        <para>
            Zend_Controller_Router_Rewrite possède des routes par défaut qui vont
            correspondre pour des <acronym>URI</acronym> du type <code>controller/action</code>. De plus, un nom de
            module peut être spécifié comme premier élément du chemin, autorisant ainsi des <acronym>URI</acronym> du
            type <code>module/controller/action</code>. Enfin, chaque paramètres de la requête sera
            trouvé à la fin de la requête, comme
            <code>controller/action/var1/value1/var2/value2</code>.
        </para>

        <para>Exemples avec ces routes&#160;:</para>

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

Module seulement:
http://example/news
    module == news

Un module invalide dirige vers le contrôleur:
http://example/foo
    controller == foo

Module + controller:
http://example/blog/archive
    module     == blog
    controller == archive

Module + controller + action:
http://example/blog/archive/list
    module     == blog
    controller == archive
    action     == list

Module + controller + action + params:
http://example/blog/archive/list/sort/alpha/date/desc
    module     == blog
    controller == archive
    action     == list
    sort       == alpha
    date       == desc
]]></programlisting>

        <para>
            La route par défaut est simplement un objet
            <classname>Zend_Controller_Router_Route_Module</classname>, stocké sous le nom
            "default" dans le routeur de réécriture(RewriteRouter). Il est conçu comme ceci&#160;:
        </para>

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

        <para>
            Si vous ne souhaitez pas cette route par défaut, créez en une et stocker la avec
            le nom "default" (écrasement), ou supprimez la route avec
            <methodname>removeDefaultRoutes()</methodname>&#160;:
        </para>

        <programlisting language="php"><![CDATA[
// Supprime les routes par défaut
$router->removeDefaultRoutes();
]]></programlisting>
    </sect2>

    <sect2 id="zend.controller.router.rewritebase">
        <title>Base URL et sous dossiers</title>

        <para>
            Le routeur de réécriture peut être utilisé dans des sous dossiers (comme
            <code>http://domain.com/~user/application-root/</code>), dans un tél cas, l'URL de base
            de l'application (<code>/~user/application-root</code>) devrait être automatiquement
            détectée par <classname>Zend_Controller_Request_Http</classname> et utilisée
            ensuite.
        </para>

        <para>
            Si ça n'était pas le cas, vous pouvez spécifier votre propre base <acronym>URL</acronym> dans
            <classname>Zend_Controller_Request_Http</classname> en appelant
            <methodname>setBaseUrl()</methodname> (voyez
            <xref linkend="zend.controller.request.http.baseurl" />)&#160;:
        </para>

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

    <sect2 id="zend.controller.router.global.parameters">
        <title>Paramètres globaux</title>

        <para>
            Vous pouvez régler des paramètres globaux dans un routeur, qui sont
            automatiquement fournis à la route lors de son assemblage, grâce à la fonction
            <methodname>setGlobalParam()</methodname>. Si un paramètre global est réglé mais qu'il est aussi
            fourni directement à la méthode d'assemblage, le paramètre utilisateur écrase le
            paramètre global. Vous pouvez régler un paramètre global de cette manière&#160;:
        </para>

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

    <sect2 id="zend.controller.router.routes">
        <title>Types 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">
            <xi:fallback>
                <xi:include href="../../en/module_specs/Zend_Controller-Router-Route-Chain.xml" />
            </xi:fallback>
        </xi:include>
        <xi:include href="Zend_Controller-Router-Route-Rest.xml">
            <xi:fallback>
                <xi:include href="../../en/module_specs/Zend_Controller-Router-Route-Rest.xml" />
            </xi:fallback>
        </xi:include>
    </sect2>

    <sect2 id="zend.controller.router.add-config">
        <title>Utiliser Zend_Config avec le RewriteRouter</title>

        <para>
            Il arrive qu'il soit plus commode d'éditer un fichier de configuration de routes,
            plutôt que d'éditer un code source. Ceci est rendu possible par la méthode
            <methodname>addConfig()</methodname>. Vous créez un objet compatible Zend_Config et vous le passez
            à cette méthode.
        </para>

        <para>Par exemple, voyons un fichier <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"
; OU: routes.archive.map.year = 1
]]></programlisting>

        <para>
            Ce fichier <acronym>INI</acronym> peut être lu dans grâce à un objet <classname>Zend_Config</classname>
            comme suit&#160;:
        </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>
            Nous indiquons au routeur d'utiliser la section "routes" du fichier <acronym>INI</acronym>. Chaque
            clé de premier niveau représente le nom de la route, ainsi nous avons dans l'exemple ci
            dessus "archive" et "news". Chaque route attend alors au moins une entrée "route" avec
            une ou plusieurs entrées "defaults"&#160;; optionnellement nous pouvons rajouter des
            paramètres obligatoires. Tout ceci correspond aux trois arguments fournis par l'objet
            implémentant <classname>Zend_Controller_Router_Route_Interface</classname>. Une entrée
            optionnelle "type" peut être utilisée pour indiquer le type de classe de routage à
            utiliser, il s'agit par défaut de <classname>Zend_Controller_Router_Route</classname>.
            Dans l'exemple au dessus, la route "news" va utiliser
            <classname>Zend_Controller_Router_Route_Static</classname>.
        </para>
    </sect2>

    <sect2 id="zend.controller.router.subclassing">
        <title>Dérivation de l'objet Router</title>

        <para>
            Le routeur par défaut, dit de réécriture, devrait suffire dans la majorité des
            projets. Tout ce qu'il peut être nécessaire de faire, est d'ajouter des routes
            particulières selon vos besoins.
        </para>

        <para>
            Cependant, si vous voulez utiliser votre propre logique de routage, une interface
            est disponible. <classname>Zend_Controller_Router_Interface</classname> ne définit
            qu'une seule méthode&#160;:
        </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>
            Le processus de routage n'intervient qu'une fois : lorsque la requête est reçue
            par le système. Le routeur doit alors déterminer un contrôleur, une action et de
            paramètres optionnel et les spécifier dans un objet de requête, qui est ensuite passé
            au distributeur. Si il n'est pas possible de router une requête, alors l'objet de
            requête devrait être laissé tel-quel.
        </para>
    </sect2>
</sect1>