Development

Documentation/fr_FR/book/1.0/02-Exploring-Symfony-s-Code (diff)

You must first sign up to be able to contribute.

Changes between Version 12 and Version 13 of Documentation/fr_FR/book/1.0/02-Exploring-Symfony-s-Code

Show
Ignore:
Author:
Geoff (IP: 86.68.182.129)
Timestamp:
06/12/07 00:44:31 (10 years ago)
Comment:

Chngement de cible du lien'effort de traduction de HowToContibute? à Resources/fr_FR

Legend:

Unmodified
Added
Removed
Modified
  • Documentation/fr_FR/book/1.0/02-Exploring-Symfony-s-Code

    v12 v13  
    11{{{ 
    22#!html 
    3 <div style="border: solid 2px #f80;padding:10px;margin:5px;background-color: #fdb"> 
     3<div style="border: solid 3px #ff8;padding:10px;margin:5px;background-color: #ffd"> 
    44}}} 
    5 Cette partie de la documentation est en cours de traduction. Cela signifie qu'elle est traduite de manière soit incomplète, soit inexacte. En attendant que cette traduction soit terminée, vous pouvez consulter la [http://www.symfony-project.com/book/trunk/02-Exploring-Symfony-s-Code version en anglais] pour des informations plus fiables. 
     5Cette partie de la documentation n'est pas encore traduite. Vous pouvez : 
     6 
     7 * [http://www.symfony-project.com/book/trunk/about Consulter cette page en anglais] 
     8 * [wiki:Resources/fr_FR Contribuer à l'effort de traduction de la documentation] :) 
     9 
    610{{{ 
    711#!html 
    812</div> 
    913}}} 
    10  
    11 {{{ 
    12 #!WikiMarkdown 
    13  
    14  
    15 Chapitre 2 – L'exploration du code de Symfony 
    16 ============================================= 
    17  
    18 Au premier regard le code de Symfony peut sembler déroutant. Il est réparti sur plusieurs répertoires, comporte beaucoup de scripts comme des classes PHP ou du HTML, et quelque fois un mélange des deux. Il y est aussi fait référence à des classes que vous aurez du mal à retrouver dans cette arborescence étendue sur six niveaux. Mais une fois compris le pourquoi du comment de cette apparente complexité, tout vous semblera tellement naturel que vous n’aurez pas envie d’échanger votre Symfony pour autre chose (pas même contre un baril d’Ariel). Ce chapitre à pour but de détaillr le mécanisme de Symfony et de vous ôter vos dernières peurs. 
    19  
    20 Le modèle MVC  
    21 ------------- 
    22  
    23 Symfony est basé sur le modèle classique de conception web connu sous le nom architecture [MVC] [1] (Modèle – Vue – Contrôleur), composé de trois parties : 
    24  
    25    * Le Modèle, qui représente le comportement de l’application, sa logique de métier. 
    26    * La Vue, qui représente l’interface web proprement dite. 
    27    * Le Contrôleur, qui prend en charge la gestion des évènements et commande la mise à jour de la Vue ou du Modèle. 
    28  
    29 Le schéma 2-1 illustre l’architecture [MVC] [1] 
    30  
    31 Au sein de l’architecture [MVC] [1] la logique de métier (modèle) est séparée de la présentation (vue). La maintenance en est donc simplifiée. Par exemple, si votre application doit être déployée sur plusieurs navigateurs ainsi que sur des appareils mobiles, vous aurez besoin de plusieurs vues (plusieurs présentations) mais pourrez conserver le même contrôleur et le même modèle (une seule logique de métier). Le contrôleur rend l’utilisation des différents protocoles utilisés (http, email, etc… ) complètement transparent pour le modèle et la vue. Le modèle gère la logique de donnée rendant, par exemple, la vue et le contrôleur indépendant du type de base de données utilisé pour l’application. 
    32  
    33 *Schéma 2-1 L'architecture [MVC] [1]* 
    34  
    35 ![Le modèle MVC](http://www.symfony-project.com/images/book/trunk/F0201.png "Le modèle MVC") 
    36  
    37 ### L’architecture MVC 
    38  
    39 Pour mieux comprendre les avantages du modèle [MVC] [1], nous allons voir comment convertir une application PHP standard en une application basée sur l’architecture [MVC] [1]. Pour cela, nous étudierons une liste de message (post) d’un weblog. 
    40  
    41 #### La programmation standard 
    42  
    43 En programmation PHP standard, l’affichage d’une liste d’éléments d’une base de données pourrait ressembler au listing 2-1 
    44  
    45  
    46 *Listing 2-1 - Un script standard* 
    47  
    48     [php] 
    49     <?php 
    50  
    51     // Connection , sélection de la base de donnée 
    52     $link = mysql_connect('localhost', 'myuser', 'mypassword'); 
    53     mysql_select_db('blog_db', $link); 
    54  
    55     // Exécution de la requête 
    56     $result = mysql_query('SELECT date, title FROM post', $link); 
    57  
    58     ?> 
    59  
    60     <html> 
    61       <head> 
    62         <title>Liste des Messages</title> 
    63       </head> 
    64       <body> 
    65        <h1>Liste des Messages</h1> 
    66        <table> 
    67          <tr><th>Date</th><th>Title</th></tr> 
    68     <?php 
    69     // Affichage des résultats en HTML 
    70     while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) 
    71     { 
    72     echo "\t<tr>\n"; 
    73     printf("\t\t<td> %s </td>\n", $row['date']); 
    74     printf("\t\t<td> %s </td>\n", $row['title']); 
    75     echo "\t</tr>\n"; 
    76     } 
    77     ?> 
    78         </table> 
    79       </body> 
    80     </html> 
    81  
    82     <?php 
    83  
    84     // Fermeture de la connexion 
    85     mysql_close($link); 
    86  
    87     ?> 
    88  
    89  
    90 C’est rapide à écrire, à exécuter mais difficile à maintenir. Les principaux problèmes de ce code sont : 
    91  
    92    * Pas de contrôle d’erreur (que se passe-t-il si la connexion échoue ?) 
    93    * La syntaxe s’appuie sur du PHP et du HTML entremêlés. 
    94    * Le code n’est adapté qu’à la base de données MySQL. 
    95  
    96 #### Isoler la présentation 
    97  
    98 Sur le listing 2-1, l’utilisation des ordres `echo`  et `printf`  complexifie la lisibilité du code et tout changement de présentation, via une modification du source HTML, devient périlleux. Par conséquent nous diviserons ce script en deux parties. La première contiendra le code PHP et la logique de métier qui seront déplacés dans le script du contrôleur, comme indiqué dans l’exemple 2-2 
    99  
    100 *Exemple 2-2 La partie contrôleur dans `index.php`.* 
    101  
    102     [php] 
    103     <?php 
    104  
    105      // Connection, sélection de la base de données 
    106      $link = mysql_connect('localhost', 'myuser', 'mypassword'); 
    107      mysql_select_db('blog_db', $link); 
    108  
    109      // Excécution de la requête sql 
    110      $result = mysql_query('SELECT date, title FROM post', $link); 
    111  
    112      // Filling up the array for the view 
    113      $posts = array(); 
    114      while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) 
    115      { 
    116         $posts[] = $row; 
    117      } 
    118  
    119      // Fermeture de la connection 
    120      mysql_close($link); 
    121  
    122      // Affichage du résultat 
    123      require('view.php'); 
    124  
    125      ?> 
    126  
    127 Le code HTML, contenant la syntaxe PHP dédié à la présentation, sera stocké dans le script de vue comme indiqué dans l’exemple 2-3 
    128  
    129 *Exemple 2-3 – La partie vue, dans `view.php`.* 
    130  
    131     [php] 
    132     <html> 
    133       <head> 
    134         <title>Liste de Messages</title> 
    135       </head> 
    136       <body> 
    137         <h1>Liste de Messages</h1> 
    138         <table> 
    139           <tr><th>Date</th><th>Title</th></tr> 
    140         <?php foreach ($posts as $post): ?> 
    141           <tr> 
    142             <td><?php echo $post['date'] ?></td> 
    143             <td><?php echo $post['title'] ?></td> 
    144           </tr> 
    145         <?php endforeach; ?> 
    146         </table> 
    147       </body> 
    148     </html> 
    149  
    150 Pour qu’un script de vue soit de bonne qualité, il doit contenir le moins de code PHP possible et aucun ordres PHP encapsulant des balises HTML de manière à être compréhensible par un graphiste démuni de connaissances en PHP. 
    151 Les ordres les plus communs dans un script vue sont `echo`, `if/endif`, `foreach/endforeach`. 
    152  
    153 Toute la logique de donnée est placée dans le script Contrôleur et ne contient que la syntaxe PHP, sans aucun code HTML. Dans l’idéal, il faut pouvoir réutiliser le même contrôleur pour une présentation complètement différente comme une impression PDF ou un fichier XML. 
    154  
    155 #### Isoler la manipulation des données 
    156  
    157 La majeure partie du code d’un script contrôleur est dédiée à la manipulation des données. Mais que ce passerait-il si vous aviez besoin de la même liste de messages pour un autre contrôleur, comme pour la gestion d’un un flux RSS par exemple ? Comment faire si vous souhaitez conserver toutes les requêtes de base de données dans un même fichier pour éviter de dupliquer le code ? Que faire si vous décidez de changer la structure de la base de données et que la table `posts`  devient ` weblog_post` ? N’allez vous pas un jour migrer de PostgreSQL à MySQL ? Pour permettre toutes ces opérations nous allons devoir placer la manipulation des données dans un autre script appelé modèle (cf exemple 2-4) 
    158  
    159 *Exemple 2-4 La partie modèle, dans `model.php`.* 
    160  
    161     [php] 
    162     <?php 
    163  
    164     function getAllPosts() 
    165     { 
    166       // Connection, sélection de la base de données 
    167       $link = mysql_connect('localhost', 'myuser', 'mypassword'); 
    168       mysql_select_db('blog_db', $link); 
    169  
    170       // Excécution de la requête sql 
    171       $result = mysql_query('SELECT date, title FROM post', $link); 
    172  
    173       // Remplissage du tableau 
    174       $posts = array(); 
    175       while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) 
    176       { 
    177          $posts[] = $row; 
    178       } 
    179  
    180       // Fermeture de la connection 
    181       mysql_close($link); 
    182  
    183       return $posts; 
    184     } 
    185     ?> 
    186  
    187 L’exemple 2-5 montre le contrôleur modifié. 
    188  
    189 *Exemple 2-5 la partie contrôleur, dans `index.php`.* 
    190  
    191     [php] 
    192     <?php 
    193  
    194     // Appel du modèle 
    195     require_once('model.php'); 
    196  
    197     // Récupération de la liste des posts 
    198     $posts = getAllPosts(); 
    199  
    200     // Appel de la vue 
    201     require('view.php'); 
    202  
    203     ?> 
    204  
    205 Le contrôleur devient plus facile à lire. Son principal rôle est de transférer les données du modèle à la vue. Au sein d’applications plus complexes, il s’occupe aussi des requêtes, des sessions utilisateurs, de l’authentification etc… L’emploi de nom de fonctions compréhensibles peut même rendre les commentaires du contrôleur obsolètes.  
    206  
    207 Le script model est dédié à l’accès aux bases et doit être pensé en ce sens. Toutes les informations qui ne sont pas propres aux bases (comme les paramètres des requêtes) doivent être reçu du contrôleur et non intégré directement dans le modèle. De cette manière le modèle peut être réutilisé dans un autre contrôleur. 
    208  
    209 ### La séparation en couche au-delà de MVC 
    210  
    211 Pour résumer, le principe de l’architecture [MVC] [1] est de répartir les codes sur trois niveaux : la logique de données est placée dans le modèle, la présentation dans la vue, et enfin la logique applicative dans le contrôleur. 
    212  
    213 Afin de simplifier encore le codage, il est possible d’aller plus loin. Ainsi le modèle, la vue et le contrôleur peuvent aussi être divisés. 
    214  
    215 #### L’abstraction de données 
    216  
    217 La couche modèle peut être elle-même divisée en deux sous-couches : le niveau accès aux données et le niveau abstraction de données. De la sorte la partie accès de données n’utilisera pas de requêtes dépendantes du SGBD, mais fera appelle à des fonctions prévues à cet effet. Si la base de données vient à changer, seule la couche d’abstraction de données devra alors être adaptée. 
    218  
    219 Le listing 2-6 vous montre un exemple d’abstraction de données lié à MySql. Le listing montre l’exemple d’accès de données associés. 
    220  
    221 *Listing 2-6 L’abstraction de données du modèle* 
    222  
    223     [php] 
    224     <?php 
    225  
    226     function open_connection($host, $user, $password) 
    227     { 
    228       return mysql_connect($host, $user, $password); 
    229     } 
    230  
    231     function close_connection($link) 
    232     { 
    233       mysql_close($link); 
    234     } 
    235  
    236     function query_database($query, $database, $link) 
    237     { 
    238       mysql_select_db($database, $link); 
    239  
    240       return mysql_query($query, $link); 
    241     } 
    242  
    243     function fetch_results($result) 
    244     { 
    245       return mysql_fetch_array($result, MYSQL_ASSOC); 
    246     } 
    247  
    248 *Listing 2-7 - Accès aux données du modèle* 
    249  
    250     [php] 
    251     function getAllPosts() 
    252     { 
    253       // Connection à la base de données 
    254       $link = open_connection('localhost', 'myuser', 'mypassword'); 
    255  
    256       // Excécution de la requête sql 
    257       $result = query_database('SELECT date, title FROM post', 'blog_db', $link); 
    258  
    259       // Remplissage du tableau 
    260       $posts = array(); 
    261       while ($row = fetch_results($result)) 
    262       { 
    263          $posts[] = $row; 
    264       } 
    265  
    266       // Fermeture de la connection 
    267       close_connection($link); 
    268  
    269       return $posts; 
    270     } 
    271     ?> 
    272  
    273 On constate qu’aucunes fonctions dépendantes de la base de données ne se trouvent dans la partie accès de données. De plus, les fonctions de la partie abstraction de données peuvent être réutilisées pour d’autres fonctions du modèle ayant besoin d’un accès à la base de données. 
    274  
    275 >**NOTE** 
    276 >Quelques petites améliorations devraient encore être apportées aux exemples 2-6 et 2-7 pour qu’ils soient pleinement satisfaisants (indépendance du code SQL, mise en classes de toutes les fonctions etc …). Mais tel n’est pas le but de ce livre et dans le chapitre 8 vous découvrirez que Symfony gère très bien tous les types d’abstraction. 
    277  
    278 #### La partie Vue 
    279  
    280 La vue aussi peut faire l’objet d’une séparation de code. Une page contient souvent des éléments communs à toute l’application comme l’entête, le pied de page, la charte graphique, les principes de navigations etc… Seule le contenu de la page est appelé à changer. Ainsi on peut distinguer deux parties dans la vue : la maquette (layout) et le gabarit (template). 
    281 La maquette est généralement globale à l’application ou à un groupe de pages et le gabarit met en forme les données fournies par le contrôleur. Une troisième partie est la vue logique (ou simplement vue) qui permet aux deux premières de travailler de concert. 
    282 En appliquant ces principes, le listing 2-3 peut être séparé en trois parties comme le montrent les listings 2-8, 2-9 et 2-10 
    283  
    284 *Listing 2-8 La partie gabarit de la vue, dans `mytemplate.php`.* 
    285  
    286     [php] 
    287     <h1>Liste de messages</h1> 
    288     <table> 
    289     <tr><th>Date</th><th>Title</th></tr> 
    290     <?php foreach ($posts as $post): ?> 
    291       <tr> 
    292         <td><?php echo $post['date'] ?></td> 
    293        <td><?php echo $post['title'] ?></td> 
    294       </tr> 
    295     <?php endforeach; ?> 
    296     </table> 
    297  
    298 *Listing 2-9 La vue logique de la vue* 
    299  
    300     [php] 
    301     <?php 
    302   
    303     $title = 'Liste de messages'; 
    304     $content = include('mytemplate.php'); 
    305     ?> 
    306  
    307 *Listing 2-10 La partie maquette de la vue* 
    308  
    309     [php] 
    310  
    311     <html> 
    312       <head> 
    313        <title><?php echo $title ?></title> 
    314       </head> 
    315       <body> 
    316         <?php echo $content ?> 
    317       </body> 
    318     </html> 
    319  
    320  
    321 #### Action et contrôleur principale (front controller). 
    322  
    323 Dans les exemples précédents, le contrôleur ne fait pas grand chose, mais dans une application web réelle, il est sûrement celui qui à le plus de travaille. De plus, la plus part des contrôleurs partagent en grande partie les mêmes actions comme la gestion des requêtes, la sécurité, la configuration de l’application etc… C’est pourquoi les contrôleurs sont plus souvent représentés par un contrôleur principale unique à l’application et par les actions, qui ne contiennent que le code contrôleur spécifique à certaines pages. 
    324  
    325 #### Orienté objet. 
    326  
    327 Tous les exemples précédents s'appuient sur les principes de la programmation procédurale. Mais les possibilités de la programmation orientée objet (POO ou OOP) des langages modernes permettent de rendre les développements encore plus simples grâce à l’encapsulation, l’héritage d’autres objets et permettent, en outre, d’avoir des normes de codifications simples. 
    328  
    329 Implémenter une architecture avec un langage non objet augmente les risques de duplications de codes, de collisions de nom et d’une manière générale rend le source plus difficile à lire. 
    330  
    331 L’orientation objet permet aux développeurs de travailler avec les objets vue, contrôleur et les classes du modèle, et permet de transformer toutes les fonctions des exemples précédents (php standard) en méthodes. C'est un avantage considérable. 
    332  
    333 >**TIP** 
    334 >Si vous voulez approfondir vos connaissances sur les Design Patterns pour le web en orienté objet, procurez-vous le livre Patterns of Entreprise Application Architecture de Martin Fowler (Addison-Wesley, ISBN : 0-32112-742-0). Les exemples sont en Java ou C#, mais restent compréhensibles pour un développeur PHP. [http://www.amazon.fr/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420/ref=sr_11_1/402-5852976-8124116?ie=UTF8&qid=1180975022&sr=11-1 "Sur Amazon.com"] 
    335  
    336 ### L’implémentation [MVC] [1] de Symfony 
    337  
    338 Revenons à notre liste de messages. Combien de couches faut-il donc implémenter pour obtenir cette simple page ? Nous avons identifié les éléments illustrés par le schéma 2-2 : 
    339  
    340    * Niveau Modèle 
    341       * Abstraction de données 
    342       * Accès aux données 
    343    * Niveau Vue 
    344       * Vue (logique de vue) 
    345       * Gabarit 
    346       * La maquette 
    347    * Le niveau Contrôleur  
    348      * Le contrôleur principal 
    349      * Les actions 
    350  
    351 Sept scripts ! Beaucoup de fichiers à ouvrir et à modifier pour chaque nouvelle page ! 
    352 Cependant, Symfony rend les choses faciles car tout en prenant le meilleur de l’architecture [MVC] [1], il l’implémente de manière à rendre le développement rapide et aisé. 
    353  
    354 Tout d’abord, le contrôleur principal et la maquette sont commun à toute l’application. Vous pouvez en avoir plusieurs mais un seul de chaque est nécessaire. Le contrôleur principal est un composant pure [MVC] [1], ce qui veut dire que vous n’aurez jamais à le coder, Symfony le générera pour vous. 
    355  
    356 L’autre bonne nouvelle est que les classes du niveau modèle sont aussi générées automatiquement en fonction de votre base de données et ce grâce à Proprel. Cette librairie gère les clés étrangères et les champs de date, utilise les « setters » et « getters » facilitant encore plus la manipulation de données. De plus, l’abstraction de données est complètement transparente pour vous puisqu’entièrement gérée par une autre composant appelé Creole. Ainsi, si vous décidez de changer de SGBD, vous n’aurez pas de code à récrire, mais juste à modifier un paramètre de la configuration. 
    357  
    358 Enfin, la logique de vue peut s’appuyer sur un simple fichier de configuration, sans avoir besoin de programmation. 
    359  
    360 *Schéma 2-2 Le processus Symfony* 
    361  
    362 ![Diagramme de flux de Symfony](http://www.symfony-project.com/images/book/trunk/F0202.png "Diagramme de flux de Symfony") 
    363  
    364 Il en résulte que notre liste de messages ne requiert plus que trois fichiers pour fonctionner comme le montrent les listings 2-11, 2-12, 2-13 
    365  
    366 *Listing 2-11 Actions de `list` de `myproject/apps/myapp/modules/weblog/actions/actions.class.php`.* 
    367  
    368     [php] 
    369     <?php 
    370     class weblogActions extends sfActions 
    371     { 
    372       public function executeList() 
    373         { 
    374         $this->posts = PostPeer::doSelect(new Criteria()); 
    375         } 
    376     } 
    377     ?> 
    378  
    379 *Listing 2-12 Template de `list`, de `myproject/apps/myapp/modules/weblog/templates/listSuccess.php`.* 
    380  
    381     [php] 
    382     <h1>Liste de messages</h1> 
    383     <table> 
    384     <tr><th>Date</th><th>Title</th></tr> 
    385     <?php foreach ($posts as $post): ?> 
    386       <tr> 
    387         <td><?php echo $post->getDate() ?></td> 
    388         <td><?php echo $post->getTitle() ?></td> 
    389       </tr> 
    390     <?php endforeach; ?> 
    391     </table> 
    392  
    393 *Listing 2-13 Vue de `list`, de `myproject/apps/myapp/modules/weblog/config/view.yml`.* 
    394  
    395     listSuccess: 
    396       metas: { title: List of Posts } 
    397   
    398 De plus, vous allez aussi devoir définir une maquette, comme le montre le listing 2-14.  Elle sera régulièrement réutilisée. 
    399  
    400 *Listing 2-14 – Maquette de `list`, dans `myproject/apps/myapp/templates/layout.php`.* 
    401     [php] 
    402     <html> 
    403       <head> 
    404         <?php echo include_title() ?> 
    405       </head> 
    406       <body> 
    407         <?php echo $sf_data->getRaw('sf_content') ?> 
    408       </body> 
    409     </html> 
    410  
    411 Voilà donc tout ce qui vous est nécessaire. Ce code a exactement le même effet que celui écrit en PHP standard vu plus haut sur le listing 2-1. Faire fonctionner tous les composants ensemble n'est pas de votre ressort et est géré pas Symfony. Si vous inspectez le code vous verrez que le développement de la liste de messages en architecture [MVC] [1] ne requiert pas plus de temps, ni de code que l'écriture en PHP standard. 
    412 Cependant, cela vous apporte de grands avantages comme une organisation plus claire du code, la possibilité de le réutiliser facilement, de la flexibilité, des possibilités de debug, une configuration aisée, l'abstraction de données, l'URL rewriting, le multi-environnement et encore beaucoup d'outils de développement. 
    413  
    414 #### Le noyau de Symfony 
    415  
    416 L'implémentation [MVC] [1] de Symfony utilise plusieurs classes que vous rencontrerez plusieurs fois dans ce livre : 
    417  
    418    * ‘sfController` est la classe contrôleur. Elle interprète les requêtes et les transmets aux actions. 
    419    * ‘sfRequest` conserve les éléments des requêtes comme les paramètres, les cookies, les entêtes etc ... 
    420    * ‘sfReponse` contient les entêtes et contenu des réponses. C'est l'objet qui peut éventuellement converti en HTML et renvoyé le résultat à l'utilisateur. 
    421    * Le contexte (récupérer par `sfContext::getInstance()`) conserve une référence de chaque objets du noyau et de la configuration courante. Il est accessible de n'importe où. 
    422  
    423 Vous pourrez en apprendre plus sur ces objets au chapitre 6. 
    424  
    425 Comme vous pouvez le constater les classes Symfony sont préfixées par `sf` comme le sont toutes les variables du noyau. Cela permet d'éviter les conflits de nom avec vos classes et variables, et rend les classes du noyau plus parlantes et faciles à reconnaître. 
    426  
    427 >**NOTE** 
    428 >Dans Symfony, la méthode de codification UpperCamelCase est utilisée nommer les classes et variables. Deux exceptions à cela, les classes du noyau commençant par `sf` qui est en minuscule et les variables des gabarits qui utilisent la séparation par underscore. 
    429  
    430 L'organisation du code 
    431 ---------------------- 
    432  
    433 Maintenant que vous connaissez les différents composants de Symfony vous vous demandez sûrement comment ils sont agencés. Symfony organise le code par projets et chaque projet possède une arborescence standard. 
    434  
    435 ### La structure des projets: applications, modules et actions. 
    436  
    437 Avec Symfony, un projet est un ensemble de services et opérations réunis sous un nom de domaine donné, partageant le même modèle objet. 
    438  
    439 Au sein d'un projet, les opérations sont regroupées logiquement en applications. Une application peut normalement fonctionner indépendamment des autres applications du même projet. Dans la plus part des cas, un projet contiendra deux applications : le front-office et le back-office partageant les même base de donnée. Mais un même projet peut contenir plusieurs mini-sites, qui sont alors chacun une application différente. Dans ce cas les liens entre les applications doivent être des adresses absolues. 
    440  
    441 Chaque application est un ensemble d'un ou plusieurs modules. Un module correspond généralement à une page ou un groupe de page traitant du même sujet. Par exemple, vous pouvez avoir les modules `accueil`, `articles`, `aide`, `caddy`, `compte` etc ... 
    442  
    443 Les modules contiennent des actions qui peuvent être utilisées au sein de ce module. Par exemple, un `caddy` peut comporter les actions `ajouter`, `afficher`, `mettre à jour` etc ... Généralement, les actions peuvent être décrites par un simple verbe. Une action peut être vue comme une page particulière d'une application web classique, à ce ceci près que deux actions peuvent avoir comme résultat la même page. (par exemple, ajouter une commentaire dans un message d'un weblog réaffiche ce message avec le nouveau commentaire.) 
    444  
    445 >**TIP** 
    446 >Si cette organisation est trop étoffée pour un premier projet, il est possible de regrouper toutes les actions dans un seul module. Quand l'application deviendra plus complexe, il sera encore temps d'organiser les actions dans des modules séparés. Comme indiqué dans le chapitre 1, réécrire le code pour améliorer son organisation ou sa lisibilité tout en conservant son comportement est appelé le refactoring, et vous ferez souvent ça lorsque vous appliquerez les principes du RAD. 
    447  
    448 Le schéma 2-3 vous montre un exemple d'organisation de code pour un weblog avec une structure projet/application/module/action. Notez que l'arborescence réelle du projet différera de l'organisation montrée dans ce schéma. 
    449  
    450 *Schéma 2-3 Exemple d'organisation de code.* 
    451  
    452 ![Exemple d'organisation du code](http://www.symfony-project.com/images/book/trunk/F0203.png "Exemple d'organisation du code") 
    453  
    454  
    455 ### L'arborescence 
    456  
    457 La plus part des projets web partagent un certains nombres d'éléments comme : 
    458  
    459    * une base de données comme MySQL ou PostgreSQL 
    460    * des fichiers statiques (HTML, images, fichiers JavaScript, feuilles de styles etc ...) 
    461    * des fichiers ajoutés par les utilisateurs ou administrateurs 
    462    * des classes et librairies PHP 
    463    * des libraires externes (scripts externes) 
    464    * des fichiers batch (des scripts lancés par des lignes commandes ou via les tâches planifiées) 
    465    * des fichiers de logs (traces laissées par une application et/ou le serveur) 
    466    * des fichiers de configuration. 
    467  
    468 Symfony fournit une arborescence standard de dossiers afin d’organiser de façon logique le contenu et conformément aux choix de la l’architecture (modèles [MVC] [1] regroupement projet/application/module). 
    469 Cet arborescence est automatiquement crée à l’initialisation de chaque projets, applications ou modules. Naturellement, libre à vous de l’adapter à vos besoins ou à ceux des clients. 
    470  
    471 #### L’arborescence à la racine 
    472  
    473 Voici l’arborescence standard d’un projet Symfony : 
    474  
    475     apps/ 
    476       frontend/ 
    477       backend/ 
    478     batch/ 
    479     cache/ 
    480     config/ 
    481     data/ 
    482       sql/ 
    483     doc/ 
    484     lib/ 
    485       model/ 
    486     log/ 
    487     plugins/ 
    488     test/ 
    489       unit/ 
    490       functional/ 
    491     web/ 
    492       css/ 
    493       images/ 
    494       js/ 
    495       uploads/ 
    496  
    497 Le tableau 2-1 décrit le contenu des ces répertoires 
    498  
    499 *Tableau 2-1 Répertoires racines* 
    500  
    501 Répertoire | Description 
    502 -----------|------------- 
    503 `apps/`    | Contient un répertoire par applications du projet (communément `fronteend` et `backend` pour le front et le back office) 
    504 `batch/`   | Contient les scripts PHP appelés pas une ligne de commande ou un planificateur de tâches 
    505 `cache/`   | Contient le cache de la configuration et (si vous l’activez) le cache des actions et des gabarits du projet. Le cache (décrit au chapitre 12) utilise ces fichiers pour améliorer les temps de réponses des requêtes. Chaque applications y aura donc un sous-répertoire contenant des processus PHP ou HTML prétraité. 
    506 `config/`  | Contient la configuration générale du projet 
    507 `data/`    | Tout ce qui est relatif aux bases de données est conservé ici : le schéma de la base de donné, les fichiers SQL de création etc … 
    508 `doc/`     | Contient la documentation du projet y compris votre propre documentation et celle générée par PHPdoc 
    509 `lib/`     | Ce répertoire est réservé aux classes et librairies extérieures. Vous pouvez-y ajouter du code devant être partagé par toutes vos applications. Le répertoire `model/`contient le modèle objet du projet (cf. Chapitre 8) 
    510 `log/`     | Ici sont conservés les fichiers logs générés par Symfony. Il peut aussi contenir les logs du serveur web, des bases de données ou n’importe quels autres fichiers de logs du projet. Symfony crée un fichier de logs par application et environnement (cf Chapitre 16) 
    511 `plugins/` | Ce répertoire contient les plugins installés pour cette application (cf Chapitre 17) 
    512 `test/`    | Il contient des jeux d’essai unitaire et fonctionnel écrit en php et compatible avec le framework de test de Symfony (cf Chapitre 15). 
    513 `web/`     | La racine du serveur web. Seuls les fichiers se trouvant dans ce fichier sont accessible via Internet. 
    514  
    515  
    516 #### L’arborescence d’une application 
    517  
    518 L’arborescence d’une application est identique : 
    519  
    520     apps/ 
    521       [nom de l’application]/ 
    522         config/ 
    523         i18n/ 
    524         lib/ 
    525         modules/ 
    526         templates/ 
    527           layout.php 
    528           error.php 
    529           error.txt 
    530  
    531 Le tableau 2-2 décrit les répertoires d’une application 
    532  
    533 *Tableau 2-2 Répertoires d’une application* 
    534  
    535 Répertoire   | Description 
    536 -------------|------------ 
    537 `config/`    | Contient l’ensemble des fichiers de configuration YAML. Le plus gros de la configuration de l’application se trouve ici mis à part les paramètres par défaut conservé  au sein du framwork lui-même. Remarque : les paramètres par défaut peuvent être écrasés ici si nécessaire. Vous en apprendrez plus sur la configuration d’une application au chapitre 5 
    538 `I18n/`      | Contient les fichiers d’internationalisation de l’application, des fichiers de traduction de l’interface la plus part du temps. (Cf Chapitre 13) Vous pouvez vous passer de ces fichiers si vous gérez l’internationalisation pas la base de donnée 
    539 `lib/`       | Contient les librairies et les classes spécifiques à l’application 
    540 `modules/`   | Contient tous les modules propres à l’application 
    541 `templates/` | Contient tous les gabarits de l’application, ceux partagé par tous les modules. Par défaut, il contient `layout.php` qui est la maquette dans laquelle tous les gabarits sont insérés. 
    542  
    543 >**NOTE** 
    544 >Les répertoires `i18/`, `lib/` et `modules/` sont vides pour une nouvelle application. 
    545  
    546 Les classes d’une application ne sont pas capables d’accéder aux méthodes ou attributs d’une tierce application d’un même projet.  
    547 Lorsque vous déciderez de la manière de diviser votre projet en plusieurs applications, vous devrez garder à l’esprit que les liens hypertextes entre ces différentes applications devront être de forme absolue. 
    548  
    549 #### L’arborescence du module 
    550  
    551 Chaque application contient un ou plusieurs modules. Chaque module possède sa propre arborescence au sein du répertoire modules, et le nom du module est préciser au moment de l'installation. 
    552  
    553 Voici l’arborescence classique d’un module : 
    554  
    555     apps/ 
    556       [nom de l’application]/ 
    557         modules/ 
    558           [nom du module]/ 
    559               actions/ 
    560                 actions.class.php 
    561               config/ 
    562               lib/ 
    563               templates/ 
    564                 indexSuccess.php 
    565               validate/ 
    566  
    567 Le tableau 2-3 décris les répertoires du module 
    568  
    569 *Tableau 2-3 Répertoires du module* 
    570  
    571 Répertoire | Description 
    572 -----------|------------ 
    573 `actions/`   | En règle générale, ce répertoire possède ne contient que la classe `actions.class.php` qui regroupe toutes les actions du modules. Il est aussi possible d’écrire plusieurs actions dans des fichiers séparés 
    574 `config/`    | Il peut contenir des fichiers de paramétrages locaux pour les modules 
    575 `lib/`       | Contient les classes et librairies spécifiques au module 
    576 `template/`  | Contient les gabarits correspondant aux actions du module. Un gabarit par défaut appelé `indexSucces.php`, est crée par défaut à l’installation du module 
    577 `validate/`  | Dédié à la configuration des fichiers utilisés par le formulaire de validation (cf Chapitre 10)  
    578  
    579 >**NOTE** 
    580 >Les dossiers `config/`, `lib/` et `validate/` sont vides à la création d’un nouveau module. 
    581  
    582 #### L’arborescence web 
    583  
    584 Le dossier web, qui regroupe tous les fichiers accessible sur le net, n’a que peu de sous-répertoires. 
    585 Le respect de conventions de nommage clair facilitera l’utilisation de ces dossiers dans les gabarits. Voici un exemple de l’arborescence d’un dossier  
    586 web 
    587  
    588     web/ 
    589       css/ 
    590       images/ 
    591       js/ 
    592       uploads/ 
    593  
    594 Par convention, les fichiers statiques sont répartis dans les dossiers décris par le tableau 2-4 
    595  
    596 *Tableau 2-4 – Arborescence Web classique* 
    597  
    598 Répertoire | Description 
    599 -----------|------------ 
    600 `css/`     | Contient les feuilles de styles avec l’extension `.css` 
    601 `images/`  | Contient les images aux formats `.jpg`, `.png` ou `.gif` 
    602 `js/`      | Contient les fichiers JavaScript avec l’extension `.js` 
    603 `uploads/` | Doit contenir les images uploadées par l’utilisateur. Même si le dossier contient des images, il est bien distinct du dossier des images afin que la synchronisation des serveurs de développement et de production, n’affecte pas les images uploadées. 
    604  
    605 >**NOTE** 
    606 >Même s’il est fortement conseillé de ne pas modifier l’arborescence par défaut, il est possible de le faire pour des besoins spécifiques, comme permettre à un projet de tourner sur un serveur à l’arborescence et aux conventions de codage différents. Cf Chapitre 19 pour plus d’information sur la modification d’arborescence. 
    607  
    608 Outils communs 
    609 -------------- 
    610  
    611 Dans ce livre et dans vos projets, vous serez fréquemment confronté à certaines techniques très couramment utilisées au sein de Symfony comme les conteneurs de paramètres, les constantes et l’auto-chargement des classes 
    612  
    613 ### Le conteneur de paramètres 
    614  
    615 Beaucoup de classes Symfony possède un conteneur de paramètre. C’est un moyen simple d’encapsuler un attribut avec des méthodes getter et setter correct. Par exemple, la classe `sfResponse` possède un conteneur de paramètre que vous pouvez utiliser en appelant la méthode `getParameterHolder()`. Chaque conteneur de paramètre conserve les données comme illustré par le listing 2-15. 
    616  
    617 *Listing 2-15 Utilisation du conteneur de paramètre de `sfResponse`* 
    618  
    619     [php] 
    620     $response->getParameterHolder()->set(‘foo’, ‘bar’); 
    621     Echo $response->getParameterHolder()-get(‘foo’); 
    622     => ‘bar’ 
    623  
    624  
    625 La plus part des classes utilisant le conteneur de paramètre se servent de méthodes intermédiaires pour raccourcir le code saisi pour les opérations get/set. Dans le cas de l’objet `sfResponse`, l’opération décrite dans le listing 2-15 peut-être simplifiée comme le montre le listing 2-16 
    626  
    627 *Listing 2-16 Utilisation des méthodes intermédiaire des conteneurs de paramètres de `sfResponse`* 
    628  
    629     [php] 
    630     $response->setParameter(‘foo’, ‘bar’); 
    631     Echo $response->getParameter(‘foo’); 
    632     => ‘bar’ 
    633  
    634  
    635 La méthode getter du conteneur de paramètre accepte une valeur par défaut comme second argument ce qui permet un échappement automatique bien plus léger qu’un équivalent réalisé par un codage conditionnel. Le listing 2-17 illustre ce point de vue. 
    636  
    637 *Listing 2-17 – Utilisation de la valeur par défaut de l’attribut du getter* 
    638  
    639     [php] 
    640     // Le paramètre 'foobar' n’est pas défini, donc le getter renvoie une valeur vide 
    641     echo $response->getParameter('foobar'); 
    642     => null 
    643   
    644     // Une valeur par défaut peut-être utilisée en ajoutant le getter dans la condition suivante 
    645     if ($response->hasParameter('foobar')) 
    646     { 
    647       echo $response->getParameter('foobar'); 
    648     } 
    649     else 
    650     { 
    651       echo 'default'; 
    652     } 
    653      => default 
    654   
    655     // Mais il est plus rapide d’utiliser le deuxième argument du getter pour cela. 
    656     echo $response->getParameter('foobar', 'default'); 
    657     => default 
    658  
    659  
    660 Les conteneurs de paramètres peuvent aussi supporter les espaces de nommage. Si vous spécifiés un troisième paramètres, il sera interprété comme un espace de nommage et le paramètre sera alors défini uniquement dans cette espace. Le Listing 2-18 illustre ce point. 
    661  
    662 *Listing 2-18 – Utilisation de l’espace de nommage du conteneur de paramètre de la méthode `sfResponse`* 
    663  
    664     [php] 
    665     $response->setParameter(‘foo’, ‘bar1’) ; 
    666     $response->setParameter(‘foo’, ‘bar2’, ‘my/name/space’); 
    667     Echo $response->getParameter(‘foo’); 
    668     => ‘bar1’ 
    669     Echo $response->getParamater(‘foo’, null, ‘my/name/space’); 
    670     => ‘bar2’ 
    671  
    672  
    673 Vous pouvez bien évidemment ajouter un conteneur de paramètre dans vos propres classes pour profiter de cette fonctionnalité. Le listing 2-19 vous explique comment définir une classe avec un conteneur de paramètre. 
    674  
    675 *Listing 2-19 Ajouter un conteneur de paramètre à une classe* 
    676  
    677     [php] 
    678     class MyClass 
    679     { 
    680       protected $parameter_holder = null; 
    681       public function initialize ($parameters = array()) 
    682       { 
    683         $this->parameter_holder = new sfParameterHolder(); 
    684         $this->parameter_holder->add($parameters); 
    685       } 
    686   
    687       public function getParameterHolder() 
    688       { 
    689         return $this->parameter_holder; 
    690       } 
    691     } 
    692  
    693  
    694 ### Constantes 
    695  
    696 Étrangement vous ne trouverez que peu de constantes dans Symfony et ce pour le simple fait qu’il existe une contrainte majeure en PHP : une fois définie, leur valeur devient non modifiable. C’est pour cela que pour remplacer les constantes, Symfony utilise son propre objet de configuration : `sfConfig`. Grace à ses méthodes statiques, vous pouvez atteindre ce paramètre de n’importe où. Le listing 2-20 vous montre comment utiliser l’objet sfConfig. 
    697  
    698 *Listing 2-20 Utilisation de l’objet `sfConfig` à la place des constantes* 
    699  
    700     [php] 
    701     // A la place des constantes, 
    702     define('SF_FOO', 'bar'); 
    703     echo SF_FOO; 
    704     // Symfony utilise l’objet `sfConfig` 
    705     sfConfig::set('sf_foo', 'bar'); 
    706     echo sfConfig::get('sf_foo'); 
    707  
    708 La méthode `sfConfig` accepte un paramètre par défaut et vous pouvez appeler plusieurs fois la méthode `sfConfig::set()` pour le même paramètre afin de modifier sa valeur. Vous trouverez plus d’informations sur la méthode `sfConfig` au chapitre 5. 
    709  
    710 ### Auto-chargement des classes 
    711  
    712 De façon standard, lorsque vous souhaitez utiliser une classe ou créer un objet en PHP, vous devez tout d’abord inclure explicitement la définition de cette classe 
    713  
    714     [php] 
    715     Include ‘classes/MyClass.php’; 
    716     $myObject = new MyClass(); 
    717  
    718  
    719 Mais au sein de projets volumineux possédant beaucoup de classes et une architecture complexe, se souvenir de tous les fichiers à inclure et de leur chemin devient fastidieux. En proposant la fonction __autoload() –ou la fonction `spl_autoload_register()`), Symfony rend obsolète l’emploi de l’ordre `include`. Vous pouvez alors directement écrire 
    720  
    721     [php] 
    722     $myObject = new MyClass(); 
    723  
    724  
    725 Dès lors, Symfony recherche la définition de `MyClass` dans tous les fichiers d’extension `.php` présent dans l’un des répertoires `lib/` du projet. S’il la trouve, elle est incluse automatiquement. 
    726  
    727 Par conséquent, si vous conservez toutes vos classes dans les répertoires `lib`, vous n’aurez jamais à inclure aucunes classes. C’est exactement pourquoi les projets Symfony n’utilisent jamais les ordres `include` ou `require`. 
    728  
    729 >**NOTE** 
    730 >Dans le but d’améliorer les performances, l’auto-chargement de Symfony parcours une liste de répertoires (définis dans un fichier interne de configuration) à l’occasion de la première requête. Toutes les classes sont passées en revue par répertoire et l’association classe/fichier est sauvegardée dans un tableau associatif.  De cette manière, les futurs requêtes n’auront pas besoin de refaire la vérification. Voilà aussi pourquoi vous devez vider le cache à chaque fois que vous ajoutez ou supprimer une classe dans votre projet et lançant la commande Symfony clear-cache. Vous en apprendrez plus sur le cache au chapitre 12 et la configuration de l’auto-chargement au chapitre 19. 
    731  
    732 Résumé 
    733 ------ 
    734  
    735 L’usage d’un framework basé sur [MVC] [1] vous oblige à répartir et organiser votre code en accord certaines règles précises. Le code de présentation est placé dans la vue, le modèle hérite du code de manipulation de données, et toute la partie gestion des requêtes se retrouve au niveau du contrôleur. Ceci rend les applications s’appuyant sur l’architecture [MVC] [1] à la fois plus simple à utiliser et plus contraignantes. 
    736  
    737 Symfony est un framework [MVC] [1] écrit en PHP5. Il tire le meilleur parti de l’architecture [MVC] [1] tout en conservant une grande simplicité d’utilisation. Au regard sa souplesse et de ses grandes possibilités de configuration, Symfony est adapté à tout type de projet web. 
    738  
    739 Maintenant que vous avez compris la théorie sous-jacente à Symfony, vous êtes presque prêt pour développer votre première application. Mais avant cela vous avez besoin d’installer et configurer Symfony sur un serveur de développement. 
    740  
    741 [1]: http://fr.wikipedia.org/wiki/MVC "MVC sur Wikipédia" 
    742  
    743 }}}