# Routeur Standard

## Introduction

Zend_Controller_Router_Rewrite 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 Zend_Controller_Request_Http qui est alors injecté dans Zend_Controller_Dispatcher_Standard pour y être traité Le routage n'est effectué qu'une seule fois par requête : juste avant que le premier contrôleur ne soit traité (distribué)

Zend_Controller_Router_Rewrite intervient pour fournir un environnement de requête similaire à "mod_rewrite", tout en utilisant uniquement du PHP. 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 :

    RewriteEngine on
    RewriteRule !\.(js|ico|gif|jpg|png|css|html)$ index.php

ou (recommandé) :

    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} -s [OR]
    RewriteCond %{REQUEST_FILENAME} -l [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^.*$ - [NC,L]
    RewriteRule ^.*$ index.php [NC,L]

Le routeur de réécriture peut aussi être utilisé avec un serveur Web IIS (versions <= 7.0) si Isapi_Rewrite a été installée comme une extension Isap avec la règle suivante :

    RewriteRule ^[\w/\%]*(?:\.(?!(?:js|ico|gif|jpg|png|css|html)$)[\w\%]*$)? /index.php [I]

IIS Isapi_Rewrite

Lorsque IIS est utilisé, `$_SERVER['REQUEST_URI']` n'existera pas ou vaudra une chaîne vide. Dans ce cas, Zend_Controller_Request_Http essaiera d'utiliser la valeur de `$_SERVER['HTTP_X_REWRITE_URL']`, initialisée par l'extension Isapi_Rewrite.

IIS 7.0 introduit un moodule de réécriture d'URL natif, et il peut être configuré comme ceci :

    <?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>

Si vous utilisez Lighttpd, la règle de réécriture suivante est valide :

    url.rewrite-once = (
        ".*\?(.*)$" => "/index.php?$1",
        ".*\.(js|ico|gif|jpg|png|css|html)$" => "$0",
        "" => "/index.php"
    )

## Utilisation d'un routeur

Pour utiliser un routeur et le configurer, vous devez le récupérer et ajouter des routes :

    /* 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'))
    );

## Utilisation basique du routeur de réécriture

Le coeur de ce routeur repose sur le concept de routes personnalisées. Les routes sont ajoutées en appelant la méthode addRoute() et en lui passant une instance implémentant Zend_Controller_Router_Route_Interface. Exemple :

    $router->addRoute('user',
                      new Zend_Controller_Router_Route('user/:username'));

Le routeur de réécriture est fourni avec six types de route, dont une spéciale :

- Zend_Controller_Router_Route

- Zend_Controller_Router_Route_Static

- Zend_Controller_Router_Route_Regex

- Zend_Controller_Router_Route_Hostname

- Zend_Controller_Router_Route_Chain

- Zend_Controller_Router_Rewrite *

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.

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

L'utilisation la plus plausible du nom de la route est illustrée dans l'aide vue "url" :

    <a href="<?php echo $this->url(array('username' => 'martel'), 'user') ?>">
    Martel
    </a>

Ce qui donnera un "href" : `user/martel`.

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 Zend_Controller_Request 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.

Si vous devez déterminer quelle route a été trouvée, vous pouvez utilisez la méthode getCurrentRouteName(), 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 getCurrentRoute().

Pile LIFO

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.

Paramètres de la requête

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

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

Valeurs spéciales

Le nom de ces valeurs peut être changé dans Zend_Controller_Request_Http avec les méthodes `setControllerKey` et `setActionKey`.

## Routes par défaut

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

Exemples avec ces routes :

    // 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

La route par défaut est simplement un objet Zend_Controller_Router_Route_Module, stocké sous le nom "default" dans le routeur de réécriture(RewriteRouter). Il est conçu comme ceci :

    $compat = new Zend_Controller_Router_Route_Module(array(),
                                                      $dispatcher,
                                                      $request);
    $this->addRoute('default', $compat);

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 removeDefaultRoutes() :

    // Supprime les routes par défaut
    $router->removeDefaultRoutes();

## Base URL et sous dossiers

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

Si ça n'était pas le cas, vous pouvez spécifier votre propre base URL dans Zend_Controller_Request_Http en appelant setBaseUrl() (voyez Base de l'URL et sous-dossiers) :

    $request->setBaseUrl('/~user/application-root/');

## Paramètres globaux

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 setGlobalParam(). 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 :

    $router->setGlobalParam('lang', 'en');

## Types de route

## Utiliser Zend_Config avec le RewriteRouter

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 addConfig(). Vous créez un objet compatible Zend_Config et vous le passez à cette méthode.

Par exemple, voyons un fichier INI :

    [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

Ce fichier INI peut être lu dans grâce à un objet Zend_Config comme suit :

    $config = new Zend_Config_Ini('/path/to/config.ini', 'production');
    $router = new Zend_Controller_Router_Rewrite();
    $router->addConfig($config, 'routes');

Nous indiquons au routeur d'utiliser la section "routes" du fichier INI. 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" ; optionnellement nous pouvons rajouter des paramètres obligatoires. Tout ceci correspond aux trois arguments fournis par l'objet implémentant Zend_Controller_Router_Route_Interface. 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 Zend_Controller_Router_Route. Dans l'exemple au dessus, la route "news" va utiliser Zend_Controller_Router_Route_Static.

## Dérivation de l'objet Router

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.

Cependant, si vous voulez utiliser votre propre logique de routage, une interface est disponible. Zend_Controller_Router_Interface ne définit qu'une seule méthode :

    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);
    }

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.