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 13 and Version 14 of Documentation/fr_FR/book/1.0/02-Exploring-Symfony-s-Code

Show
Ignore:
Author:
Geoff (IP: 88.191.40.240)
Timestamp:
07/24/07 17:52:30 (10 years ago)
Comment:

--

Legend:

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

    v13 v14  
    11{{{ 
    22#!html 
    3 <div style="border: solid 3px #ff8;padding:10px;margin:5px;background-color: #ffd"> 
     3<div style="border: solid 2px #f80;padding:10px;margin:5px;background-color: #fdb"> 
    44}}} 
    5 Cette 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  
     5Cette 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. 
    106{{{ 
    117#!html 
    128</div> 
     9<br> 
    1310}}} 
     11 
     12{{{ 
     13#!WikiMarkdown 
     14    
     15 
     16Chapitre 2 – L'exploration du code de Symfony 
     17============================================= 
     18 
     19Au 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 a pour but de détailler le mécanisme de Symfony et de vous ôter vos dernières peurs. 
     20 
     21Le modèle MVC  
     22------------- 
     23 
     24Symfony 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 : 
     25 
     26   * Le Modèle, qui représente le comportement de l’application, sa logique de métier. 
     27   * La Vue, qui représente l’interface web proprement dite. 
     28   * Le Contrôleur, qui prend en charge la gestion des évènements et commande la mise à jour de la Vue ou du Modèle. 
     29 
     30Le schéma 2-1 illustre l’architecture [MVC] [1] 
     31 
     32Au 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 transparente 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épendants du type de base de données utilisé pour l’application. 
     33 
     34*Schéma 2-1 L'architecture [MVC] [1]* 
     35 
     36![Le modèle MVC](http://www.symfony-project.com/images/book/trunk/F0201.png "Le modèle MVC") 
     37 
     38### L’architecture MVC 
     39 
     40Pour 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 messages (*posts*) d’un weblog. 
     41 
     42#### La programmation standard 
     43 
     44En programmation PHP standard, l’affichage d’une liste d’éléments d’une base de données pourrait ressembler au listing 2-1 
     45 
     46 
     47*Listing 2-1 - Un script standard* 
     48 
     49    [php] 
     50    <?php 
     51 
     52    // Connection , sélection de la base de données 
     53    $link = mysql_connect('localhost', 'myuser', 'mypassword'); 
     54    mysql_select_db('blog_db', $link); 
     55 
     56    // Exécution de la requête 
     57    $result = mysql_query('SELECT date, title FROM post', $link); 
     58 
     59    ?> 
     60 
     61    <html> 
     62      <head> 
     63        <title>Liste des Messages</title> 
     64      </head> 
     65      <body> 
     66       <h1>Liste des Messages</h1> 
     67       <table> 
     68         <tr><th>Date</th><th>Title</th></tr> 
     69    <?php 
     70    // Affichage des résultats en HTML 
     71    while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) 
     72    { 
     73    echo "\t<tr>\n"; 
     74    printf("\t\t<td> %s </td>\n", $row['date']); 
     75    printf("\t\t<td> %s </td>\n", $row['title']); 
     76    echo "\t</tr>\n"; 
     77    } 
     78    ?> 
     79        </table> 
     80      </body> 
     81    </html> 
     82 
     83    <?php 
     84 
     85    // Fermeture de la connexion 
     86    mysql_close($link); 
     87 
     88    ?> 
     89 
     90 
     91C’est rapide à écrire et à exécuter mais difficile à maintenir. Les principaux problèmes de ce code sont : 
     92 
     93   * Pas de contrôle d’erreur (que se passe-t-il si la connexion échoue ?) 
     94   * La syntaxe s’appuie sur du PHP et du HTML entremêlés. 
     95   * Le code n’est adapté qu’à la base de données MySQL. 
     96 
     97#### Isoler la présentation 
     98 
     99Sur 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 
     100 
     101*Exemple 2-2 La partie contrôleur dans `index.php`.* 
     102 
     103    [php] 
     104    <?php 
     105 
     106     // Connexion, sélection de la base de données 
     107     $link = mysql_connect('localhost', 'myuser', 'mypassword'); 
     108     mysql_select_db('blog_db', $link); 
     109 
     110     // Excécution de la requête sql 
     111     $result = mysql_query('SELECT date, title FROM post', $link); 
     112 
     113     // Filling up the array for the view 
     114     $posts = array(); 
     115     while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) 
     116     { 
     117        $posts[] = $row; 
     118     } 
     119 
     120     // Fermeture de la connection 
     121     mysql_close($link); 
     122 
     123     // Affichage du résultat 
     124     require('view.php'); 
     125 
     126     ?> 
     127 
     128Le code HTML, contenant la syntaxe PHP dédiée à la présentation, sera stocké dans le script de vue comme indiqué dans l’exemple 2-3 
     129 
     130*Exemple 2-3 – La partie vue, dans `view.php`.* 
     131 
     132    [php] 
     133    <html> 
     134      <head> 
     135        <title>Liste de Messages</title> 
     136      </head> 
     137      <body> 
     138        <h1>Liste de Messages</h1> 
     139        <table> 
     140          <tr><th>Date</th><th>Title</th></tr> 
     141        <?php foreach ($posts as $post): ?> 
     142          <tr> 
     143            <td><?php echo $post['date'] ?></td> 
     144            <td><?php echo $post['title'] ?></td> 
     145          </tr> 
     146        <?php endforeach; ?> 
     147        </table> 
     148      </body> 
     149    </html> 
     150 
     151Pour 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. 
     152Les ordres les plus communs dans un script vue sont `echo`, `if/endif`, `foreach/endforeach`. 
     153 
     154Toute la logique de traitement des données 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. 
     155 
     156#### Isoler la manipulation des données 
     157 
     158La majeure partie du code d’un script contrôleur est dédiée à la manipulation des données. Mais que se passerait-il si vous aviez besoin de la même liste de messages pour un autre contrôleur, comme pour la gestion d’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) 
     159 
     160*Exemple 2-4 La partie modèle, dans `model.php`.* 
     161 
     162    [php] 
     163    <?php 
     164 
     165    function getAllPosts() 
     166    { 
     167      // Connexion, sélection de la base de données 
     168      $link = mysql_connect('localhost', 'myuser', 'mypassword'); 
     169      mysql_select_db('blog_db', $link); 
     170 
     171      // Excécution de la requête sql 
     172      $result = mysql_query('SELECT date, title FROM post', $link); 
     173 
     174      // Remplissage du tableau 
     175      $posts = array(); 
     176      while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) 
     177      { 
     178         $posts[] = $row; 
     179      } 
     180 
     181      // Fermeture de la connection 
     182      mysql_close($link); 
     183 
     184      return $posts; 
     185    } 
     186    ?> 
     187 
     188L’exemple 2-5 montre le contrôleur modifié. 
     189 
     190*Exemple 2-5 la partie contrôleur, dans `index.php`.* 
     191 
     192    [php] 
     193    <?php 
     194 
     195    // Appel du modèle 
     196    require_once('model.php'); 
     197 
     198    // Récupération de la liste des posts 
     199    $posts = getAllPosts(); 
     200 
     201    // Appel de la vue 
     202    require('view.php'); 
     203 
     204    ?> 
     205 
     206Le 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 noms de fonctions compréhensibles peut même rendre les commentaires du contrôleur obsolètes.  
     207 
     208Le script `model.php` 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çues du contrôleur et non intégrées directement dans le modèle. De cette manière le modèle peut être réutilisé dans un autre contrôleur. 
     209 
     210### La séparation en couche au-delà de MVC 
     211 
     212Pour 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. 
     213 
     214Afin 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. 
     215 
     216#### L’abstraction de données 
     217 
     218La 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 appel à 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. 
     219 
     220Le 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. 
     221 
     222*Listing 2-6 L’abstraction de données du modèle* 
     223 
     224    [php] 
     225    <?php 
     226 
     227    function open_connection($host, $user, $password) 
     228    { 
     229      return mysql_connect($host, $user, $password); 
     230    } 
     231 
     232    function close_connection($link) 
     233    { 
     234      mysql_close($link); 
     235    } 
     236 
     237    function query_database($query, $database, $link) 
     238    { 
     239      mysql_select_db($database, $link); 
     240 
     241      return mysql_query($query, $link); 
     242    } 
     243 
     244    function fetch_results($result) 
     245    { 
     246      return mysql_fetch_array($result, MYSQL_ASSOC); 
     247    } 
     248 
     249*Listing 2-7 - Accès aux données du modèle* 
     250 
     251    [php] 
     252    function getAllPosts() 
     253    { 
     254      // Connection à la base de données 
     255      $link = open_connection('localhost', 'myuser', 'mypassword'); 
     256 
     257      // Excécution de la requête sql 
     258      $result = query_database('SELECT date, title FROM post', 'blog_db', $link); 
     259 
     260      // Remplissage du tableau 
     261      $posts = array(); 
     262      while ($row = fetch_results($result)) 
     263      { 
     264         $posts[] = $row; 
     265      } 
     266 
     267      // Fermeture de la connection 
     268      close_connection($link); 
     269 
     270      return $posts; 
     271    } 
     272    ?> 
     273 
     274On constate qu’aucune des 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 par d’autres fonctions du modèle ayant besoin d’un accès à la base de données. 
     275 
     276>**NOTE** 
     277>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. 
     278 
     279#### La partie Vue 
     280 
     281La 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). 
     282La 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. 
     283En 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 
     284 
     285*Listing 2-8 La partie gabarit de la vue, dans `mytemplate.php`.* 
     286 
     287    [php] 
     288    <h1>Liste de messages</h1> 
     289    <table> 
     290    <tr><th>Date</th><th>Title</th></tr> 
     291    <?php foreach ($posts as $post): ?> 
     292      <tr> 
     293        <td><?php echo $post['date'] ?></td> 
     294       <td><?php echo $post['title'] ?></td> 
     295      </tr> 
     296    <?php endforeach; ?> 
     297    </table> 
     298 
     299*Listing 2-9 La vue logique de la vue* 
     300 
     301    [php] 
     302    <?php 
     303  
     304    $title = 'Liste de messages'; 
     305    $content = include('mytemplate.php'); 
     306    ?> 
     307 
     308*Listing 2-10 La partie maquette de la vue* 
     309 
     310    [php] 
     311 
     312    <html> 
     313      <head> 
     314       <title><?php echo $title ?></title> 
     315      </head> 
     316      <body> 
     317        <?php echo $content ?> 
     318      </body> 
     319    </html> 
     320 
     321 
     322#### Action et contrôleur principal (front controller). 
     323 
     324Dans 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 a le plus de travail. De plus, la plupart 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 principal unique à l’application et par les actions, qui ne contiennent que le code contrôleur spécifique à certaines pages. 
     325 
     326#### Orienté objet. 
     327 
     328Tous 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 et permettent, en outre, d’avoir des normes de codifications simples. 
     329 
     330Implé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 les sources plus difficiles à lire. 
     331 
     332L’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. 
     333 
     334>**TIP** 
     335>Si vous voulez approfondir vos connaissances sur les motifs de conception 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. [Sur Amazon](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) 
     336 
     337### L’implémentation [MVC] [1] de Symfony 
     338 
     339Revenons à 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 : 
     340 
     341   * Niveau Modèle 
     342      * Abstraction de données 
     343      * Accès aux données 
     344   * Niveau Vue 
     345      * Vue (logique de vue) 
     346      * Gabarit 
     347      * La maquette 
     348   * Le niveau Contrôleur  
     349     * Le contrôleur principal 
     350     * Les actions 
     351 
     352Sept scripts ! Beaucoup de fichiers à ouvrir et à modifier pour chaque nouvelle page ! 
     353Cependant, 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é. 
     354 
     355Tout d’abord, le contrôleur principal et la maquette sont communs à toute l’application. Vous pouvez en avoir plusieurs mais un seul de chaque est nécessaire. Le contrôleur principal est un composant pur [MVC] [1], ce qui veut dire que vous n’aurez jamais à le coder, Symfony le générera pour vous. 
     356 
     357L’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 à Propel. Cette librairie gère les clés étrangères et les champs de date, génère les accesseurs, etc 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. 
     358 
     359Enfin, la logique de vue peut s’appuyer sur un simple fichier de configuration, sans avoir besoin de programmation. 
     360 
     361*Schéma 2-2 Le processus Symfony* 
     362 
     363![Diagramme de flux de Symfony](http://www.symfony-project.com/images/book/trunk/F0202.png "Diagramme de flux de Symfony") 
     364 
     365Il 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 
     366 
     367*Listing 2-11 Actions de `list` de `myproject/apps/myapp/modules/weblog/actions/actions.class.php`.* 
     368 
     369    [php] 
     370    <?php 
     371    class weblogActions extends sfActions 
     372    { 
     373      public function executeListe() 
     374        { 
     375        $this->messages = MessagePeer::doSelect(new Criteria()); 
     376        } 
     377    } 
     378    ?> 
     379 
     380*Listing 2-12 Gabarit de `liste`, de `myproject/apps/myapp/modules/weblog/templates/listeSuccess.php`.* 
     381 
     382    [php] 
     383    <h1>Liste de messages</h1> 
     384    <table> 
     385    <tr><th>Date</th><th>Titre</th></tr> 
     386    <?php foreach ($messagess as $message): ?> 
     387      <tr> 
     388        <td><?php echo $message->getDate() ?></td> 
     389        <td><?php echo $message->getTitre() ?></td> 
     390      </tr> 
     391    <?php endforeach; ?> 
     392    </table> 
     393 
     394*Listing 2-13 Vue de `liste`, de `myproject/apps/myapp/modules/weblog/config/view.yml`.* 
     395 
     396    listSuccess: 
     397      metas: { title: Liste de messages } 
     398  
     399De plus, vous allez aussi devoir définir une maquette, comme le montre le listing 2-14.  Elle sera régulièrement réutilisée. 
     400 
     401*Listing 2-14 – Maquette de `liste`, dans `myproject/apps/myapp/templates/layout.php`.* 
     402    [php] 
     403    <html> 
     404      <head> 
     405        <?php echo include_title() ?> 
     406      </head> 
     407      <body> 
     408        <?php echo $sf_data->getRaw('sf_content') ?> 
     409      </body> 
     410    </html> 
     411 
     412Voilà 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. 
     413Cependant, 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 deboggage, une configuration aisée, l'abstraction de données, la réécriture d'URL, le multi-environnement et encore beaucoup d'outils de développement. 
     414 
     415#### Le noyau de Symfony 
     416 
     417L'implémentation [MVC] [1] de Symfony utilise plusieurs classes que vous rencontrerez plusieurs fois dans ce livre : 
     418 
     419   * ‘sfController` est la classe contrôleur. Elle interprète les requêtes et les transmet aux actions. 
     420   * ‘sfRequest` conserve les éléments des requêtes comme les paramètres, les cookies, les entêtes, etc ... 
     421   * ‘sfResponse` contient les entêtes et le contenu des réponses. C'est l'objet qui peut éventuellement être converti en HTML et renvoyé à l'utilisateur. 
     422   * Le contexte (récupéré par `sfContext::getInstance()`) conserve une référence de chaque objet du noyau et de la configuration courante. Il est accessible de n'importe où. 
     423 
     424Vous pourrez en apprendre plus sur ces objets au chapitre 6. 
     425 
     426Comme 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. 
     427 
     428>**NOTE** 
     429>Dans Symfony, la méthode de codification UpperCamelCase est utilisée pour 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. 
     430 
     431L'organisation du code 
     432---------------------- 
     433 
     434Maintenant 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. 
     435 
     436### La structure des projets: applications, modules et actions. 
     437 
     438Avec 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. 
     439 
     440Au 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 plupart des cas, un projet contiendra deux applications : le front-office et le back-office partageant les mêmes bases de données. 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. 
     441 
     442Chaque application est un ensemble d'un ou plusieurs modules. Un module correspond généralement à une page ou un groupe de pages traitant du même sujet. Par exemple, vous pouvez avoir les modules `accueil`, `articles`, `aide`, `panier`, `compte` etc ... 
     443 
     444Les modules contiennent des actions qui peuvent être utilisées au sein de ce module. Par exemple, un `panier` 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, à 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.) 
     445 
     446>**TIP** 
     447>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. 
     448 
     449Le 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. 
     450 
     451*Schéma 2-3 Exemple d'organisation de code.* 
     452 
     453![Exemple d'organisation du code](http://www.symfony-project.com/images/book/trunk/F0203.png "Exemple d'organisation du code") 
     454 
     455 
     456### L'arborescence 
     457 
     458La plupart des projets web partagent un certains nombres d'éléments comme : 
     459 
     460   * une base de données comme MySQL ou PostgreSQL 
     461   * des fichiers statiques (HTML, images, fichiers JavaScript, feuilles de styles etc ...) 
     462   * des fichiers ajoutés par les utilisateurs ou administrateurs 
     463   * des classes et librairies PHP 
     464   * des librairies externes (scripts externes) 
     465   * des fichiers batch (des scripts exécutés en ligne de commande ou via les tâches planifiées) 
     466   * des fichiers journaux (traces laissées par une application et/ou le serveur) 
     467   * des fichiers de configuration. 
     468 
     469Symfony fournit une arborescence standard de dossiers afin d’organiser le contenu de façon logique et conformément aux choix de l’architecture (modèles [MVC] [1] regroupement projet/application/module). 
     470Cette arborescence est automatiquement créée à l’initialisation de chaque projet, application ou module. Naturellement, libre à vous de l’adapter à vos besoins ou à ceux des clients. 
     471 
     472#### L’arborescence à la racine 
     473 
     474Voici l’arborescence standard d’un projet Symfony : 
     475 
     476    apps/ 
     477      frontend/ 
     478      backend/ 
     479    batch/ 
     480    cache/ 
     481    config/ 
     482    data/ 
     483      sql/ 
     484    doc/ 
     485    lib/ 
     486      model/ 
     487    log/ 
     488    plugins/ 
     489    test/ 
     490      unit/ 
     491      functional/ 
     492    web/ 
     493      css/ 
     494      images/ 
     495      js/ 
     496      uploads/ 
     497 
     498Le tableau 2-1 décrit le contenu de ces répertoires 
     499 
     500*Tableau 2-1 Répertoires racines* 
     501 
     502Répertoire | Description 
     503-----------|------------- 
     504`apps/`    | Contient un répertoire par applications du projet (communément `frontend` et `backend` pour le front et le back office) 
     505`batch/`   | Contient les scripts PHP appelés par une ligne de commande ou un planificateur de tâches 
     506`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é. 
     507`config/`  | Contient la configuration générale du projet 
     508`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 … 
     509`doc/`     | Contient la documentation du projet y compris votre propre documentation et celle générée par PHPdoc 
     510`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) 
     511`log/`     | Ici sont conservés les fichiers journaux générés par Symfony. Il peut aussi contenir les journaux du serveur web, des bases de données ou n’importe quels autres fichiers journaux du projet. Symfony crée un fichier journal par application et environnement (cf Chapitre 16) 
     512`plugins/` | Ce répertoire contient les plugins installés pour cette application (cf Chapitre 17) 
     513`test/`    | Il contient des jeux d’essai unitaires et fonctionnels écrit en php et compatibles avec le framework de test de Symfony (cf Chapitre 15). 
     514`web/`     | La racine du serveur web. Seuls les fichiers se trouvant dans ce fichier sont accessible via Internet. 
     515 
     516 
     517#### L’arborescence d’une application 
     518 
     519L’arborescence d’une application est identique : 
     520 
     521    apps/ 
     522      [nom de l’application]/ 
     523        config/ 
     524        i18n/ 
     525        lib/ 
     526        modules/ 
     527        templates/ 
     528          layout.php 
     529          error.php 
     530          error.txt 
     531 
     532Le tableau 2-2 décrit les répertoires d’une application 
     533 
     534*Tableau 2-2 Répertoires d’une application* 
     535 
     536Répertoire   | Description 
     537-------------|------------ 
     538`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 
     539`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 
     540`lib/`       | Contient les librairies et les classes spécifiques à l’application 
     541`modules/`   | Contient tous les modules propres à l’application 
     542`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. 
     543 
     544>**NOTE** 
     545>Les répertoires `i18/`, `lib/` et `modules/` sont vides pour une nouvelle application. 
     546 
     547Les 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.  
     548Lorsque 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. 
     549 
     550#### L’arborescence du module 
     551 
     552Chaque 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écisé au moment de l'installation. 
     553 
     554Voici l’arborescence classique d’un module : 
     555 
     556    apps/ 
     557      [nom de l’application]/ 
     558        modules/ 
     559          [nom du module]/ 
     560              actions/ 
     561                actions.class.php 
     562              config/ 
     563              lib/ 
     564              templates/ 
     565                indexSuccess.php 
     566              validate/ 
     567 
     568Le tableau 2-3 décrit les répertoires du module 
     569 
     570*Tableau 2-3 Répertoires du module* 
     571 
     572Répertoire | Description 
     573-----------|------------ 
     574`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 
     575`config/`    | Il peut contenir des fichiers de paramétrages locaux pour les modules 
     576`lib/`       | Contient les classes et librairies spécifiques au module 
     577`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 
     578`validate/`  | Dédié à la configuration des fichiers utilisés par le formulaire de validation (cf Chapitre 10)  
     579 
     580>**NOTE** 
     581>Les dossiers `config/`, `lib/` et `validate/` sont vides à la création d’un nouveau module. 
     582 
     583#### L’arborescence web 
     584 
     585Le dossier web, qui regroupe tous les fichiers accessibles sur le net, n’a que peu de sous-répertoires. 
     586Le respect de conventions de nommage claires facilitera l’utilisation de ces dossiers dans les gabarits. Voici un exemple de l’arborescence d’un dossier  
     587web 
     588 
     589    web/ 
     590      css/ 
     591      images/ 
     592      js/ 
     593      uploads/ 
     594 
     595Par convention, les fichiers statiques sont répartis dans les dossiers décrits par le tableau 2-4 
     596 
     597*Tableau 2-4 – Arborescence Web classique* 
     598 
     599Répertoire | Description 
     600-----------|------------ 
     601`css/`     | Contient les feuilles de styles avec l’extension `.css` 
     602`images/`  | Contient les images aux formats `.jpg`, `.png` ou `.gif` 
     603`js/`      | Contient les fichiers JavaScript avec l’extension `.js` 
     604`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. 
     605 
     606>**NOTE** 
     607>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. 
     608 
     609Outils communs 
     610-------------- 
     611 
     612Dans 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 
     613 
     614### Le conteneur de paramètres 
     615 
     616Beaucoup de classes Symfony possèdent un conteneur de paramètres. C’est un moyen simple d’encapsuler un attribut avec des méthodes getter et setter correctes. Par exemple, la classe `sfResponse` possède un conteneur de paramètres que vous pouvez utiliser en appelant la méthode `getParameterHolder()`. Chaque conteneur de paramètres conserve les données comme illustré par le listing 2-15. 
     617 
     618*Listing 2-15 Utilisation du conteneur de paramètre de `sfResponse`* 
     619 
     620    [php] 
     621    $response->getParameterHolder()->set(‘foo’, ‘bar’); 
     622    Echo $response->getParameterHolder()-get(‘foo’); 
     623    => ‘bar’ 
     624 
     625 
     626La plupart des classes utilisant le conteneur de paramètres 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 
     627 
     628*Listing 2-16 Utilisation des méthodes intermédiaires des conteneurs de paramètres de `sfResponse`* 
     629 
     630    [php] 
     631    $response->setParameter(‘foo’, ‘bar’); 
     632    Echo $response->getParameter(‘foo’); 
     633    => ‘bar’ 
     634 
     635 
     636La méthode getter du conteneur de paramètres 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. 
     637 
     638*Listing 2-17 – Utilisation de la valeur par défaut de l’attribut du getter* 
     639 
     640    [php] 
     641    // Le paramètre 'foobar' n’est pas défini, donc le getter renvoie une valeur vide 
     642    echo $response->getParameter('foobar'); 
     643    => null 
     644  
     645    // Une valeur par défaut peut-être utilisée en ajoutant le getter dans la condition suivante 
     646    if ($response->hasParameter('foobar')) 
     647    { 
     648      echo $response->getParameter('foobar'); 
     649    } 
     650    else 
     651    { 
     652      echo 'default'; 
     653    } 
     654     => default 
     655  
     656    // Mais il est plus rapide d’utiliser le deuxième argument du getter pour cela. 
     657    echo $response->getParameter('foobar', 'default'); 
     658    => default 
     659 
     660 
     661Les conteneurs de paramètres peuvent aussi supporter les espaces de nommage. Si vous spécifiez un troisième paramètre, il sera interprété comme un espace de nommage et le paramètre sera alors défini uniquement dans cet espace. Le Listing 2-18 illustre ce point. 
     662 
     663*Listing 2-18 – Utilisation de l’espace de nommage du conteneur de paramètres de la méthode `sfResponse`* 
     664 
     665    [php] 
     666    $response->setParameter(‘foo’, ‘bar1’) ; 
     667    $response->setParameter(‘foo’, ‘bar2’, ‘my/name/space’); 
     668    Echo $response->getParameter(‘foo’); 
     669    => ‘bar1’ 
     670    Echo $response->getParamater(‘foo’, null, ‘my/name/space’); 
     671    => ‘bar2’ 
     672 
     673 
     674Vous pouvez bien évidemment ajouter un conteneur de paramètres 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ètres. 
     675 
     676*Listing 2-19 Ajouter un conteneur de paramètres à une classe* 
     677 
     678    [php] 
     679    class MyClass 
     680    { 
     681      protected $parameter_holder = null; 
     682      public function initialize ($parameters = array()) 
     683      { 
     684        $this->parameter_holder = new sfParameterHolder(); 
     685        $this->parameter_holder->add($parameters); 
     686      } 
     687  
     688      public function getParameterHolder() 
     689      { 
     690        return $this->parameter_holder; 
     691      } 
     692    } 
     693 
     694 
     695### Constantes 
     696 
     697É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. 
     698 
     699*Listing 2-20 Utilisation de l’objet `sfConfig` à la place des constantes* 
     700 
     701    [php] 
     702    // A la place des constantes, 
     703    define('SF_FOO', 'bar'); 
     704    echo SF_FOO; 
     705    // Symfony utilise l’objet `sfConfig` 
     706    sfConfig::set('sf_foo', 'bar'); 
     707    echo sfConfig::get('sf_foo'); 
     708 
     709La 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. 
     710 
     711### Auto-chargement des classes 
     712 
     713De 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 
     714 
     715    [php] 
     716    Include ‘classes/MyClass.php’; 
     717    $myObject = new MyClass(); 
     718 
     719 
     720Mais 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 
     721 
     722    [php] 
     723    $myObject = new MyClass(); 
     724 
     725 
     726Dès lors, Symfony recherche la définition de `MyClass` dans tous les fichiers d’extension `.php` présents dans l’un des répertoires `lib/` du projet. S’il la trouve, elle est incluse automatiquement. 
     727 
     728Par conséquent, si vous conservez toutes vos classes dans les répertoires `lib`, vous n’aurez jamais à inclure aucune classes. C’est exactement pourquoi les projets Symfony n’utilisent jamais les ordres `include` ou `require`. 
     729 
     730>**NOTE** 
     731>Dans le but d’améliorer les performances, l’auto-chargement de Symfony parcourt 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 supprimez une classe dans votre projet en 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. 
     732 
     733Résumé 
     734------ 
     735 
     736L’usage d’un framework basé sur [MVC] [1] vous oblige à répartir et organiser votre code en accord avec 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 simples à utiliser et plus contraignantes. 
     737 
     738Symfony 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 de sa souplesse et de ses grandes possibilités de configuration, Symfony est adapté à tout type de projet web. 
     739 
     740Maintenant 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. 
     741 
     742[1]: http://fr.wikipedia.org/wiki/MVC "MVC sur Wikipédia" 
     743 
     744}}}