Browse Source

Added some french doc for tutorials

git-svn-id: http://framework.zend.com/svn/framework/standard/trunk@20652 44c647ce-9c0f-0410-b52a-842ac1e357ba
doctorrock83 16 years ago
parent
commit
cd79084c39

+ 20 - 0
documentation/manual/fr/tutorials/autoloading-conclusion.xml

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- EN-Revision: 20573 -->
+<!-- Reviewed: no -->
+<sect1 id="learning.autoloading.conclusion">
+    <title>Conclusion</title>
+
+    <para>
+        Zend Framework encourage l'utilisation de l'auto-chargement, et l'initialise même par
+        défaut dans <classname>Zend_Application</classname>. Nous espérons que ce tutoriel vous
+        a apporté toutes les informations sur l'utilisation de
+        <classname>Zend_Loader_Autoloader</classname>, ainsi que sur son extension pour ajouter
+        des autochargeurs personnalisés.
+    </para>
+
+    <para>
+        Pour plus d'informations sur son utilisation, lisez les sections du manuel sur <link
+            linkend="zend.loader.autoloader">Zend_Loader_Autoloader</link> et <link
+            linkend="zend.loader.autoloader-resource">Zend_Loader_Autoloader_Resource</link>.
+    </para>
+</sect1>

+ 109 - 0
documentation/manual/fr/tutorials/autoloading-design.xml

@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- EN-Revision: 20573 -->
+<!-- Reviewed: no -->
+<sect1 id="learning.autoloading.design">
+    <title>Architecture et buts</title>
+
+    <sect2 id="learning.autoloading.design.naming">
+        <title>Convention de noms des classes</title>
+
+        <para>
+            Pour comprendre l'autochargement dans le Zend Framework, vous devez d'abord comprendre
+            la relation entre nom de classe et nom de fichier.
+        </para>
+
+        <para>
+            Zend Framework a emprunté une idée de <ulink url="http://pear.php.net/">PEAR</ulink>,
+            dans lequel les noms des classes ont une relation 1:1 avec le système de fichiers.
+            Simplement, le caractère underscore ("_") est remplacé par un séparateur de dossier
+            pour résoudre le chemin vers le fichier, puis le suffixe "<filename>.php</filename>"
+            est ajouté. Par exemple, une classe "<classname>Foo_Bar_Baz</classname>" va
+            correspondre à "<filename>Foo/Bar/Baz.php</filename>" sur le système de fichiers.
+            La supposition est alors que <acronym>PHP</acronym> résoudra les fichier relativement
+            à l'<property>include_path</property> ce qui permet d'utiliser
+            <methodname>include()</methodname> et <methodname>require()</methodname> pour chercher
+            le fichier relativement à l'<property>include_path</property>.
+        </para>
+
+        <para>
+            Aussi, conformément à <acronym>PEAR</acronym> et au <ulink
+                url="http://php.net/userlandnaming.tips">PHP project</ulink>, nous utilisons et
+            vous recommandons d'utiliser un préfixe à votre code. Cela signifie que toutes les
+            classes que vous écrivez doivent partager un préfixe unique, par exemple, dans
+            Zend Framework le préfixe est "Zend_". Cette convention de noms évite toute collision
+            dans les noms des classes. Dans Zend Framework, nous utilisons la notion "d'espace de
+            noms" ("namespace"); attention à éviter la confusion avec l'implémentation native
+            des espaces de noms de <acronym>PHP</acronym>.
+        </para>
+
+        <para>
+            Zend Framework suit ces règles simples en interne et nos standards de code
+            vous encouragent à faire de même avec le code de vos propres librairies.
+        </para>
+    </sect2>
+
+    <sect2 id="learning.autoloading.design.autoloader">
+        <title>Conventions et architecture d'Autoload</title>
+
+        <para>
+            Le support de l'autochargement (autoload) de Zend Framework, implémenté grâce à
+            <classname>Zend_Loader_Autoloader</classname>, possède l'architecture et les
+            buts suivants:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <emphasis>Correspondance d'espace de noms</emphasis>. Si l'espace de noms
+                    de la classe (son préfixe) n'est pas dans une liste pré-enregistrée, retourner
+                    <constant>FALSE</constant> immédiatement. Ceci permet une optimisation de la
+                    recherche ainsi que l'utilisation d'autres autoloaders ou d'un autoloader
+                    global par défaut.
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    <emphasis>Permettre un auto-chargement "de secours"</emphasis>.
+                    Dans le cas où l'on ne peut lister ou prédéterminer les préfixes de manière
+                    claire et sûre, l'autoloader doit pouvoir être configuré pour charger n'importe
+                    quel espace de noms de classes. Notez que ce cas n'est pas recommandé car il
+                    fait intervenir des algorithmes complexes et non optimisés.
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    <emphasis>Permettre la non-suppression des erreurs</emphasis>. Nous pensons
+                     -- et la plus grande partie de la communauté <acronym>PHP</acronym> aussi --
+                    que la suppression des erreurs est une mauvaise idée. C'est couteux en
+                    ressources et cela masque les problèmes réels de l'application. Ainsi, par
+                    défaut, la suppression des erreurs devrait être désactivée. Cependant, si
+                    un développeur <emphasis>insiste</emphasis> pour l'activer, nous le permettons.
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    <emphasis>Autoriser l'utilisation de fonctions d'autoload personnalisées</emphasis>.
+                    Certaines personnes ne veulent pas utiliser
+                    <methodname>Zend_Loader::loadClass()</methodname> pour l'autoload, mais veulent
+                    tout de même bénéficier des mécanismes du Zend Framework.
+                    <classname>Zend_Loader_Autoloader</classname> permet de préciser ses propres
+                    fonctions d'auto-chargement.
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    <emphasis>Permettre la manipulation de la chaine des autoloads de la
+                    <acronym>SPL</acronym></emphasis>. Ceci autorise la spécification
+                    d'autoloaders additionnels -- par exemple les chargeurs de ressources
+                    pour les classes n'ayant pas une correspondance 1:1 avec le système de
+                    fichiers -- ces autoloaders pouvant être chargés avant ou après
+                    l'autoloader principal de Zend Framework.
+                </para>
+            </listitem>
+        </itemizedlist>
+    </sect2>
+</sect1>

+ 34 - 0
documentation/manual/fr/tutorials/autoloading-intro.xml

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- EN-Revision: 20573 -->
+<!-- Reviewed: no -->
+<sect1 id="learning.autoloading.intro">
+    <title>Introduction</title>
+
+    <para>
+        L'auto-chargement est un mécanisme qui élimine les inclusions de dépendances manuelles
+        au sein du code <acronym>PHP</acronym>. Le <ulink url="http://php.net/autoload">manuel sur
+        l'autoload en PHP</ulink>précise qu'une fois qu'un autoloader a été défini, "il est
+        appelé automatiquement dans le cas où l'on tente d'utiliser une classe ou une interface
+        qui n'a pas encore été définie"
+    </para>
+
+    <para>
+        En utilisant l'auto-chargement, vous n'avez pas besoin de vous inquiéter
+        <emphasis>du lieu</emphasis> où la classe existe au sein du projet. Avec des autoloaders
+        bien définis, la résolution du fichier contenant la classe utilisée sera effectuée de
+        manière transparente.
+    </para>
+
+    <para>
+        Aussi, l'autoloader chargeant la classe uniquement lorsque celle-ci est strictement nécessaire,
+        ceci peut avoir des effets très positifs sur les performances globales -- particulièrement
+        si vous prenez soin de supprimer tous les appels à <methodname>require_once()</methodname>
+        avant votre déploiement.
+    </para>
+
+    <para>
+        Zend Framework encourage l'utilisation de l'auto-chargement et propose différents outils pour
+        charger le code des librairies comme celui de l'application. Ce tutoriel couvre ces outils
+        et la manière de les utiliser efficacement.
+    </para>
+</sect1>

+ 109 - 0
documentation/manual/fr/tutorials/autoloading-resources.xml

@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- EN-Revision: 20573 -->
+<!-- Reviewed: no -->
+<sect1 id="learning.autoloading.resources">
+    <title>Auto-chargement de resources</title>
+
+    <para>
+        En développant des applications, il est souvent difficile de regrouper certaines classes
+        dans une relation 1:1 avec le système de fichiers que recommande le Zend framework, ou alors
+        ça ne semble pas intuitif de le faire. Cela signifie que les classes ne seront pas trouvées
+        par l'autoloader.
+    </para>
+
+    <para>
+        Si vous lisez <link linkend="learning.autoloading.design">les caractéristiques de l'architecture
+        </link> de l'autoloader, le dernier point de cette section indique qu'une solution existe pour
+        un tel problème. Zend Framework utilise alors <classname>Zend_Loader_Autoloader_Resource
+        </classname>.
+    </para>
+
+    <para>
+        Une ressource est juste un nom qui correspond à un espace de noms pour un composant
+        (qui est ajouté à l'espace de noms de l'autoloader) et un chemin (qui est relatif au
+        chemin de base de l'autoloader). Sous forme de code, vous feriez quelque chose comme:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+$loader = new Zend_Application_Module_Autoloader(array(
+    'namespace' => 'Blog',
+    'basePath'  => APPLICATION_PATH . '/modules/blog',
+));
+]]></programlisting>
+
+    <para>
+        Une fois le chargeur en place, il faut l'informer des différents types de ressources
+        qu'il va avoir à gérer. Ces types sont simplement des paires d'arbres et de préfixes.
+    </para>
+
+    <para>
+        Considérons ce qui suit comme exemple:
+    </para>
+
+    <programlisting language="text"><![CDATA[
+path/to/some/resources/
+|-- forms/
+|   `-- Guestbook.php        // Foo_Form_Guestbook
+|-- models/
+|   |-- DbTable/
+|   |   `-- Guestbook.php    // Foo_Model_DbTable_Guestbook
+|   |-- Guestbook.php        // Foo_Model_Guestbook
+|   `-- GuestbookMapper.php  // Foo_Model_GuestbookMapper
+]]></programlisting>
+
+    <para>
+        Le premier reflexe est de créer un chargeur de ressources:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+$loader = new Zend_Loader_Autoloader_Resource(array(
+    'basePath'  => 'path/to/some/resources/',
+    'namespace' => 'Foo',
+));
+]]></programlisting>
+
+    <para>
+        Puis, nous définissons des types de ressources.
+        <methodname>Zend_Loader_Autoloader_Resourse::addResourceType()</methodname> prend trois
+        arguments: le "type" de resource (une chaine arbitraire), le chemin sous le chemin de base
+        dans lequel le type de ressource doit se trouver, et le préfixe particulier à utiliser pour
+        ce type de ressource. Dans l'arbre représenté ci-dessus, il y a trois types : form
+        (dans le sous-dossier "forms", avec un préfixe "Form"), model (dans le sous-dossier "models",
+        avec un préfixe "Model"), et dbtable (dans le sous-dossier
+        "<filename>models/DbTable</filename>", avec un préfixe "<classname>Model_DbTable</classname>").
+        Nous les définirons comme ceci:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+$loader->addResourceType('form', 'forms', 'Form')
+       ->addResourceType('model', 'models', 'Model')
+       ->addResourceType('dbtable', 'models/DbTable', 'Model_DbTable');
+]]></programlisting>
+
+    <para>
+        Il ne reste plus qu'à utiliser les classes:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+$form      = new Foo_Form_Guestbook();
+$guestbook = new Foo_Model_Guestbook();
+]]></programlisting>
+
+    <note>
+        <title>Autoload de ressource Module</title>
+
+        <para>
+            La couche <acronym>MVC</acronym> de Zend Framework encourage l'utilisation de "modules",
+            qui sont des mini-applications de votre site. Les modules possèdent typiquement des
+            types de ressource par défaut, et Zend Framework
+            <link linkend="project-structure.filesystem">recommande une hiérarchie de répertoires
+            standard pour les modules</link>. Les autoloaders de ressources sont particulièrement
+            adaptés à cette situation -- tellement qu'ils sont activés par défaut lorsque vous créez
+            des classes de bootstrap qui étendent
+            <classname>Zend_Application_Module_Bootstrap</classname>. Pour plus d'informations, lisez
+            la <link
+                linkend="zend.loader.autoloader-resource.module">documentation de
+                Zend_Loader_Autoloader_Module</link>.
+        </para>
+    </note>
+</sect1>

+ 164 - 0
documentation/manual/fr/tutorials/autoloading-usage.xml

@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- EN-Revision: 20573 -->
+<!-- Reviewed: no -->
+<sect1 id="learning.autoloading.usage">
+    <title>Utilisation de base de l'autoloader</title>
+
+    <para>
+        Maintenant que vous savez les buts et le fonctionnement des autoloaders de
+        Zend Framework, voyons comment utiliser <classname>Zend_Loader_Autoloader</classname>.
+    </para>
+
+    <para>
+        Dans le cas le plus simple, vous incluez cette classe et l'instanciez. Comme
+        <classname>Zend_Loader_Autoloader</classname> est un singleton (car l'autoloader de la
+        <acronym>SPL</acronym> est unique), nous utilisons
+        <methodname>getInstance()</methodname> pour en récupérer l'instance.
+    </para>
+
+    <programlisting language="php"><![CDATA[
+require_once 'Zend/Loader/Autoloader.php';
+Zend_Loader_Autoloader::getInstance();
+]]></programlisting>
+
+    <para>
+        Par défaut, ceci va permettre de charger des classes dont le préfixe est
+        "Zend_" ou "ZendX_", si leurs fichiers sont dans votre <property>include_path</property>.
+    </para>
+
+    <para>
+        Que se passe-t-il si vous avez d'autres espaces de noms à charger? Le mieux et le plus simple
+        est alors d'utiliser la méthode <methodname>registerNamespace()</methodname> de l'instance.
+        Vous pouvez lui passer un préfixe simple, ou un tableau de préfixes:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+require_once 'Zend/Loader/Autoloader.php';
+$loader = Zend_Loader_Autoloader::getInstance();
+$loader->registerNamespace('Foo_');
+$loader->registerNamespace(array('Foo_', 'Bar_'));
+]]></programlisting>
+
+    <para>
+        Aussi, vous pouvez indiquer à <classname>Zend_Loader_Autoloader</classname> d'agire comme
+        autoloader par défaut ("de secours"). Ceci signifie qu'il essayera de charger toute classe
+        peu importe son préfixe.
+    </para>
+
+    <programlisting language="php"><![CDATA[
+$loader->setFallbackAutoloader(true);
+]]></programlisting>
+
+    <warning>
+        <title>N'utilisez pas l'autoloader de secours</title>
+
+        <para>
+            Ce peut être tentant de se reposer abondamment sur
+            <classname>Zend_Loader_Autoloader</classname> comme chargeur de secours, nous ne
+            recommandons pas une telle pratique.
+        </para>
+
+        <para>
+            En interne, <classname>Zend_Loader_Autoloader</classname> utilise
+            <methodname>Zend_Loader::loadClass()</methodname> pour charger les classes. Cette
+            méthode utilise <methodname>include()</methodname> pour tenter de charger le fichier
+            de la classe. <methodname>include()</methodname> retourne <constant>FALSE</constant>
+            s'il ne réussi pas -- mais renvoie aussi un warning <acronym>PHP</acronym>. Ce dernier
+            point peut mener à des problèmes:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    Si <property>display_errors</property> est activé, le warning sera inclus dans
+                    la sortie (l'affichage).
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    Selon le niveau de <property>error_reporting</property>, le warning pourra aussi
+                    déclencher l'écriture dans les journaux d'évènements.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Vous pouvez supprimer les messages d'erreur (la documentation de
+            <classname>Zend_Loader_Autoloader</classname> détaille cela), mais notez bien que la
+            suppression n'est utilisée que lorsque <property>display_errors</property> est activé;
+            le journal des évènements enregistrera toujours l'erreur. Pour ces raisons, nous vous
+            recommandons de bien configurer vos espaces de noms avec l'autoloader.
+        </para>
+    </warning>
+
+    <note>
+        <title>Préfixes d'espaces de nom et espaces de noms PHP</title>
+
+        <para>
+            A l'heure de l'écriture de ces lignes, <acronym>PHP</acronym> 5.3 est sorti. Avec
+            cette version, <acronym>PHP</acronym> supporte maintenant officiellement les espaces
+            de noms.
+        </para>
+
+        <para>
+            Cependant, Zend Framework date d'avant <acronym>PHP</acronym> 5.3, et donc les espaces
+            de noms PHP. Dans Zend Framework, lorsque nous parlons "d'espace de noms", nous parlons
+            d'une pratique consistant à préfixer le nom de la classe par un préfixe. Par exemple,
+            toutes les classes de Zend Framework commencent par "Zend_" -- c'est notre espace de
+            noms.
+        </para>
+
+        <para>
+            Zend Framework projette de supporter nativement les espaces de noms <acronym>PHP</acronym>
+            pour l'autoloader dans les versions futures. Il utilisera aussi ce support en interne, à
+            partir de la version 2.0.0.
+        </para>
+    </note>
+
+    <para>
+        Si vous possédez votre propre autoloader et que vous voulez l'utiliser avec Zend Framework
+        -- peut être un autoloader provenant d'une autre librairie que vous utilisez -- vous pouvez
+        l'enregistrer grâce aux méthodes de <classname>Zend_Loader_Autoloader</classname>
+        <methodname>pushAutoloader()</methodname> et <methodname>unshiftAutoloader()</methodname>.
+        Ces méthodes ajoutent des autoloaders à la fin ou au début de la chaine utilisée avant
+        l'exécution des mecanismes internes d'auto-chargement de Zend Framewor. Cette approche a
+        les avantages suivants:
+    </para>
+
+    <itemizedlist>
+        <listitem>
+            <para>
+                Chaque méthode prend un deuxième paramètre : un espace de noms qui indique que
+                l'autoloader passé ne doit être utilisé que pour charger des classes dans cet
+                espace de noms là. Si la classe n'est pas dans cet espace de noms, l'autoloader
+                sera alors ignoré, ce qui peut amener à des optimisations de performance.
+            </para>
+        </listitem>
+
+        <listitem>
+            <para>
+                Si vous devez manipuler le registre de <methodname>spl_autoload()</methodname>,
+                prenez garde si vous préciser des fonctions de rappels sous forme de méthodes de
+                classes car <methodname>spl_autoload_functions()</methodname> ne retourne pas
+                exactement leurs définitions. <classname>Zend_Loader_Autoloader</classname>
+                ne souffre pas de ce problème.
+            </para>
+        </listitem>
+    </itemizedlist>
+
+    <para>
+        Voici une liste de définitions de fonctions de rappel pour auto-chargement valides en
+        <acronym>PHP</acronym>.
+    </para>
+
+    <programlisting language="php"><![CDATA[
+// Ajoute à la suite de la pile la fonction 'my_autoloader',
+// pour charger des classes commençant par 'My_':
+$loader->pushAutoloader('my_autoloader', 'My_');
+
+// Ajoute au début de la pile une méthode statique Foo_Loader::autoload(),
+// pour charger des classes commençant par 'Foo_':
+$loader->unshiftAutoloader(array('Foo_Loader', 'autoload'), 'Foo_');
+]]></programlisting>
+</sect1>

+ 387 - 0
documentation/manual/fr/tutorials/form-decorators-composite.xml

@@ -0,0 +1,387 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- EN-Revision: 20573 -->
+<!-- Reviewed: no -->
+<sect1 id="learning.form.decorators.composite">
+    <title>Créer et rendre des éléments composites</title>
+
+    <para>
+        Dans <link linkend="learning.form.decorators.individual">la dernière section</link>, nous
+        avions un exemple traitant un élément "date de naissance":
+    </para>
+
+
+    <programlisting language="php"><![CDATA[
+<div class="element">
+    <?php echo $form->dateOfBirth->renderLabel() ?>
+    <?php echo $this->formText('dateOfBirth[day]', '', array(
+        'size' => 2, 'maxlength' => 2)) ?>
+    /
+    <?php echo $this->formText('dateOfBirth[month]', '', array(
+        'size' => 2, 'maxlength' => 2)) ?>
+    /
+    <?php echo $this->formText('dateOfBirth[year]', '', array(
+        'size' => 4, 'maxlength' => 4)) ?>
+</div>
+]]></programlisting>
+
+    <para>
+        Comment représenteriez-vous cet élément en tant que
+        <classname>Zend_Form_Element</classname>?
+        Comment écrire un décorateur qui s'assure de son rendu ?
+    </para>
+
+    <sect2 id="learning.form.decorators.composite.element">
+        <title>L'élément</title>
+
+        <para>
+            Les questions à se poser sur le fonctionnement de l'élément sont:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    Comment affecter et récupérer une valeur?
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    Comment valider la valeur?
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    Comment proposer l'affectation personnalisée d'une valeur composées de trois
+                    segments (jour, mois, année)?
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Les deux première questions se positionnent sur l'élément de formulaire lui-même, comment
+            vont fonctionner les méthodes <methodname>setValue()</methodname> et
+            <methodname>getValue()</methodname>?
+            L'autre question nous suggère de nous questionner sur comment récupérer les segments
+            représentant la date, ou comment les affecter dans l'élément?
+        </para>
+
+        <para>
+            La solution est de surcharger la méthode <methodname>setValue()</methodname> dans l'élément
+             pour proposer sa propre logique. Dans le cas de notre exemple, notre élément devrait avoir
+             trois comportements distincts:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    Si un timestamp entier est utilisé, il doit aider à la détermination des entités
+                    jour, mois, année.
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    Si une chaine est utilisée, elle devrait être transformée en timestamp, et cette valeur
+                    sera utiliser pour déterminer les entités jour, mois, année.
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    Si un tableau contenant les clés jour, mois, année est utilisé, alors les valeurs
+                    doivent être stockées.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            En interne, les jour, mois et année seront stockés distinctement. Lorsque la valeur de l'élément
+            sera demandée, nous récupèrerons une chaine formatée et normalisée. Nous surchargerons
+            <methodname>getValue()</methodname> pour assembler les segments élémentaires composant la date.
+        </para>
+
+        <para>
+            Voici à quoi ressemblerait la classe:
+        </para>
+
+        <programlisting language="php"><![CDATA[
+class My_Form_Element_Date extends Zend_Form_Element_Xhtml
+{
+    protected $_dateFormat = '%year%-%month%-%day%';
+    protected $_day;
+    protected $_month;
+    protected $_year;
+
+    public function setDay($value)
+    {
+        $this->_day = (int) $value;
+        return $this;
+    }
+
+    public function getDay()
+    {
+        return $this->_day;
+    }
+
+    public function setMonth($value)
+    {
+        $this->_month = (int) $value;
+        return $this;
+    }
+
+    public function getMonth()
+    {
+        return $this->_month;
+    }
+
+    public function setYear($value)
+    {
+        $this->_year = (int) $value;
+        return $this;
+    }
+
+    public function getYear()
+    {
+        return $this->_year;
+    }
+
+    public function setValue($value)
+    {
+        if (is_int($value)) {
+            $this->setDay(date('d', $value))
+                 ->setMonth(date('m', $value))
+                 ->setYear(date('Y', $value));
+        } elseif (is_string($value)) {
+            $date = strtotime($value);
+            $this->setDay(date('d', $date))
+                 ->setMonth(date('m', $date))
+                 ->setYear(date('Y', $date));
+        } elseif (is_array($value)
+                  && (isset($value['day'])
+                      && isset($value['month'])
+                      && isset($value['year'])
+                  )
+        ) {
+            $this->setDay($value['day'])
+                 ->setMonth($value['month'])
+                 ->setYear($value['year']);
+        } else {
+            throw new Exception('Valeur de date invalide');
+        }
+
+        return $this;
+    }
+
+    public function getValue()
+    {
+        return str_replace(
+            array('%year%', '%month%', '%day%'),
+            array($this->getYear(), $this->getMonth(), $this->getDay()),
+            $this->_dateFormat
+        );
+    }
+}
+]]></programlisting>
+
+        <para>
+            Cette classe est fléxible : nous pouvons affecter les valeurs par défaut depuis une base de
+            données et être certains qu'elles seront stockées correctement. Aussi, la valeur peut être
+            affectée depuis un tableau provenant des entrées du formulaire. Enfin, nous avons tous les
+            accesseurs distincts pour chaque segment de la date, un décorateur pourra donc créer
+            l'élément comme il le voudra.
+        </para>
+    </sect2>
+
+    <sect2 id="learning.form.decorators.composite.decorator">
+        <title>Le décorateur</title>
+
+        <para>
+            Toujours en suivant notre exemple, imaginons que nous voulions que notre utilisateur
+            saisissent chaque segment jour, mois, année séparément. Heureusement, PHP permet
+            d'utiliser la notation tableau pour créer des éléments, ainsi nous pourrons capturer
+            ces trois valeurs en une seule et nous crérons un élément
+            <classname>Zend_Form</classname> traitant avec des valeurs en tableau.
+        </para>
+
+        <para>
+            Le décorateur est relativement simple: Il va récupérer le jour, le mois et l'année de
+            l'élément et passer chaque valeur à une aide de vue qui rendra chaque champ
+            individuellement. Nous les rassemblerons ensuite dans le rendu final.
+        </para>
+
+        <programlisting language="php"><![CDATA[
+class My_Form_Decorator_Date extends Zend_Form_Decorator_Abstract
+{
+    public function render($content)
+    {
+        $element = $this->getElement();
+        if (!$element instanceof My_Form_Element_Date) {
+            // Nous ne rendons que des éléments Date
+            return $content;
+        }
+
+        $view = $element->getView();
+        if (!$view instanceof Zend_View_Interface) {
+            // Nous utilisons des aides de vue, si aucune vue n'existe
+            // nous ne rendons rien
+            return $content;
+        }
+
+        $day   = $element->getDay();
+        $month = $element->getMonth();
+        $year  = $element->getYear();
+        $name  = $element->getFullyQualifiedName();
+
+        $params = array(
+            'size'      => 2,
+            'maxlength' => 2,
+        );
+        $yearParams = array(
+            'size'      => 4,
+            'maxlength' => 4,
+        );
+
+        $markup = $view->formText($name . '[day]', $day, $params)
+                . ' / ' . $view->formText($name . '[month]', $month, $params)
+                . ' / ' . $view->formText($name . '[year]', $year, $yearParams);
+
+        switch ($this->getPlacement()) {
+            case self::PREPEND:
+                return $markup . $this->getSeparator() . $content;
+            case self::APPEND:
+            default:
+                return $content . $this->getSeparator() . $markup;
+        }
+    }
+}
+]]></programlisting>
+
+    <para>
+        Il faut maintenant préciser à notre élément d'utiliser notre décorateur par défaut.
+        Pour ceci, il faut informer l'élément du chemin vers notre décorateur. Nous pouvons
+        effectuer ceci par le constructeur:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+class My_Form_Element_Date extends Zend_Form_Element_Xhtml
+{
+    // ...
+
+    public function __construct($spec, $options = null)
+    {
+        $this->addPrefixPath(
+            'My_Form_Decorator',
+            'My/Form/Decorator',
+            'decorator'
+        );
+        parent::__construct($spec, $options);
+    }
+
+    // ...
+}
+]]></programlisting>
+
+    <para>
+        Notez que l'on fait cela en constructeur et non dans la méthode <methodname>init()</methodname>.
+        Ceci pour deux raisons. D'abord, ceci permet d'étendre dans le futur notre élément afin d'y
+        ajouter de la logique dans <methodname>init</methodname> sans se soucier de l'appel à
+        <methodname>parent::init()</methodname>. Ensuite, celà permet aussi de redéfinir le décorateur
+        par défaut <classname>Date</classname> dans le futur si celà devient nécessaire, via le
+        constructeur ou la méthode <methodname>init</methodname>.
+    </para>
+
+    <para>
+        Ensuite, nous devons réécrire la méthode <methodname>loadDefaultDecorators()</methodname> pour
+        lui indiquer d'utiliser notre décorateur <classname>Date</classname>:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+class My_Form_Element_Date extends Zend_Form_Element_Xhtml
+{
+    // ...
+
+    public function loadDefaultDecorators()
+    {
+        if ($this->loadDefaultDecoratorsIsDisabled()) {
+            return;
+        }
+
+        $decorators = $this->getDecorators();
+        if (empty($decorators)) {
+            $this->addDecorator('Date')
+                 ->addDecorator('Errors')
+                 ->addDecorator('Description', array(
+                     'tag'   => 'p',
+                     'class' => 'description'
+                 ))
+                 ->addDecorator('HtmlTag', array(
+                     'tag' => 'dd',
+                     'id'  => $this->getName() . '-element'
+                 ))
+                 ->addDecorator('Label', array('tag' => 'dt'));
+        }
+    }
+
+    // ...
+}
+]]></programlisting>
+
+    <para>
+        A qyuoi ressemble le rendu final ? Considérons l'élément suivant:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+$d = new My_Form_Element_Date('dateOfBirth');
+$d->setLabel('Date de naissance: ')
+  ->setView(new Zend_View());
+
+// Ces deux procédés sont équivalents:
+$d->setValue('20 April 2009');
+$d->setValue(array('year' => '2009', 'month' => '04', 'day' => '20'));
+]]></programlisting>
+
+    <para>
+        Si vous affichez cet élément, vous obtiendrez ce rendu (avec quelques modifications
+        concernant la mise en page du manuel et sa lisibilité):
+    </para>
+
+    <programlisting language="html"><![CDATA[
+<dt id="dateOfBirth-label"><label for="dateOfBirth" class="optional">
+    Date de naissance:
+</label></dt>
+<dd id="dateOfBirth-element">
+    <input type="text" name="dateOfBirth[day]" id="dateOfBirth-day"
+        value="20" size="2" maxlength="2"> /
+    <input type="text" name="dateOfBirth[month]" id="dateOfBirth-month"
+        value="4" size="2" maxlength="2"> /
+    <input type="text" name="dateOfBirth[year]" id="dateOfBirth-year"
+        value="2009" size="4" maxlength="4">
+</dd>
+]]></programlisting>
+    </sect2>
+
+    <sect2 id="learning.form.decorators.composite.conclusion">
+        <title>Conclusion</title>
+
+        <para>
+            Nous avons maintenant un élément qui peut rendre de multiples champs de formulaire,
+            et les traiter comme une seule entité -- la valeur <varname>dateOfBirth</varname>
+            sera passée comme un tableau à l'élément et celui-ci créra les segments de date
+            appropriés et retournera une valeur normalisée.
+        </para>
+
+        <para>
+            Aussi, nous pouvons toujours utiliser des décorateurs différents avec l'élément. Si
+            nous avions voulu utiliser un décorateur
+            <ulink url="http://dojotoolkit.org/">Dojo</ulink> <classname>DateTextBox</classname>
+            -- qui accepte et retourne des chaines -- we aurions pu, sans modification sur
+            l'élément lui-même.
+        </para>
+
+        <para>
+            Enfin, vous avez une API uniforme pour décrire un élement se composant se plusieurs
+            segments distincts.
+        </para>
+    </sect2>
+</sect1>

+ 13 - 0
documentation/manual/fr/tutorials/form-decorators-conclusion.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- EN-Revision: 20573 -->
+<!-- Reviewed: no -->
+<sect1 id="learning.form.decorators.conclusion">
+    <title>Conclusion</title>
+
+    <para>
+        Les décorateur de formulaire sont un système qui peut prendre du temps à maitriser.
+        A première vue, ils semblent complexes et rudes. Mais les différents sujets traités
+        dans ce chapitre vous aident à comprendre leur fonctionnement et vous montrent des
+        manières de faire pour les utiliser efficacement dans vos formulaires.
+    </para>
+</sect1>

+ 284 - 0
documentation/manual/fr/tutorials/form-decorators-individual.xml

@@ -0,0 +1,284 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- EN-Revision: 20573 -->
+<!-- Reviewed: no -->
+<sect1 id="learning.form.decorators.individual">
+    <title>Rendu individuel des décorateurs</title>
+
+    <para>
+        Dans la <link linkend="learning.form.decorators.layering">section précédente</link>, nous
+        avons vu comment combiner les décorateurs afin de créer un rendu complexe. Ceci est très fléxible
+        mais rajoute tout de même un part de compléxité à l'ensemble. Dans ce chapitre, nous allons
+        inspecter le rendu individuel des décorateurs afin de créer du contenu visuel pour des
+        formulaires ou des éléments.
+    </para>
+
+    <para>
+        Une fois des décorateurs enregistrés, vous pouvez les récupérer via leur nom depuis l'élément.
+        Revoyons l'exemple précédent:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+$element = new Zend_Form_Element('foo', array(
+    'label'      => 'Foo',
+    'belongsTo'  => 'bar',
+    'value'      => 'test',
+    'prefixPath' => array('decorator' => array(
+        'My_Decorator' => 'path/to/decorators/',
+    )),
+    'decorators' => array(
+        'SimpleInput'
+        array('SimpleLabel', array('placement' => 'append')),
+    ),
+));
+]]></programlisting>
+
+    <para>
+        Si nous voulons récupérer le décorateur <classname>SimpleInput</classname>, nous passons
+        par la méthode <methodname>getDecorator()</methodname>:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+$decorator = $element->getDecorator('SimpleInput');
+echo $decorator->render('');
+]]></programlisting>
+
+    <para>
+        C'est simple et ça peut l'être encore plus; ré-écrivons le tout sur une seule ligne:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+echo $element->getDecorator('SimpleInput')->render('');
+]]></programlisting>
+
+    <para>
+        Pas mauvais, mais toujours un peu compliqué. Pour simplifier, une notation raccourcie a été
+        introduite dans <classname>Zend_Form</classname> en 1.7: vous pouvez rendre n'importe quel
+        décorateur enregistré en appelant une méthode de la forme
+        <methodname>renderDecoratorName()</methodname>.
+        Ceci effectue le rendu et fait en sorte que <varname>$content</varname> soit optionnel ce qui
+        simplifie l'utilisation:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+echo $element->renderSimpleInput();
+]]></programlisting>
+
+    <para>
+        C'est une simplification astucieuse, mais comment et pourquoi l'utiliser?
+    </para>
+
+    <para>
+        Beaucoup de développeurs ont des besoins très précis en affichage des formulaires. Ils préfèrent
+        avoir un contrôle complet sur tout l'affichage plutôt que d'utiliser une solution automatisée
+        qui peut s'écarter de leur but initial. Dans d'autres cas, les formulaires peuvent demander
+        un affichage extrêmement spécifique, en groupant des éléments alors que d'autres doivent
+        pouvoir être invisibles avant que l'on n'effectue telle action sur la page, etc.
+    </para>
+
+    <para>
+        Utilisons la possibilité de rendre un seul décorateur pour créer un affichage précis.
+    </para>
+
+    <para>
+        D'abord, définissons un formulaire. Celui-ci récupèrera des détails démographiques sur l'utilisateur.
+        Le rendu sera hautement personnalisé et dans certains cas il utilisera les aides de vue directement
+        plutôt que les éléments. Voici une définition simple du formulaire:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+class My_Form_UserDemographics extends Zend_Form
+{
+    public function init()
+    {
+        // Ajoute un chemin pour les décorateurs personnalisés
+        $this->addElementPrefixPaths(array(
+            'decorator' => array('My_Decorator' => 'My/Decorator'),
+        ));
+
+        $this->addElement('text', 'firstName', array(
+            'label' => 'First name: ',
+        ));
+        $this->addElement('text', 'lastName', array(
+            'label' => 'Last name: ',
+        ));
+        $this->addElement('text', 'title', array(
+            'label' => 'Title: ',
+        ));
+        $this->addElement('text', 'dateOfBirth', array(
+            'label' => 'Date of Birth (DD/MM/YYYY): ',
+        ));
+        $this->addElement('text', 'email', array(
+            'label' => 'Your email address: ',
+        ));
+        $this->addElement('password', 'password', array(
+            'label' => 'Password: ',
+        ));
+        $this->addElement('password', 'passwordConfirmation', array(
+            'label' => 'Confirm Password: ',
+        ));
+    }
+}
+]]></programlisting>
+
+    <note>
+        <para>
+            Nous n'utilisons pas de validateurs ou de filtres ici, car ils n'ont rien à voir avec le
+            rendu visuel qui nous interesse. En réalité, il y en aurait.
+        </para>
+    </note>
+
+    <para>
+        Maintenant réfléchissons au rendu visuel du formulaire. Une communalité concernant les nom
+        et prénom est qu'on les affiche l'un à coté de l'autre, à coté de leur titre, si présent.
+        Les dates, si elles n'utilisent pas Javascript, affichent souvent des champs séparés pour
+        chaque segment de la date.
+    </para>
+
+    <para>
+        Utilisons la possibilité de rendre des décorateurs un par un pour accomplir notre tâche.
+        D'abord, notez qu'aucun décorateur spécifique n'a été renseigné dans les éléments.
+        Rappelons donc les décorateurs par défaut de la plupart des éléments:
+    </para>
+
+    <itemizedlist>
+        <listitem>
+            <para>
+                <classname>ViewHelper</classname>: utilise une aide de vue pour rendre l'élément
+                balise de formulaire à proprement parlé.
+            </para>
+        </listitem>
+
+        <listitem>
+            <para>
+                <classname>Errors</classname>: utilise l'aide de vue <classname>FormErrors</classname>
+                pour afficher les erreurs de validation éventuelles.
+            </para>
+        </listitem>
+
+        <listitem>
+            <para>
+                <classname>Description</classname>: utilise l'aide de vue <classname>FormNote</classname>
+                afin de rendre la description éventuelle de l'élément.
+            </para>
+        </listitem>
+
+        <listitem>
+            <para>
+                <classname>HtmlTag</classname>: encapsule les trois objets ci-dessus dans un tag
+                <code>&lt;dd&gt;</code>.
+            </para>
+        </listitem>
+
+        <listitem>
+            <para>
+                <classname>Label</classname>: rend l'intitulé de l'élément en utilisant l'aide de vue
+                <classname>FormLabel</classname> (et en encapsulant le tout dans un tag
+                <code>&lt;dt&gt;</code>).
+            </para>
+        </listitem>
+    </itemizedlist>
+
+    <para>
+        Nous vous rappelons aussi que vous pouvez accéder à tout élément individuellement en tant
+        qu'attribut du formulaire représentant son nom.
+    </para>
+
+    <para>
+        Notre script de vue ressemblerait à cela:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+<?php
+$form = $this->form;
+// Enlève le <dt> depuis l'intitulé
+foreach ($form->getElements() as $element) {
+    $element->getDecorator('label')->setOption('tag', null);
+}
+?>
+<form method="<?php echo $form->getMethod() ?>" action="<?php echo
+    $form->getAction()?>">
+    <div class="element">
+        <?php echo $form->title->renderLabel()
+              . $form->title->renderViewHelper() ?>
+        <?php echo $form->firstName->renderLabel()
+              . $form->firstName->renderViewHelper() ?>
+        <?php echo $form->lastName->renderLabel()
+              . $form->lastName->renderViewHelper() ?>
+    </div>
+    <div class="element">
+        <?php echo $form->dateOfBirth->renderLabel() ?>
+        <?php echo $this->formText('dateOfBirth[day]', '', array(
+            'size' => 2, 'maxlength' => 2)) ?>
+        /
+        <?php echo $this->formText('dateOfBirth[month]', '', array(
+            'size' => 2, 'maxlength' => 2)) ?>
+        /
+        <?php echo $this->formText('dateOfBirth[year]', '', array(
+            'size' => 4, 'maxlength' => 4)) ?>
+    </div>
+    <div class="element">
+        <?php echo $form->password->renderLabel()
+              . $form->password->renderViewHelper() ?>
+    </div>
+    <div class="element">
+        <?php echo $form->passwordConfirmation->renderLabel()
+              . $form->passwordConfirmation->renderViewHelper() ?>
+    </div>
+    <?php echo $this->formSubmit('submit', 'Save') ?>
+</form>
+]]></programlisting>
+
+    <para>
+        Si vous utilisez le script ci-dessus, vous verrez un code HTML ressemblant à ceci:
+    </para>
+
+    <programlisting language="html"><![CDATA[
+<form method="post" action="">
+    <div class="element">
+        <label for="title" tag="" class="optional">Title:</label>
+        <input type="text" name="title" id="title" value=""/>
+
+        <label for="firstName" tag="" class="optional">First name:</label>
+        <input type="text" name="firstName" id="firstName" value=""/>
+
+        <label for="lastName" tag="" class="optional">Last name:</label>
+        <input type="text" name="lastName" id="lastName" value=""/>
+    </div>
+
+    <div class="element">
+        <label for="dateOfBirth" tag="" class="optional">Date of Birth
+            (DD/MM/YYYY):</label>
+        <input type="text" name="dateOfBirth[day]" id="dateOfBirth-day"
+            value="" size="2" maxlength="2"/>
+        /
+        <input type="text" name="dateOfBirth[month]" id="dateOfBirth-month"
+            value="" size="2" maxlength="2"/>
+        /
+        <input type="text" name="dateOfBirth[year]" id="dateOfBirth-year"
+            value="" size="4" maxlength="4"/>
+    </div>
+
+    <div class="element">
+        <label for="password" tag="" class="optional">Password:</label>
+        <input type="password" name="password" id="password" value=""/>
+    </div>
+
+    <div class="element">
+        <label for="passwordConfirmation" tag="" class="" id="submit"
+            value="Save"/>
+</form>
+]]></programlisting>
+
+    <para>
+        Ca peut ne pas ressembler à quelque chose de terminé, mais avec un peu de CSS, cela peut
+        ressembler exactement à ce que vous cherchez. Le point important ici, c'est que le formulaire
+        a été généré en utilisant de la décoration manuelle personnalisée (ainsi que l'utilisation
+        d'échappement avec htmlentities).
+    </para>
+
+    <para>
+        Grâce à cette partie du tutoriel, vous devriez être à l'aise avec les possibilité de rendu de
+        <classname>Zend_Form</classname>. Dans la section suivante, nous verrons comment monter un
+        élément de date grâce à des éléments et des décorateur uniques assemblés main.
+    </para>
+</sect1>

+ 23 - 0
documentation/manual/fr/tutorials/form-decorators-intro.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- EN-Revision: 20573 -->
+<!-- Reviewed: no -->
+<sect1 id="learning.form.decorators.intro">
+    <title>Introduction</title>
+
+    <para>
+        <link linkend="zend.form">Zend_Form</link> utilise le pattern <emphasis>décorateur</emphasis>
+        afin de générer le rendu des éléments. Contrairement au pattern <ulink
+            url="http://en.wikipedia.org/wiki/Decorator_pattern">classique du décorateur</ulink>, dans
+            lequel se sont des objets qui sont passés, les décorateur de <classname>Zend_Form</classname>
+        implémentent un pattern <ulink url="http://en.wikipedia.org/wiki/Strategy_pattern">strategy
+            </ulink>, et utilisent les méta-données contenues dans l'élément ou le formulaire afin de
+            créer une représentation de celles-ci.
+    </para>
+
+    <para>
+        Ne vous laissez pas surprendre par ces termes, les décorateurs de
+        <classname>Zend_Form</classname> ne sont pas terriblement difficiles et les mini-tutoriels qui
+        suivent vont vous le prouver. Ils vont vous guider pour les bases et les techniques avancées de
+        décoration.
+    </para>
+</sect1>

+ 361 - 0
documentation/manual/fr/tutorials/form-decorators-layering.xml

@@ -0,0 +1,361 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- EN-Revision: 20649 -->
+<!-- Reviewed: no -->
+<sect1 id="learning.form.decorators.layering">
+    <title>Chainer les décorateurs</title>
+
+    <para>
+        Si vous avez bien suivi <link linkend="learning.form.decorators.simplest">la section
+            précédente</link>, vous avez pu remarquer que la méthode
+        <methodname>render()</methodname> prend un argument, <varname>$content</varname>.
+        Il est de type chaine de caractères. <methodname>render()</methodname> va utiliser cette
+        chaine et décider de la remplacer, de rajouter ou de faire précéder du contenu à celle-ci.
+        Ceci permet de chaine les décorateurs -- ce qui ouvre des possibilités de créer ses propres
+        décorateurs qui vont rendre une petite partie des données d'un élément chacun -- c'est la
+        chaine complet de décorateurs qui déterminera le rendu final réel de l'élément.
+    </para>
+
+    <para>
+        Voyons voir en pratique comment ça fonctionne.
+    </para>
+
+    <para>
+        Pour la plupart des éléments, les décorateurs suiovants sont chargés par défaut:
+    </para>
+
+    <itemizedlist>
+        <listitem>
+            <para>
+                <classname>ViewHelper</classname>: utilise une aide de vue pour rendre l'élément
+                balise de formulaire à proprement parlé.
+            </para>
+        </listitem>
+
+        <listitem>
+            <para>
+                <classname>Errors</classname>: utilise l'aide de vue <classname>FormErrors</classname>
+                pour afficher les erreurs de validation éventuelles.
+            </para>
+        </listitem>
+
+        <listitem>
+            <para>
+                <classname>Description</classname>: utilise l'aide de vue <classname>FormNote</classname>
+                afin de rendre la description éventuelle de l'élément.
+            </para>
+        </listitem>
+
+        <listitem>
+            <para>
+                <classname>HtmlTag</classname>: encapsule les trois objets ci-dessus dans un tag
+                <code>&lt;dd&gt;</code>.
+            </para>
+        </listitem>
+
+        <listitem>
+            <para>
+                <classname>Label</classname>: rend l'intitulé de l'élément en utilisant l'aide de vue
+                <classname>FormLabel</classname> (et en encapsulant le tout dans un tag
+                <code>&lt;dt&gt;</code>).
+            </para>
+        </listitem>
+    </itemizedlist>
+
+    <para>
+        Notez bien que chaque décorateur na qu'une petite tâche particulière et opère sur une partie
+        spécifique des données de l'élément auquel il est rattaché, le décorateur
+        <classname>Errors</classname> récupère les messages de validation de l'élément et les rend,
+        le décorateur <classname>Label</classname> rend simplement le libéllé. Ceci fait que chaque
+        décorateur est très petit, réutilisable, et surtout testable.
+    </para>
+
+    <para>
+        Cet argument <varname>$content</varname> vient de là aussi : chaque décorateur travaille
+        avec sa méthode <methodname>render()</methodname> sur un contenu (générallement généré par
+        le décorateur immédiatement précédent dans la pile globale) et embellit ce contenu en lui
+        rajoutant ou en lui faisant précéder des informations. Il peut aussi remplacer totallement
+        son contenu.
+    </para>
+
+    <para>
+        Ainsi, pensez au mécanisme des décorateurs comme la conception d'un oignon de l'intérieur
+        vers l'exterieur.
+    </para>
+
+    <para>
+        Voyons voir un exemple, le même que celui<link
+            linkend="learning.form.decorators.simplest">de la section précédente</link>:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+class My_Decorator_SimpleInput extends Zend_Form_Decorator_Abstract
+{
+    protected $_format = '<label for="%s">%s</label>'
+                       . '<input id="%s" name="%s" type="text" value="%s"/>';
+
+    public function render($content)
+    {
+        $element = $this->getElement();
+        $name    = htmlentities($element->getFullyQualifiedName());
+        $label   = htmlentities($element->getLabel());
+        $id      = htmlentities($element->getId());
+        $value   = htmlentities($element->getValue());
+
+        $markup  = sprintf($this->_format, $id, $label, $id, $name, $value);
+        return $markup;
+    }
+}
+]]></programlisting>
+
+    <para>
+        Supprimons la fonctionnalité libéllé (label) et créons un décorateur spécifique pour lui.
+    </para>
+
+    <programlisting language="php"><![CDATA[
+class My_Decorator_SimpleInput extends Zend_Form_Decorator_Abstract
+{
+    protected $_format = '<input id="%s" name="%s" type="text" value="%s"/>';
+
+    public function render($content)
+    {
+        $element = $this->getElement();
+        $name    = htmlentities($element->getFullyQualifiedName());
+        $id      = htmlentities($element->getId());
+        $value   = htmlentities($element->getValue());
+
+        $markup  = sprintf($this->_format, $id, $name, $value);
+        return $markup;
+    }
+}
+
+class My_Decorator_SimpleLabel extends Zend_Form_Decorator_Abstract
+{
+    protected $_format = '<label for="%s">%s</label>';
+
+    public function render($content)
+    {
+        $element = $this->getElement();
+        $id      = htmlentities($element->getId());
+        $label   = htmlentities($element->getLabel());
+
+        $markup = sprint($this->_format, $id, $label);
+        return $markup;
+    }
+}
+]]></programlisting>
+
+    <para>
+        Ok, ca semble bon mais il y a un problème : le dernier décorateur va l'emporter. Vous allez
+        vous retrouver avec comme seul rendu, celui du dernier décorateur.
+    </para>
+
+    <para>
+        Pour faire fonctionner le tout comme il se doit, concaténez simplement le contenu précédent
+        <varname>$content</varname> avec le contenu généré:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+return $content . $markup;
+]]></programlisting>
+
+    <para>
+        Le problème avec cette approche est que vous ne pouvez pas choisir où se place le contenu du décorateur
+        en question. Heureusement, un mécanisme standard existe;
+        <classname>Zend_Form_Decorator_Abstract</classname> possède le concept de place et définit des constantes
+        pour le régler. Aussi, il permet de préciser un séparateur à placer entre les 2. Voyons celà:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+class My_Decorator_SimpleInput extends Zend_Form_Decorator_Abstract
+{
+    protected $_format = '<input id="%s" name="%s" type="text" value="%s"/>';
+
+    public function render($content)
+    {
+        $element = $this->getElement();
+        $name    = htmlentities($element->getFullyQualifiedName());
+        $id      = htmlentities($element->getId());
+        $value   = htmlentities($element->getValue());
+
+        $markup  = sprintf($this->_format, $id, $name, $value);
+
+        $placement = $this->getPlacement();
+        $separator = $this->getSeparator();
+        switch ($placement) {
+            case self::PREPEND:
+                return $markup . $separator . $content;
+            case self::APPEND:
+            default:
+                return $content . $separator . $markup;
+        }
+    }
+}
+
+class My_Decorator_SimpleLabel extends Zend_Form_Decorator_Abstract
+{
+    protected $_format = '<label for="%s">%s</label>';
+
+    public function render($content)
+    {
+        $element = $this->getElement();
+        $id      = htmlentities($element->getId());
+        $label   = htmlentities($element->getLabel());
+
+        $markup = sprintf($this->_format, $id, $label);
+
+        $placement = $this->getPlacement();
+        $separator = $this->getSeparator();
+        switch ($placement) {
+            case self::APPEND:
+                return $markup . $separator . $content;
+            case self::PREPEND:
+            default:
+                return $content . $separator . $markup;
+        }
+    }
+}
+]]></programlisting>
+
+    <para>
+        Notez que dans l'exemple ci-dessus, nous intervertissons les comportements par défaut
+        avec append et prepend.
+    </para>
+
+    <para>
+        Créons dès lors un élément de formulaire qui va utiliser tout celà:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+$element = new Zend_Form_Element('foo', array(
+    'label'      => 'Foo',
+    'belongsTo'  => 'bar',
+    'value'      => 'test',
+    'prefixPath' => array('decorator' => array(
+        'My_Decorator' => 'path/to/decorators/',
+    )),
+    'decorators' => array(
+        'SimpleInput',
+        'SimpleLabel',
+    ),
+));
+]]></programlisting>
+
+    <para>
+        Comment ça fonctionne? et bien nous appelons <methodname>render()</methodname>, l'élément va alors
+        commencer une itération sur tous ses décorateurs, en appelant <methodname>render()</methodname>
+        sur chacun. Il va passer une chaine vide comme contenu pour le premier décorateur, et le rendu
+        de chaque décorateur va servir de contenu pour le suivant, ainsi de suite:
+    </para>
+
+    <itemizedlist>
+        <listitem>
+            <para>
+                Contenu initial : chaine vide: ''.
+            </para>
+        </listitem>
+
+        <listitem>
+            <para>
+                chaine vide ('') est passée au décorateur <classname>SimpleInput</classname>, qui génère
+                un tag de formulaire de type input qu'il ajoute à la chaine vide: <emphasis>&lt;input
+                    id="bar-foo" name="bar[foo]" type="text" value="test"/&gt;</emphasis>.
+            </para>
+        </listitem>
+
+        <listitem>
+            <para>
+                Ce contenu généré est alors passé comme contenu original pour le décorateur
+				<classname>SimpleLabel</classname> qui génère un libéllé et le place avant le contenu
+				original avec comme séparateur <constant>PHP_EOL</constant>, ce qui donne:
+                <emphasis>&lt;label for="bar-foo"&gt;\n&lt;input id="bar-foo" name="bar[foo]"
+                    type="text" value="test"/&gt;</emphasis>.
+            </para>
+        </listitem>
+    </itemizedlist>
+
+    <para>
+        Mais attendez une minute! Et si nous voulions que le libéllé soit rendu après le tag de formulaire
+        pour une raison quelconque? Vous souvenez-vous de l'option "placement"? Vous pouvez la préciser
+        comme option de décorateur, et le plus simple est alors de la passer à la création de l'élément:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+$element = new Zend_Form_Element('foo', array(
+    'label'      => 'Foo',
+    'belongsTo'  => 'bar',
+    'value'      => 'test',
+    'prefixPath' => array('decorator' => array(
+        'My_Decorator' => 'path/to/decorators/',
+    )),
+    'decorators' => array(
+        'SimpleInput'
+        array('SimpleLabel', array('placement' => 'append')),
+    ),
+));
+]]></programlisting>
+
+    <para>
+        Notez que passer des options vous oblige à préciser le nom du décorateur dans un tableau en tant
+        que premier élément, le deuxième élément est un tableau d'options.
+    </para>
+
+    <para>
+        Le code ci-dessus propose un rendu : <emphasis>&lt;input id="bar-foo" name="bar[foo]" type="text"
+            value="test"/&gt;\n&lt;label for="bar-foo"&gt;</emphasis>.
+    </para>
+
+    <para>
+        Grâce à cette technique, vous pouvez avoir plusieurs décorateurs dont chacun s'occupe
+        de rendre une petite partie d'un élément; et c'est en utilisant plusieurs décorateurs et en
+        les chainant correctement que vous obtiendrez un rendu complet : l'oignon final.
+    </para>
+
+    <para>
+        Avantages et inconvénients d'une telle technique, commençons par les inconvénients:
+    </para>
+
+    <itemizedlist>
+        <listitem>
+            <para>
+                C'est plus complexe qu'un rendu simple. Vous devez faire attention à chaque décorateur
+                mais en plus à l'ordre dans lequel ils agissent.
+            </para>
+        </listitem>
+
+        <listitem>
+            <para>
+                Ca consomme plus de ressources. Plus de décorateurs, plus d'objets, multipliés par le
+                nombre d'éléments dans un formulaire et la consommation en ressources augmente.
+                La mise en cache peut aider.
+            </para>
+        </listitem>
+    </itemizedlist>
+
+    <para>
+        Les avantages sont:
+    </para>
+
+    <itemizedlist>
+        <listitem>
+            <para>
+                Réutilisabilité. Vous pouvez créer des décorateurs complètement réutilisables car vous
+                ne vous souciez pas du rendu final, mais de chaque petit bout de rendu.
+            </para>
+        </listitem>
+
+        <listitem>
+            <para>
+                Fléxibilité. Il est en théorie possible d'arriver au rendu final voulu très exactement,
+                et ceci avec une petite poignée de décorateurs.
+            </para>
+        </listitem>
+    </itemizedlist>
+
+    <para>
+        Les exemples ci-dessus montrent l'utilisation de décorateurs au sein même d'un objet
+        <classname>Zend_Form</classname> et nous avons vu comment les décorateurs jouent les uns avec les
+        autres pour arriver au rendu final. Afin de pouvoir les utiliser de manière indépendante,
+        la version 1.7 a ajouté des méthodes fléxibles rendant les formulaires ressemblant au style
+        Rail. Nous allons nous pencher sur ce fait dans la section suivante.
+    </para>
+</sect1>

+ 248 - 0
documentation/manual/fr/tutorials/form-decorators-simplest.xml

@@ -0,0 +1,248 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- EN-Revision: 20573 -->
+<!-- Reviewed: no -->
+<sect1 id="learning.form.decorators.simplest">
+    <title>Les bases des décorateurs</title>
+
+    <sect2 id="learning.form.decorators.simplest.decorator-overview">
+        <title>Aperçu du pattern décorateur</title>
+
+        <para>
+            Pour commencer, nous allons voir un epu de théorie sur <ulink
+                url="http://en.wikipedia.org/wiki/Decorator_pattern">le pattern décorateur
+                </ulink>. Une technique consiste à définir une interface commune que les
+            objets originaux et les décorateurs implémentent; les décorateurs ayant comme
+            dépendance les objets originaux, ils vont alors pouvoir redéfinir ou proxier
+            les appels à leurs méthodes. Voyons un peu de code afin de mieux comprendre:
+        </para>
+
+        <programlisting language="php"><![CDATA[
+interface Window
+{
+    public function isOpen();
+    public function open();
+    public function close();
+}
+
+class StandardWindow implements Window
+{
+    protected $_open = false;
+
+    public function isOpen()
+    {
+        return $this->_open;
+    }
+
+    public function open()
+    {
+        if (!$this->_open) {
+            $this->_open = true;
+        }
+    }
+
+    public function close()
+    {
+        if ($this->_open) {
+            $this->_open = false;
+        }
+    }
+}
+
+class LockedWindow implements Window
+{
+    protected $_window;
+
+    public function __construct(Window $window)
+    {
+        $this->_window = $window;
+        $this->_window->close();
+    }
+
+    public function isOpen()
+    {
+        return false;
+    }
+
+    public function open()
+    {
+        throw new Exception('Cannot open locked windows');
+    }
+
+    public function close()
+    {
+        $this->_window->close();
+    }
+}
+]]></programlisting>
+
+        <para>
+            Nous créons un objet de type <classname>StandardWindow</classname>, le passons au constructeur
+            de <classname>LockedWindow</classname>, et le comportement de notre fenêtre a maintenant changé.
+            Le point fort ici est que nous n'avons pas besoin d'implémenter une fonctionnalité de verrou
+            ("lock") dans l'objet de base (StandardWindow) -- le décorateur s'occupe de cela. En plus,
+            vous pouvez utiliser votre fenêtre décorée à la place de la fenêtre standard : elles
+            implémentent la même interface.
+        </para>
+
+        <para>
+            Une utilisation particulièrement pratique du pattern décorateur est pour tout ce qui
+            concerne la représentation des objets. Par exemple un objet "Personne" qui en lui-même
+            n'a aucune représentation textuelle. Grâce au pattern décorateur, vous pouvez créer un
+            objet qui va agir comme une Personne mais qui pourra aussi représenter textuellement
+            cette Personne.
+        </para>
+
+        <para>
+            Dans cet exemple particulier, nous allons utiliser le<ulink
+                url="http://en.wikipedia.org/wiki/Duck_typing">duck typing</ulink> plutôt qu'une
+            interface explicite. Ceci permet à notre implémentation d'être un peu plus fléxible
+            tout en gardant l'utilisation de la décoration intacte.
+        </para>
+
+        <programlisting language="php"><![CDATA[
+class Person
+{
+    public function setFirstName($name) {}
+    public function getFirstName() {}
+    public function setLastName($name) {}
+    public function getLastName() {}
+    public function setTitle($title) {}
+    public function getTitle() {}
+}
+
+class TextPerson
+{
+    protected $_person;
+
+    public function __construct(Person $person)
+    {
+        $this->_person = $person;
+    }
+
+    public function __call($method, $args)
+    {
+        if (!method_exists($this->_person, $method)) {
+            throw new Exception('Invalid method called on HtmlPerson: '
+                .  $method);
+        }
+        return call_user_func_array(array($this->_person, $method), $args);
+    }
+
+    public function __toString()
+    {
+        return $this->_person->getTitle() . ' '
+            . $this->_person->getFirstName() . ' '
+            . $this->_person->getLastName();
+    }
+}
+]]></programlisting>
+
+        <para>
+            Dans cet exemple, nous passons une instance <classname>Person</classname> au constructeur
+            de <classname>TextPerson</classname>. Grâce à la surcharge des méthodes, nous pouvons
+            continuer d'appeler les méthodes de <classname>Person</classname> -- affecter un nom,
+            un prénom, ... -- mais nous pouvons en plus récupérer une représentation sous forme de
+            chaine grâce à <methodname>__toString()</methodname>.
+        </para>
+
+        <para>
+            Cet exemple est proche du fonctionnement interne des décorateurs de
+            <classname>Zend_Form</classname>. La différence est qu'au lieu que le décorateur
+            n'encapsule l'objet initial, c'est l'objet élément qui possède en lui un ou plusieurs
+            decorateurs à qui il passe lui-même pour effectuer le rendu visuel. Les décorateurs
+            peuvent ainsi accéder à l'élément et en créer une représentation.
+        </para>
+    </sect2>
+
+    <sect2 id="learning.form.decorators.simplest.first-decorator">
+        <title>Créer votre premier décorateur</title>
+
+        <para>
+            Les décorateurs de <classname>Zend_Form</classname> implémentent tous,
+            <classname>Zend_Form_Decorator_Interface</classname>. Cette interface permet
+            de régler les options du décorateur, enregistrer en lui l'élément ainsi
+            qu'effectuer le rendu. YUne classe de base,
+            <classname>Zend_Form_Decorator_Abstract</classname>, propose une implémentation
+            de cette logique de base dont vous aurez besoin, à l'exception du rendu que vous
+            devrez définir.
+        </para>
+
+        <para>
+            Imaginons une situation dans laquelle nous souhaitons simplement rendre un élément
+            comme un tag html text avec un libéllé(label). Juste la base, nous verrons plus tard
+            la gestion des erreurs et les éventuels autres tags html. Un tel décorateur pourrait
+            ressembler à ça:
+        </para>
+
+        <programlisting language="php"><![CDATA[
+class My_Decorator_SimpleInput extends Zend_Form_Decorator_Abstract
+{
+    protected $_format = '<label for="%s">%s</label>'
+                       . '<input id="%s" name="%s" type="text" value="%s"/>';
+
+    public function render($content)
+    {
+        $element = $this->getElement();
+        $name    = htmlentities($element->getFullyQualifiedName());
+        $label   = htmlentities($element->getLabel());
+        $id      = htmlentities($element->getId());
+        $value   = htmlentities($element->getValue());
+
+        $markup  = sprintf($this->_format, $name, $label, $id, $name, $value);
+        return $markup;
+    }
+}
+]]></programlisting>
+
+        <para>
+            Créons un élément qui utilise ce décorateur:
+        </para>
+
+        <programlisting language="php"><![CDATA[
+$decorator = new My_Decorator_SimpleInput();
+$element   = new Zend_Form_Element('foo', array(
+    'label'      => 'Foo',
+    'belongsTo'  => 'bar',
+    'value'      => 'test',
+    'decorators' => array($decorator),
+));
+]]></programlisting>
+
+        <para>
+            Le visuel de cet élément donne:
+        </para>
+
+        <programlisting language="html"><![CDATA[
+<label for="bar[foo]">Foo</label>
+<input id="bar-foo" name="bar[foo]" type="text" value="test"/>
+]]></programlisting>
+
+        <para>
+            Nous pourrions aussi ranger cette classe dans un dossier de librairie, il
+            faut alors informer l'élément du chemin vers ce dossier, et ensuite faire
+            référence au décorateur comme "SimpleInput":
+        </para>
+
+        <programlisting language="php"><![CDATA[
+$element = new Zend_Form_Element('foo', array(
+    'label'      => 'Foo',
+    'belongsTo'  => 'bar',
+    'value'      => 'test',
+    'prefixPath' => array('decorator' => array(
+        'My_Decorator' => 'path/to/decorators/',
+    )),
+    'decorators' => array('SimpleInput'),
+));
+]]></programlisting>
+
+        <para>
+            Ceci permet de partager du code entre projets et ouvre aussi la possibilité
+            d'étendre dans le futur les classes rangées.
+        </para>
+
+        <para>
+            Dans le chapitre suivant, nous allons voir comment combiner les décorateurs
+            afin de créer un affichage par morceaux (composite).
+        </para>
+    </sect2>
+</sect1>

+ 20 - 0
documentation/manual/fr/tutorials/layout-conclusions.xml

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- EN-Revision: 20573 -->
+<!-- Reviewed: no -->
+<sect1 id="learning.layout.conclusions">
+    <title>Zend_Layout: Conclusions</title>
+
+    <para>
+        <classname>Zend_Layout</classname> est une simple surcouche à
+        <classname>Zend_View</classname> en proposant un pattern Two-Step View, offrant
+        la fléxibilité de créer un design applicatif dans lequel le contenu est injecté.
+    </para>
+
+    <para>
+        Si vous regardez de près les exemple, vous sentirez peut-être que les fonctionnalités
+        sont limitées    : comment modifier le titre de la page, injecter un tag script
+        optionnel ou même créer une sidebar? Ces questions concernent le concept de
+        "Composite View" -- et trouveront réponse dans le chapitre suivant couvrant des
+        "placeholders."
+    </para>
+</sect1>

+ 54 - 0
documentation/manual/fr/tutorials/layout-intro.xml

@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- EN-Revision: 20573 -->
+<!-- Reviewed: no -->
+<sect1 id="learning.layout.intro">
+    <title>Introduction</title>
+
+    <para>
+        Dans une application utilisant les couches Zend Framework <acronym>MVC</acronym>,
+        vos scripts de vue ne seront que des blocs de <acronym>HTML</acronym> concernant
+        l'action demandée. Par exemple, une action "<filename>/user/list</filename>"
+        mènerait vers un script de vue itérant sur les utilisateurs en présentant une liste:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+<h2>Utilisateurs</h2>
+<ul>
+    <?php if (!count($this->users)): ?>
+    <li>Pas d'utilisateurs</li>
+    <?php else: ?>
+    <?php foreach ($this->users as $user): ?>
+    <li>
+        <?php echo $this->escape($user->fullname) ?>
+        (<?php echo $this->escape($user->email) ?>)
+    </li>
+    <?php endforeach ?>
+    <?php endif ?>
+</ul>
+]]></programlisting>
+
+    <para>
+        Comme c'est juste un bloc de code <acronym>HTML</acronym>, ce n'est pas une page valide,
+        il manque le <acronym>DOCTYPE</acronym> et la balise ouvrante <acronym>HTML</acronym> puis
+        <acronym>BODY</acronym>. Quand seront-ils crées?
+    </para>
+
+    <para>
+        Dans les anciennes versions de Zend Framework, les développeurs créaient souvent des scripts
+        de vue "header" et "footer" qui servaient à cela. Ca fonctionnait certes, mais c'était
+        difficile à refactoriser, ou pour appeler du contenu provenant de plusieurs actions.
+    </para>
+
+    <para>
+        Le pattern
+        <ulink url="http://martinfowler.com/eaaCatalog/twoStepView.html">Two-Step View</ulink>
+        solutionne beaucoup des problèmes indiqués. Avec, la vue "application" est crée en premier,
+        puis injectée dans une vue "page" ainsi présentée à l'utilisateur client. la vue de page
+        peut être imaginée comme un template global ou layout qui décrirait des éléments communs
+        utilisés au travers de multiples pages.
+    </para>
+
+    <para>
+        Dans Zend Framework, <classname>Zend_Layout</classname> implémente le pattern Two-Step View.
+    </para>
+</sect1>

+ 242 - 0
documentation/manual/fr/tutorials/layout-usage.xml

@@ -0,0 +1,242 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- EN-Revision: 20573 -->
+<!-- Reviewed: no -->
+<sect1 id="learning.layout.usage">
+    <title>Utiliser Zend_Layout</title>
+
+    <para>
+        L'utilisation classique de <classname>Zend_Layout</classname> est simple. En supposant
+        que vous utilisez <classname>Zend_Application</classname>, il suffit simplement de
+        passer des options de configuration et créer un script de layout.
+    </para>
+
+    <sect2 id="learning.layout.usage.configuration">
+        <title>Layout Configuration</title>
+
+        <para>
+            L'endroit recommandé pour stocker les layouts est
+            "<filename>layouts/scripts/</filename>" dans l'application:
+        </para>
+
+        <programlisting language="text"><![CDATA[
+application
+|-- Bootstrap.php
+|-- configs
+|   `-- application.ini
+|-- controllers
+|-- layouts
+|   `-- scripts
+|       |-- layout.phtml
+]]></programlisting>
+
+        <para>
+            Pour initialiser <classname>Zend_Layout</classname>, ajouter ceci à votre fichier
+            de configuration ("<filename>application/configs/application.ini</filename>"):
+        </para>
+
+        <programlisting language="dosini"><![CDATA[
+resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"
+resources.layout.layout = "layout"
+]]></programlisting>
+
+        <para>
+            La première ligne indique où chercher les scripts de layout; la seconde donne le
+            nom du script à utiliser (l'extension est supposée "<filename>.phtml</filename>"
+            par défaut).
+        </para>
+    </sect2>
+
+    <sect2 id="learning.layout.usage.layout-script">
+        <title>Créer un script de layout</title>
+
+        <para>
+            Il convient maintenant de créer un script de layout. D'abord, vérifiez l'existance du
+            dossier "<filename>application/layouts/scripts</filename>"; puis ouvrez un éditeur et
+            créez une mise en page balisée. Les scripts de layout sont des scripts de vue, avec
+            quelques différences tout de même.
+        </para>
+
+        <programlisting language="php"><![CDATA[
+<html>
+<head>
+    <title>My Site</title>
+</head>
+<body>
+    <?php echo $this->layout()->content ?>
+</body>
+</html>
+]]></programlisting>
+
+        <para>
+            Dans l'exemple ci-dessus, un appel à l'aide de vue <methodname>layout()</methodname> y
+            est effectué. Lorsque vous activez l'instance de <classname>Zend_Layout</classname>,
+            vous avez aussi accès à une aide d'acion et de vue qui permettent d'accéder à l'instance
+            de <classname>Zend_Layout</classname>; et vous pouvez ainsi appeler des méthodes
+            sur l'objet layout. Dans notre cas, nous récupérons une variable appelée
+            <varname>$content</varname>, et nous l'affichons. Par défaut, <varname>$content</varname>
+            est peuplée du contenu de la vue rendue pour l'action en cours. Sinon, tout ce que vous
+            feriez dans un script de vue est valide dans un script de layout: appel d'aides ou
+            de méthodes sur la vue.
+        </para>
+
+        <para>
+            Maintenant, nous avons un script de layout fonctionnel et notre application sait où le
+            trouver.
+        </para>
+    </sect2>
+
+    <sect2 id="learning.layout.usage.access">
+        <title>Accéder à l'objet Layout</title>
+
+        <para>
+            Il est probable que vous ayez besoin d'accéder à l'objet instance layout. Cela est
+            possible de trois manières:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <emphasis>Dans des scripts de vue:</emphasis> utilisez l'aide de vue
+                    <methodname>layout()</methodname>, qui retourne l'instance de
+                    <classname>Zend_Layout</classname> enregistrée au moyen du plugin MVC.
+                </para>
+
+                <programlisting language="php"><![CDATA[
+<?php $layout = $this->layout(); ?>
+]]></programlisting>
+
+                <para>
+                    Comme cela retourne l'objet de layout, vous pouvez appeler dessus toute méthode
+                    ou assigner des variables.
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    <emphasis>Dans vos contrôleurs:</emphasis> utilisez ici l'aide d'action
+                    <methodname>layout()</methodname>, qui agit comme l'aide de vue.
+                </para>
+
+                <programlisting language="php"><![CDATA[
+// Appel de l'aide comme méthode sur le gestionnaire d'aides:
+$layout = $this->_helper->layout();
+
+// Ou, de manière plus détaillée:
+$helper = $this->_helper->getHelper('Layout');
+$layout = $helper->getLayoutInstance();
+]]></programlisting>
+
+                <para>
+                    Comme avec l'aide de vue, vous pouvez appeler dès lors n'importe quelle
+                    méthode de layout ou lui assigner des variables.
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    <emphasis>Ailleurs: </emphasis> utilisez la méthode statique
+                    <methodname>getMvcInstance()</methodname>. Cette méthode retourne l'instance
+                    de layout comme déja vu plus haut maintenant.
+                </para>
+
+                <programlisting language="php"><![CDATA[
+$layout = Zend_Layout::getMvcInstance();
+]]></programlisting>
+            </listitem>
+
+            <listitem>
+                <para>
+                    <emphasis>Via le bootstrap: </emphasis> utilisez la ressource layout qui
+                    crée, configure et retourne l'objet <classname>Zend_Layout</classname>.
+                </para>
+
+                <programlisting language="php"><![CDATA[
+$layout = $bootstrap->getResource('Layout');
+]]></programlisting>
+
+                <para>
+                    Partout où vous avez accès à l'objet bootstrap, il s'agit de la méthode
+                    recommandée par rapport à <methodname>getMvcInstance()</methodname>.
+                </para>
+            </listitem>
+        </itemizedlist>
+    </sect2>
+
+    <sect2 id="learning.layout.usage.other-operations">
+        <title>Autres opérations</title>
+
+        <para>
+            Dans la plupart des cas, le script de configuration de layout ci-dessus (avec quelques
+            modifications) répondra à vos besoins. Cependant, dans certains cas il peut être
+            intéressant d'utiliser d'autres fonctionnalités. Dans les exemples qui suivent,
+            vous allez utiliser une des<link
+                linkend="learning.layout.usage.access">méthodes listées ci-dessus</link> pour
+            récupérer l'objet layout.
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <emphasis>Affecter les variables de layout</emphasis>.
+                    <classname>Zend_Layout</classname> garde en mémoire les variables de vue
+                    spécifiques à la layout, la clé <varname>$content</varname> en est un
+                    exemple. Vous pouvez assigner et récupérer ces variables grâce à la méthode
+                    <methodname>assign()</methodname> ou en y accédant comme des attributs
+                    classiques.
+                </para>
+
+                <programlisting language="php"><![CDATA[
+// Affecter du contenu:
+$layout->somekey = "foo"
+
+// Afficher ce même contenu:
+echo $layout->somekey; // 'foo'
+
+// Utiliser la méthode assign() :
+$layout->assign('someotherkey', 'bar');
+
+// Accéder à la variable reste identique:
+echo $layout->someotherkey; // 'bar'
+]]></programlisting>
+            </listitem>
+
+            <listitem>
+                <para>
+                    <methodname>disableLayout()</methodname>. Occasionellement, vous pouriez vouloir
+                    d"sactiver totalement les layouts, par exemple, pour répondre à une requête AJAX
+                    ou autravers d'une API RESTful. Dans ces cas, appelez la méthode
+                    <methodname>disableLayout()</methodname> de l'objet layout.
+                </para>
+
+                <programlisting language="php"><![CDATA[
+$layout->disableLayout();
+]]></programlisting>
+
+                <para>
+                    Le contraire de cette méthode, <methodname>enableLayout()</methodname>, permet
+                    de ré-activer le rendu des layouts pour l'action en cours.
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    <emphasis>Utiliser un autre script de layout</emphasis>: Si vous avez plusieurs scripts
+                    de layout pour votre application, vous pouvez selectionner lequel rendre grâce à la
+                    méthode <methodname>setLayout()</methodname>. Précisez alors le nom du script de layout,
+                    sans l'extension.
+                </para>
+
+                <programlisting language="php"><![CDATA[
+// Utiliser le script de layout "alternate.phtml":
+$layout->setLayout('alternate');
+]]></programlisting>
+
+                <para>
+                    Le script de layout doit se trouver dans le <varname>$layoutPath</varname> précisé via
+                    la configuration (en bootstrap générallement). <classname>Zend_Layout</classname>
+                    utilisera le nouveau script à rendre.
+                </para>
+            </listitem>
+        </itemizedlist>
+    </sect2>
+</sect1>

+ 173 - 0
documentation/manual/fr/tutorials/multiuser-authentication.xml

@@ -0,0 +1,173 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- EN-Revision: 20649 -->
+<!-- Reviewed: no -->
+<sect1 id="learning.multiuser.authentication">
+    <title>Authentification d'utilisateurs dans Zend Framework</title>
+
+    <sect2 id="learning.multiuser.authentication.intro">
+        <title>Introduction à l'authentification</title>
+
+        <para>
+            Une fois que l'application a récupéré les informations d'un utilisateur, elle doit
+            vérifier leur "authenticité", c'est l'authentification. Pour celà, deux informations
+            sont nécessaires : l'identifiant et un ensemble de règles régissant cet identifiant,
+            aujourd'hui typiquement une chaine de caractères servant de mot de passe est très
+            classique, mais d'autres procédés existent (reconnaissances digitales, occulaires...)
+        </para>
+
+        <para>
+            Un identifiant peut lui aussi être un "login" tout banal, mais pourquoi pas un
+            numéro de membre, une adresse email... le secret, lui, est donc souvent un mot de passe
+            sous forme de chaine de caractères.
+        </para>
+
+    </sect2>
+
+    <sect2 id="learning.multiuser.authentication.basic-usage">
+        <title>Utilisation de base de Zend_Auth</title>
+
+        <para>
+            Dans l'exemple suivant, nous utiliserons <classname>Zend_Auth</classname> afin d'effectuer
+            une authentification des plus classiques: champ login et password puis vérification en
+            base de données. Cet exemple suppose que vous utilisez
+            <classname>Zend_Application</classname> afin de configurer une connexion à une base de
+            données.
+        </para>
+
+        <para>
+            <classname>Zend_Auth</classname> effectue deux tâches. D'abord elle doit récupérer un
+            adaptateur d'authentification afin de déclencher le processus d'authentification, puis
+            si celui-ci est correct, elle doit faire persister ces informations entre requêtes.
+            Pour assurer cette persistance, <classname>Zend_Auth</classname> utilise un
+            <classname>Zend_Session_Namespace</classname>, mais en général vous n'aurez pas besoin
+            d'agir sur cet objet.
+        </para>
+
+        <para>
+            Supposant une table de base de données suivante:
+        </para>
+
+        <programlisting language="php"><![CDATA[
+CREATE TABLE users (
+    id INTEGER  NOT NULL PRIMARY KEY,
+    username VARCHAR(50) UNIQUE NOT NULL,
+    password VARCHAR(32) NULL,
+    password_salt VARCHAR(32) NULL,
+    real_name VARCHAR(150) NULL
+)
+]]></programlisting>
+
+        <para>
+            C'est une table qui inclue des champs nom, password et aussi grain de sel. Le grain de
+            sel est utilisé pour améliorer la sécurité contre les attaques par force brute qui
+            cibleraient l'alogithme de hashage du mot de passe. <ulink
+                url="http://en.wikipedia.org/wiki/Salting_%28cryptography%29">Plus
+                d'informations</ulink> sur le grain de sel.
+        </para>
+
+        <para>
+            Créons un formulaire de login simple. Nous utiliserons <classname>Zend_Form</classname>.
+        </para>
+
+        <programlisting language="php"><![CDATA[
+// localisé à application/forms/Auth/Login.php
+
+class Default_Form_Auth_Login extends Zend_Form
+{
+    public function init()
+    {
+        $this->setMethod('post');
+
+        $this->addElement(
+            'text', 'username', array(
+                'label' => 'Username:',
+                'required' => true,
+                'filters'    => array('StringTrim'),
+            ));
+
+        $this->addElement('password', 'password', array(
+            'label' => 'Password:',
+            'required' => true,
+            ));
+
+        $this->addElement('submit', 'submit', array(
+            'ignore'   => true,
+            'label'    => 'Login',
+            ));
+
+    }
+}
+]]></programlisting>
+
+        <para>
+            Ce formulaire nous mène vers la création du contrôleur de traitement. Nous l'appellerons
+            "<classname>AuthController</classname>", et le logerons dans
+            <filename>application/controllers/AuthController.php</filename>. Il possèdera une seule méthode
+            "<methodname>loginAction()</methodname>" vers laquelle le formulaire enverra, la méthode
+            va donc réagir à GET et à POST, elle encapsule toute la logique.
+        </para>
+
+        <para>
+            Le code suivant montre comment construire l'adaptateur d'authentification et l'intégration du
+            formulaire:
+        </para>
+
+        <programlisting language="php"><![CDATA[
+class AuthController extends Zend_Controller_Action
+{
+
+    public function loginAction()
+    {
+        $db = $this->_getParam('db');
+
+        $loginForm = new Default_Form_Auth_Login($_POST);
+
+        if ($loginForm->isValid()) {
+
+            $adapter = new Zend_Auth_Adapter_DbTable(
+                $db,
+                'users',
+                'username',
+                'password',
+                'MD5(CONCAT(?, password_salt))'
+                );
+
+            $adapter->setIdentity($loginForm->getValue('username'));
+            $adapter->setCredential($loginForm->getValue('password'));
+
+            $result = $auth->authenticate($adapter);
+
+            if ($result->isValid()) {
+                $this->_helper->FlashMessenger('Successful Login');
+                $this->redirect('/');
+                return;
+            }
+
+        }
+
+        $this->view->loginForm = $loginForm;
+
+    }
+
+}
+]]></programlisting>
+
+        <para>
+            Le script de vue est quant à lui enfantin, il sera logé dans
+            <filename>application/views/scripts/auth/login.phtml</filename>:
+        </para>
+
+        <programlisting language="php"><![CDATA[
+$this->form->setAction($this->url());
+echo $this->form;
+]]></programlisting>
+
+        <para>
+            Et voila! Avec ce scénario de base, vous pouvez étendre les possibilités et répondre
+            à vos besoins précis. Tous les adaptateurs
+            <classname>Zend_Auth</classname> se trouvent décrits dans
+            <link linkend="zend.auth">le guide de réference</link>.
+        </para>
+    </sect2>
+</sect1>
+

+ 237 - 0
documentation/manual/fr/tutorials/multiuser-authorization.xml

@@ -0,0 +1,237 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- EN-Revision: 20649 -->
+<!-- Reviewed: no -->
+<sect1 id="learning.multiuser.authorization">
+    <title>Fabriquer un système de gestion d'autorisations avec Zend Framework</title>
+
+    <sect2 id="learning.multiuser.authorization.intro">
+        <title>Introduction à l'autorisation</title>
+
+        <para>
+            Après qu'un utilisateur se soit authentifié, une application peut proposer différentes
+            règles d'accès à ses différentes ressources (parties). Le procédé qui consiste à savoir
+            "qui a le droit de faire quoi" est nommé "gestion des autorisations". Dans sa forme la
+            plus simple l'autorisation est la composition de trois facteurs:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    l'identitié de la personne souhaitant des droits - le rôle (qui?)
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    la ressource demandée (sur quoi?)
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    et optionnellement le privilège - le droit (quoi?)
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Dans Zend Framework, le composant <classname>Zend_Acl</classname> vous propose de créer
+            ces trois entités remarquables, de les associer et de les interroger dans le futur.
+        </para>
+
+    </sect2>
+
+    <sect2 id="learning.multiuser.authorization.basic-usage">
+        <title>Utilisation de base de Zend_Acl</title>
+
+<!-- explain the interaction with a User object, how -->
+
+        <para>
+            En utilisant <classname>Zend_Acl</classname>, n'importe quel modèle peut servir de rôle
+            ou de ressource en implémentant l'interface adéquate. Pour créer des rôles, implémentez
+            <classname>Zend_Acl_Role_Interface</classname>, qui définit la méthode
+            <methodname>getRoleId()</methodname>. Pour créer des ressources, implémentez
+            <classname>Zend_Acl_Resource_Interface</classname> qui définit la méthode
+            <methodname>getResourceId()</methodname>.
+        </para>
+
+        <para>
+            Nous allons faire une démonstration avec un modèle simple. On peut le relier avec notre
+            système d'<acronym>ACL</acronym> en implémentant
+            <classname>Zend_Acl_Role_Interface</classname>. La méthode
+            <methodname>getRoleId()</methodname> retournera "guest" lorsque l'ID est inconnu,
+            ou l'ID du rôle lorsque celui-ci aura été affecté. Cette valeur peut provenir de n'importe
+            où, probablement qu'elle proviendra d'une définition faite en base de données.
+        </para>
+
+        <programlisting language="php"><![CDATA[
+class Default_Model_User implements Zend_Acl_Role_Interface
+{
+    protected $_aclRoleId = null;
+
+    public function getRoleId()
+    {
+        if ($this->_aclRoleId == null) {
+            return 'guest';
+        }
+
+        return $this->_aclRoleId;
+    }
+}
+]]></programlisting>
+
+        <para>
+            Le concept des utilisateurs ayant des rôles est simple à comprendre, mais l'application
+            peut consommer plusieurs modèles et en retrouver des "ressources" qui seront
+            consommables par les rôles. Nous utiliserons simplement des billets de blog comme
+            ressources dans nos exemples, et comme les ressources sont des objets, nous ferons
+            en sorte que l'ID d'un billet blog soir 'blogPost', naturellement cette valeur peut
+            être calculée dynamiquement en fonction du besoin.
+        </para>
+
+        <programlisting language="php"><![CDATA[
+class Default_Model_BlogPost implements Zend_Acl_Resource_Interface
+{
+    public function getResourceId()
+    {
+        return 'blogPost';
+    }
+}
+]]></programlisting>
+
+        <para>
+            Maintenant que nous avons au minimum un rôle et une ressource, définissons règles qui les
+            lient. Ces règles seront lues lorsque le système recevra une requête d'acl demandant ce
+            qu'il est possible de faire avec tel rôle, telle ressource et éventuellement tel privilège.
+        </para>
+
+        <para>
+            Imaginons les règles suivantes:
+        </para>
+
+        <programlisting language="php"><![CDATA[
+$acl = new Zend_Acl();
+
+// mise en place des rôles
+$acl->addRole('guest');
+// owner hérite du rôle guest
+$acl->addRole('owner', 'guest');
+
+// ajout de ressources
+$acl->addResource('blogPost');
+
+// ajout de privilèges liant des rôles et des ressources
+$acl->allow('guest', 'blogPost', 'view');
+$acl->allow('owner', 'blogPost', 'post');
+$acl->allow('owner', 'blogPost', 'publish');
+]]></programlisting>
+
+        <para>
+            Les règles ci-dessus sont très simples: deux rôles "guest"(invité) et "owner"
+            (propriétaire), et une ressource "blogPost"(billet). Les invités sont autorisés
+            à voir les billets, les propriétaires peuvent poster et publier des billets. Pour
+            requêter le système, procédez alors comme suit:
+        </para>
+
+        <programlisting language="php"><![CDATA[
+// Imaginons que le modèle User soit de type "guest"
+$guestUser = new Default_Model_User();
+$ownerUser = new Default_Model_Owner('OwnersUsername');
+
+$post = new Default_Model_BlogPost();
+
+$acl->isAllowed($guestUser, $post, 'view'); // true
+$acl->isAllowed($ownerUser, $post, 'view'); // true
+$acl->isAllowed($guestUser, $post, 'post'); // false
+$acl->isAllowed($ownerUser, $post, 'post'); // true
+]]></programlisting>
+
+        <para>
+            Comme vous pouvez le voir le système répond comme il faut dans la mesure où les
+            invités peuvent lire les billets mais seuls les propriétaires peuvent en ajouter.
+            Cependant ce système peut sembler manquer de dynamisme. Comment vérifier qu'un
+            utilisateur spécifique est bien propriétaire d'un billet spécifique avant de
+            l'autoriser à le publier ? Autrement dit, on veut s'assurer que seuls les
+            propriétaires des billets peuvent publier ceux-ci, et pas ceux des autres.
+        </para>
+
+        <para>
+            C'est là qu'entrent en jeu les assertions. Les assertions sont des vérifications
+            supplémentaires à effectuer en même temps que la vérification de la règle d'acl.
+            Ce sont des objets. Utilisons notre exemple avec une assertion:
+        </para>
+
+        <programlisting language="php"><![CDATA[
+class OwnerCanPublishBlogPostAssertion implements Zend_Acl_Assert_Interface
+{
+    /**
+     * Cette assertion va recevoir le User et le BlogPost actuels.
+     *
+     * @param Zend_Acl $acl
+     * @param Zend_Acl_Role_Interface $user
+     * @param Zend_Acl_Resource_Interface $blogPost
+     * @param $privilege
+     * @return bool
+     */
+    public function assert(Zend_Acl $acl,
+                           Zend_Acl_Role_Interface $user = null,
+                           Zend_Acl_Resource_Interface $blogPost = null,
+                           $privilege = null)
+    {
+        if (!$user instanceof Default_Model_User) {
+            throw new Exception(__CLASS__
+                              . '::'
+                              . __METHOD__
+                              . ' s'attend à un rôle'
+                              . ' instance de User');
+        }
+
+        if (!$blogPost instanceof Default_Model_BlogPost) {
+            throw new Exception(__CLASS__
+                              . '::'
+                              . __METHOD__
+                              . ' s'attend à un rôle'
+                              . ' instance de BlogPost');
+        }
+
+        // Si le rôle est publisher, il peut toujours modifier son billet
+        if ($user->getRoleId() == 'publisher') {
+            return true;
+        }
+
+        // vérifions que qui que ce soit, il modifie uniquement ses propres billets
+        if ($user->id != null && $blogPost->ownerUserId == $user->id) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+}
+]]></programlisting>
+
+        <para>
+            Pour faire intervenir l'assertion dans les <acronym>ACL</acronym>, nous les utilisons comme ceci:
+        </para>
+
+        <programlisting language="php"><![CDATA[
+// remplacez ceci:
+//   $acl->allow('owner', 'blogPost', 'publish');
+// par cela:
+$acl->allow('owner',
+            'blogPost',
+            'publish',
+            new OwnerCanPublishBlogPostAssertion());
+
+// ajoutons aussi le rôle "publisher" qui a accès à tout
+$acl->allow('publisher', 'blogPost', 'publish');
+]]></programlisting>
+
+        <para>
+            Maintenant, dès que l'<acronym>ACL</acronym> est consultée pour savoir si un propriétaire
+            peut publier un billet, cette assertion sera vérifiée. Elle s'assure que sauf si le rôle
+            est 'publisher' le propriétaire a bien écrit le billet. Dans cet exemple, nous vérifions
+            pour savoir si l'attribut <property>ownerUserId</property> du billet correspond à
+            l'identifiant de l'utilisateur en question.
+        </para>
+    </sect2>
+</sect1>

+ 72 - 0
documentation/manual/fr/tutorials/multiuser-intro.xml

@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- EN-Revision: 20649 -->
+<!-- Reviewed: no -->
+<sect1 id="learning.multiuser.intro">
+    <title>Fabrique une application Multi-Utilisateurs avec Zend Framework</title>
+
+    <sect2 id="learning.multiuser.intro.zf">
+        <title>Zend Framework</title>
+
+        <para>
+            Lorsque le web a été crée, il s'agissait d'un média permettant de consulter des
+            documents statiques. La demande de contenu a cru, le nombre d'internautes aussi
+            et les sites webs sont devenus des applications tournant sur de grosses plateformes.
+        </para>
+
+        <para>
+            <acronym>HTTP</acronym> est le protocole du web: sans état, des requêtes/réponses
+            à courte durée de vie. Ce protocole a été crée comme cela pour assurer le web
+            tel qu'on l'entendait avant : servir du contenu statique et c'est ce design qui
+            a fait du web un immense succès. C'est aussi ce design qui mène à des notions que
+            les développeurs veulent utiliser dans leurs applications.
+        </para>
+
+        <para>
+            Ces informations nous mènent à trois questions:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    Comment distinguer les clients d'une application?
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    Comment identifier ces clients?
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    Comment contrôler les droits d'un client identifié?
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <note>
+            <title>Client contre Utilisateur</title>
+
+            <para>
+                Nous utilisons le terme "client" et pas utilisateur. Les applications web deviennent
+                des fournisseurs de services. Ceci signifie que les "gens", les utilisateurs humains
+                avec des navigateurs web ne sont pas les seuls à consommer l'application et ses services.
+                Beaucoup d'autres applications web consomment elles-mêmes des ressources sur une
+                application via des technologies comme <acronym>REST</acronym>, <acronym>SOAP</acronym>,
+                ou <acronym>XML-RPC</acronym>. On voit bien qu'on ne peut parler d'utilisateur, nous
+                traitons donc les utilisateurs humains des utilisateurs machines sous le même nom :
+                des "clients" web.
+            </para>
+
+        </note>
+
+        <para>
+            Dans les chapitres qui suivent, nous nous attaquerons à ces problèmes que sont
+            l'authentification, l'identification et les détails. Nous allons découvrir trois
+            composants: <classname>Zend_Session</classname>, <classname>Zend_Auth</classname>, et
+            <classname>Zend_Acl</classname>; nous montrerons des exemples concrets et des possibilités
+            d'extension.
+        </para>
+    </sect2>
+</sect1>

+ 127 - 0
documentation/manual/fr/tutorials/multiuser-sessions.xml

@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- EN-Revision: 20649 -->
+<!-- Reviewed: no -->
+<sect1 id="learning.multiuser.sessions">
+    <title>Gérer les sessions dans ZF</title>
+
+    <sect2 id="learning.multiuser.sessions.intro">
+        <title>Introduction aux sessions</title>
+
+        <para>
+            Le succès du web est en grande partie dûe aux protocoles qui le supportent: HTTP. HTTP sur
+            TCP est par nature sans état ce qui signifie que le web n'a pas "de mémoire". Ce fait
+            pose des problèmes pour les développeurs voulant traiter leur application comme un
+            service riche.
+        </para>
+
+        <para>
+            Interagir avec l'application web c'est en fait faire la somme de toutes les requêtes
+            que celle-ci reçoit. Et comme il y a beaucoup de clients, il y a beaucoup de requête,
+            et le moyen d'associer une requête à un client est appelé "session".
+        </para>
+
+        <para>
+            En PHP, le problème des sessions a été résolu au travers de l'extension session qui utilise
+            un système de persistance, typiquement basé sur des cookies et un stockage local des variables
+            dans $_SESSION. Dans Zend Framework, le composant Zend_Session ajoute de la valeur au système
+            de session de PHP notamment une manipulation objet.
+        </para>
+
+    </sect2>
+
+    <sect2 id="learning.multiuser.sessions.basic-usage">
+        <title>Utilisation classique de Zend_Session</title>
+
+        <para>
+            Le composant Zend_Session est un gestionnaire de session et une API pour stocker des données
+            dans la session de manière objet. L'API de la classe Zend_Session API permet de régler des options
+            et de démarrer/arrêter la session alors que Zend_Session_Namespace représente un objet
+            contenant des données à stocker en session.
+        </para>
+
+        <para>
+            C'est générallement une bonne pratique que de démarrer sa session en bootstrap, cependant
+            la première création d'un objet Zend_Session_Namespace démarrera la session par défaut.
+        </para>
+
+        <para>
+            Zend_Application peut permettre de configurer Zend_Session grâce aux parties
+            Zend_Application_Resource. Pour les utiliser, en supposant que votre projet utilise
+            Zend_Application, ajoutez le code suivant à application.ini:
+        </para>
+
+        <programlisting language="php"><![CDATA[
+resources.session.save_path = APPLICATION_PATH "/../data/session"
+resources.session.use_only_cookies = true
+resources.session.remember_me_seconds = 864000
+]]></programlisting>
+
+        <para>
+            Comme vous le remarquez, les options utilisées sont les mêmes que celles que reconnait
+            ext/session (l'extension session de PHP). Le chemin de stockage des session par exemple.
+            Les fichiers ini peuvent utiliser des constantes, nous réutilisons APPLICATION_PATH
+            pour calculer le chemin relatif vers un dossier arbitraire sensé stocker les sessions.
+        </para>
+
+        <para>
+            La plupart des composants de Zend Framework utilisant les sessions n'ont rien besoin de plus.
+            Dès lors, vous pouvez utiliser un composant faisant appel à la session, ou manipuler la session
+            vous-même au travers d'un ou plusieurs objets Zend_Session_Namespace.
+        </para>
+
+        <para>
+            Zend_Session_Namespace est une classe qui guide ses données vers $_SESSION. La classe s'appelle
+            Zend_Session_Namespace car elle crée des espaces de noms au sein de $_SESSION, autorisant
+            plusieurs composants ou objets à stocker des valeurs sans se marcher dessus. Nous allons voir
+            dans l'exemple qui suit comment créer un simple compteur de session qui commence à 1000
+            et se remet à zéro après 1999.
+        </para>
+
+        <programlisting language="php"><![CDATA[
+$mysession = Zend_Session_Namespace('mysession');
+
+if (!isset($mysession->counter)) {
+    $mysession->counter = 1000;
+} else {
+    $mysession->counter++;
+}
+
+if ($mysession->counter > 1999) {
+    unset($mysession->counter);
+}
+]]></programlisting>
+
+        <para>
+            Comme vous le remarquez, l'objet de session utilise les méthodes magiques __get, __set,
+            __isset, et __unset pour proposer une API intuitive. Les informations stockées dans
+            notre exemple le sont en réalité dans $_SESSION['mysession']['counter'].
+        </para>
+
+    </sect2>
+    <sect2 id="learning.multiuser.sessions.advanced-usage">
+        <title>Utilisation avancée de Zend_Session</title>
+
+        <para>
+            Si vous voulez utiliser le gestionnaire de sauvegarde des sessions "DbTable", vous
+            pouvez simplement ajouter ces options à application.ini:
+        </para>
+
+        <programlisting language="php"><![CDATA[
+resources.session.saveHandler.class = "Zend_Session_SaveHandler_DbTable"
+resources.session.saveHandler.options.name = "session"
+resources.session.saveHandler.options.primary.session_id = "session_id"
+resources.session.saveHandler.options.primary.save_path = "save_path"
+resources.session.saveHandler.options.primary.name = "name"
+resources.session.saveHandler.options.primaryAssignment.sessionId = "sessionId"
+resources.session.saveHandler.options.primaryAssignment.sessionSavePath = "sessionSavePath"
+resources.session.saveHandler.options.primaryAssignment.sessionName = "sessionName"
+resources.session.saveHandler.options.modifiedColumn = "modified"
+resources.session.saveHandler.options.dataColumn = "session_data"
+resources.session.saveHandler.options.lifetimeColumn = "lifetime"
+]]></programlisting>
+
+
+    </sect2>
+
+
+</sect1>

+ 102 - 0
documentation/manual/fr/tutorials/paginator-control.xml

@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- EN-Revision: 20649 -->
+<!-- Reviewed: no -->
+<sect1 id="learning.paginator.control">
+    <title>Contrôles de la pagination et styles de défilement</title>
+
+    <para>
+        Rendre visuellement les éléments d'une page est un bon départ. Dans les sections précédentes, nous
+        avons aperçu la méthode <methodname>setCurrentPageNumber()</methodname> pour déterminer la page active.
+        Le point suivant est la navigation au travers de ces pages. Le paginateur vous fournit des outils
+        pour ça comme la possibilité de rendre un script de vue partiel et le support des styles de
+        défilement (ScrollingStyles).
+    </para>
+
+    <para>
+        La vue partiel est un bout de vue qui rend juste les contrôles de la pagination comme les boutons suivant
+        et précédent. Le design de la vue partielle est libre, il vous faudra simplement un objet Zend_View.
+        Commencez donc par créer un nouveau script de vue dans le dossier des scripts de vue. Vous pouvez
+        l'appeler comme vous voulez, nous l'appellerons "controls.phtml" de notre coté. Le manuel comporte
+        des exemples de tels scripts, en voici un.
+    </para>
+
+    <programlisting language="php"><![CDATA[
+<?php if ($this->pageCount): ?>
+<!-- First page link -->
+<?php if (isset($this->previous)): ?>
+  <a href="<?php echo $this->url(array('page' => $this->first)); ?>">
+    First
+  </a> |
+<?php else: ?>
+  <span class="disabled">First</span> |
+<?php endif; ?>
+
+<!-- Previous page link -->
+<?php if (isset($this->previous)): ?>
+  <a href="<?php echo $this->url(array('page' => $this->previous)); ?>">
+    &lt; Previous
+  </a> |
+<?php else: ?>
+  <span class="disabled">&lt; Previous</span> |
+<?php endif; ?>
+
+<!-- Next page link -->
+<?php if (isset($this->next)): ?>
+  <a href="<?php echo $this->url(array('page' => $this->next)); ?>">
+    Next &gt;
+  </a> |
+<?php else: ?>
+  <span class="disabled">Next &gt;</span> |
+<?php endif; ?>
+
+<!-- Last page link -->
+<?php if (isset($this->next)): ?>
+  <a href="<?php echo $this->url(array('page' => $this->last)); ?>">
+    Last
+  </a>
+<?php else: ?>
+  <span class="disabled">Last</span>
+<?php endif; ?>
+
+</div>
+<?php endif; ?>
+]]></programlisting>
+
+    <para>
+        Il faut maintenant indiquer à Zend_Paginator la vue partielle à utiliser. Ajoutez ceci à votre
+        bootstrap:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+Zend_View_Helper_PaginationControl::setDefaultViewPartial('controls.phtml');
+]]></programlisting>
+
+    <para>
+        La dernière étape est la plus simple. Passez un objet Paginator à un script de vue
+        (PAS 'controls.phtml'!). Ensuite, demandez simplement l'affichage de l'objet Paginator
+        lui-même. Ceci va faire intervenir l'aide de vue PaginationControl. Dans l'exemple qui suit,
+        l'objet Paginator a été affecté comme variable de vue 'paginator'. Ne vous inquiétez pas
+        si vous ne comprenez pas totalement le fonctionnement, les sections suivantes le détaillent.
+    </para>
+
+    <programlisting language="php"><![CDATA[
+<?php echo $this->paginator; ?>
+]]></programlisting>
+
+    <para>
+        Pour décider quels numéros de page afficher, le paginateur utilise des styles de défilement.
+        Le style par défaut est "Sliding", qui ressemble à la présentation des résultats de Yahoo!
+        Un style ressemblant à Google est "Elastic". Le style par défaut se règle au moyen de la méthode
+        statique <methodname>setDefaultScrollingStyle()</methodname>, ou lors du rendu du paginateur
+        dans le script de vue mais ceci nécessite un appel manuel à l'aide de vue.
+    </para>
+
+    <programlisting language="php"><![CDATA[
+// $this->paginator est un objet Paginator
+<?php echo $this->paginationControl($this->paginator, 'Elastic', 'controls.phtml'); ?>
+]]></programlisting>
+
+    <para>
+        Pour une liste de tous les styles de défilement, consultez le manuel.
+    </para>
+</sect1>