Development

Documentation/fr_FR/book/1.0/trunk/08-Inside-the-Model-Layer (diff)

You must first sign up to be able to contribute.

Changes between Version 39 and Version 40 of Documentation/fr_FR/book/1.0/trunk/08-Inside-the-Model-Layer

Show
Ignore:
Author:
berduj (IP: 77.200.138.197)
Timestamp:
02/20/08 23:50:43 (10 years ago)
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Documentation/fr_FR/book/1.0/trunk/08-Inside-the-Model-Layer

    v39 v40  
    202202 
    203203 
    204             Relationnel    | Orienté Objet 
     204               Relationnel | Orienté Objet 
    205205            -------------- | --------------- 
    206206            Table          | Classe 
    212212### Récupérer la valeur d'une colonne 
    213213 
    214 Lorsque Symfony construit le modèle, il crée une classe de base par table définies dans le fichier `schema.yml`. Chacune d'elles possède des constructeurs, accesseurs et manipulateurs par défaut. Les méthodes `new`, `getXXX()`, et `setXXX()` servent à créer des objets et à accéder aux propriétés de ces objets, comme le monte le listing 8-7. 
     214Lorsque Symfony construit le modèle, il crée une classe de base par table définie dans le fichier `schema.yml`. Chacune d'elles possède des constructeurs, accesseurs et manipulateurs par défaut. Les méthodes `new`, `getXXX()`, et `setXXX()` servent à créer des objets et à accéder aux propriétés de ces objets, comme le montre le listing 8-7. 
    215215 
    216216Listing 8-7 - Méthodes des classes générées 
    225225 
    226226>**NOTE** 
    227 >Dans l'exemple précédent, la classes générée est appelée `Article`, qui est le nom donnée à la table `blog_article`  par `phpName`. Si ce dernier n'avait été défini, la classe se serait appelée `BlogArticle`. Les accesseurs et manipulateurs appliquent une variante de la convention camelCase sur les colonnes. Ainsi la méthode `getTitle()` récupère la valeur de la colonne `title`. 
    228  
    229 Pour manipuler plusieurs champ simultanément, vous pouvez utiliser la méthode `fromArray()` aussi générée pour chaque classes, comme le montre le listing  8-8. 
     227>Dans l'exemple précédent, la classe générée est appelée `Article`, qui est le nom donné à la table `blog_article`  par `phpName`. Si ce dernier n'avait pas été défini, la classe se serait appelée `BlogArticle`. Les accesseurs et manipulateurs appliquent une variante de la convention camelCase sur les colonnes. Ainsi la méthode `getTitle()` récupère la valeur de la colonne `title`. 
     228 
     229Pour manipuler plusieurs champs simultanément, vous pouvez utiliser la méthode `fromArray()` aussi générée pour chaque classe, comme le montre le listing  8-8. 
    230230 
    231231Listing 8-8 - La méthode `fromArray()` est un manipulateur multiple. 
    239239### Récupérer des enregistrements liés 
    240240 
    241 La colonne `article_id` dans la table `blog_comment` définit implicitement une clé étrangère dans la table `blog_article`. Chaque commentaire est lié à un article et un article peut avoir plusieurs commentaires. Les classes générées contiennent cinq méthodes pour traduit ce comportement relationnel et orienté objet: 
     241La colonne `article_id` dans la table `blog_comment` définit implicitement une clé étrangère dans la table `blog_article`. Chaque commentaire est lié à un article et un article peut avoir plusieurs commentaires. Les classes générées contiennent cinq méthodes pour traduire ce comportement relationnel et orienté objet: 
    242242 
    243243  * `$comment->getArticle()`: Pour récupérer l'objet `Article` lié. 
    247247  * `$article->getComments()`: Pour récupérer l'objet `Comment` liés 
    248248 
    249 Les méthodes `getArticleId()` et `setArticleId()` montrent que vous pouvez considérer la colonne article_id comme une véritable colonne et la manipuler directement, mais cela n'a pas vraiment d'intérêts. Le vrai bénéfice d'une approche orienté objet est plus visible dans les trois autres méthodes. Le listing 8-9 montre comment utiliser les accesseurs générés. 
     249Les méthodes `getArticleId()` et `setArticleId()` montrent que vous pouvez considérer la colonne article_id comme une véritable colonne et la manipuler directement, mais cela n'a pas vraiment d'intérêt. Le vrai bénéfice d'une approche orienté objet est plus visible dans les trois autres méthodes. Le listing 8-9 montre comment utiliser les accesseurs générés. 
    250250 
    251251Listing 8-9 - Les clés étrangères sont converties en accesseurs particuliers 
    278278    $comments = $article->getComments(); 
    279279 
    280 La méthode `getArticle()` renvoie un objet de classe `Article` bénéficiant immédiatement de l'accesseur `getTitle()`. Ceci est bien mieux que réaliser la jointure soit même, ce qui pourrait bien plus de ligne de code que dans ce cas
    281  
    282 La variable `$comments` (notez le 's' en plus) du listing 8-10 contient un tableau de classes d'objets. Vous pouvez afficher le premier avec l'ordre `$comments[0]` ou parcourir l'ensemble de valeur via l'instruction `foreach ($comments as $comment)` 
     280La méthode `getArticle()` renvoie un objet de classe `Article` bénéficiant immédiatement de l'accesseur `getTitle()`. Ceci est bien mieux que réaliser la jointure soit même, ce qui prendrait bien plus de lignes de code
     281 
     282La variable `$comments` (notez le 's' en plus) du listing 8-10 contient un tableau de classes d'objets. Vous pouvez afficher le premier avec l'ordre `$comments[0]` ou parcourir l'ensemble de valeurs grace à l'instruction `foreach ($comments as $comment)` 
    283283 
    284284>**NOTE** 
    285 >Vous pouvez maintenant comprendre pourquoi les noms des objets du modèle sont au singulier. La clé étrangère définie dans la table `blog_comment` implique la création  de la méthode `getComments()`, nommé en ajoutant un `s` au nom de l'objet `Comment`. Si le nom de l'objet du modèle avait été au pluriel, la génération aurait alors nommé cette méthode `getCommentss()`, ce qui n'a pas de sens. 
     285>Vous comprenez maintenant pourquoi les noms des objets du modèle sont au singulier. La clé étrangère définie dans la table `blog_comment` implique la création  de la méthode `getComments()`, nommée en ajoutant un `s` au nom de l'objet `Comment`. Si le nom de l'objet du modèle avait été au pluriel, la génération aurait alors nommé cette méthode `getCommentss()`, ce qui n'a pas de sens. 
    286286 
    287287### Sauvegarder et supprimer des données 
    288288 
    289 En appelant le constructeur `new`, vous créez un nouvel objet mais pas un nouvel enregistrement dans la base. Modifier un objet n'a aucun effet sur la base. Pour sauvegarder les données dans une base vous devez appeler la méthode `save()` de l'objet. 
     289En appelant le constructeur `new`, vous créez un nouvel objet mais pas un nouvel enregistrement dans la base. Modifier un objet n'a aucun effet sur la base. Pour sauvegarder les données dans la base vous devez appeler la méthode `save()` de l'objet. 
    290290 
    291291    [php] 
    295295 
    296296>**TIP** 
    297 > Vous pouvez vérifier si un objet est neuf en appelant la méthode `isNew()`. Si vous vous demandez si un objet a été modifier et nécessite une sauvegarde, appelez la méthode `isModified()`. 
     297> Vous pouvez vérifier si un objet est nouveau en appelant la méthode `isNew()`. Si vous vous demandez si un objet a été modifié et nécessite une sauvegarde, appelez la méthode `isModified()`. 
    298298 
    299299En lisant les commentaires sur vos articles, vous pourriez ne plus vouloir publier sur Internet. Et si vous n'appréciez pas l'ironie de vos lecteurs, vous pouvez facilement supprimer les commentaires avec la méthode `delete()`, comme le montre le listing 8-11. 
    308308 
    309309>**TIP** 
    310 >Même après l'appelle de la méthode `delete()` un objet reste disponible jusqu'à la fin de l'exécution de la requête. Pour savoir si un objet a réellement été supprimer de la base, employez la méthode `isDeleted()`. 
     310>Même après l'appel de la méthode `delete()` un objet reste disponible jusqu'à la fin de l'exécution de la requête. Pour savoir si un objet a réellement été supprimé de la base, employez la méthode `isDeleted()`. 
    311311 
    312312### Récupérer des enregistrements pas la clé primaire. 
    313313 
    314 Si vous connaissez la clé primaire d’un enregistrement précis, utiliser la méthode `retrieveByPk()`de la classe Peer pour obtenir l'objet correspondant. 
     314Si vous connaissez la clé primaire d’un enregistrement précis, utilisez la méthode `retrieveByPk()`de la classe Peer pour obtenir l'objet correspondant. 
    315315 
    316316    [php] 
    317317    $article = ArticlePeer::retrieveByPk(7); 
    318318 
    319 Le champ `id` est défini comme clé primaire de la table `blog_article` dans le fichier `schema.yml`, ce qui implique que l'ordre précédent renverra l'article dont l'`id` est 7. Comme vous utilisez une clé primaire vous êtes certain de ne récupérer d'un seul enregistrement, la variable `$article` contenant évidemment un objet `Article`. 
    320  
    321 Dans certains cas une clé primaire peut-être composée de plusieurs colonnes. Dans ce cas la méthode `retrieveByPks()` peut accepter plusieurs paramètre correspondant a chaque colonnes clés
     319Le champ `id` est défini comme clé primaire de la table `blog_article` dans le fichier `schema.yml`, ce qui implique que l'ordre précédent renverra l'article dont l'`id` est 7. Comme vous utilisez une clé primaire vous êtes certain de ne récupérer qu'un seul enregistrement, la variable `$article` contenant évidemment un objet `Article`. 
     320 
     321Dans certains cas une clé primaire peut-être composée de plusieurs colonnes. Dans ce cas la méthode `retrieveByPks()` peut accepter plusieurs paramètres correspondant à chaque colonnes clé
    322322 
    323323Vous pouvez aussi récupérer plusieurs objets par leur clé primaire en appelant la méthode `retrieveByPKs()` avec un tableau de clés primaires en paramètre. 
    325325### Récupérer des enregistrements avec un critère  
    326326 
    327 Si vous souhaitez obtenir plusieurs enregistrements, vous aurez besoin d'employer la méthode Peer `doSelect()` de l'objet correspondant. Par exemple, pour récupérer des objets de la classe `Article`, vous devrez utiliser `ArticlePeer::doSelect()` 
    328  
    329 Le premier paramètre de la méthode `doSelect()` est un objet de classe `Criteria`, qui contient une définition de requête dépourvue de SQL pour le bien de l'abstraction de donnée. 
     327Si vous souhaitez récupérer plusieurs enregistrements, vous devrez utiliser la méthode Peer `doSelect()` de l'objet correspondant. Par exemple, pour récupérer des objets de la classe `Article`, vous devrez utiliser `ArticlePeer::doSelect()`. 
     328 
     329Le premier paramètre de la méthode `doSelect()` est un objet de classe `Criteria`, qui contient une définition de requête dépourvue de SQL pour le respect de l'abstraction de donnée. 
    330330 
    331331Un `Criteria` vide renvoie tous les objets de la classe. Par exemple, le code du listing 8-12 renvoie tous les articles. 
    345345>Hydrating 
    346346> 
    347 >L'utilisation de `::doSelect()` est en réalité bien plus puissant qu'une simple requête SQL. Tout d'abord le SQL est optimisé pour le SGBD que vous employez. En suite, toutes les valeurs passées à `Criteria` sont échappées avant d'être intégrées dans le code SQL afin d'éviter les attaques par injection SQL. Enfin, la méthode renvoie un tableau d'objets plutôt qu'un ensemble de résultats. L'ORM créer et alimente automatiquement les objets en fonction des résultats. Ce comportement est appelé l'hydrating 
    348  
    349 Pour des sélections plus complexes, vous avez entre autres besoin des équivalents des ordres WHERE, ORDER BY, GROUP BY de SQL. 
    350 L'objet `Criteria` possède des méthodes et des paramètres interprétant toutes ces conditions. Par exemple, pour obtenir tous les commentaires écrit par Steve, trié par date, renseigné le `Criteria`comme au listing 8-13. 
     347>L'utilisation de `::doSelect()` est en réalité bien plus puissant qu'une simple requête SQL. Tout d'abord le SQL est optimisé pour le SGBD que vous utilisez. Ensuite, toutes les valeurs passées à `Criteria` sont échappées avant d'être intégrées dans le code SQL afin d'éviter les attaques par injection SQL. Enfin, la méthode renvoie un tableau d'objets plutôt qu'un ensemble de résultats. L'ORM crée et alimente automatiquement les objets en fonction des résultats. Ce comportement est appelé l'hydrating. 
     348 
     349Pour des sélections plus complexes, vous aurez entre autres besoin des équivalents des ordres WHERE, ORDER BY, GROUP BY de SQL. 
     350L'objet `Criteria` possède des méthodes et des paramètres interprétant toutes ces conditions. Par exemple, pour obtenir tous les commentaires écrit par Steve, triés par date, renseignez le `Criteria` comme dans le listing 8-13. 
    351351 
    352352Listing 8-13 - Récupérer des enregistrements par critères avec `doSelect()` -- Critère avec conditions 
    368368 
    369369>**NOTE** 
    370 >Pourquoi préférer `CommentPeer::AUTHOR` à la place de `blog_comment.AUTHOR` qui sera au final la valeur de la requête SQL exécutée ? Imaginez que vous deviez changer le nom du champ auteur par `collaborateur` dans la base. Si vous employez `blog_comment.AUTHOR` vous devriez alors faire la modification dans toutes les requêtes au modèle. En préférant `CommentPeer::AUTHOR` vous modifiez simplement le nom dans `schema.yml`, conservez `AUTHOR` pour `phpName` et regénérez le modèle. 
     370>Pourquoi préférer `CommentPeer::AUTHOR` à la place de `blog_comment.AUTHOR` qui sera au final la valeur de la requête SQL exécutée ? Imaginez que vous devez changer le nom du champ auteur par `collaborateur` dans la base. Si vous utilisez `blog_comment.AUTHOR` vous devrez alors faire la modification dans toutes les requêtes au modèle. En préférant `CommentPeer::AUTHOR` vous ne modifiez que le nom dans `schema.yml`, conservez `AUTHOR` pour `phpName` et regénérez le modèle. 
    371371 
    372372La table 8-1 montre les équivalences entre la syntaxe SQL et la syntaxe de l'objet `Criteria` 
    374374 
    375375Table 8-1 - Syntaxe SQL et Criteria 
    376 SQL                                                          | Criteria 
    377 ------------------------------------------------------------ | ----------------------------------------------- 
    378 `WHERE colonne = valeur`                                     | `->add(colonne, valeur);` 
    379 `WHERE colonne <> valeur`                                    | `->add(colonne, valeur, Criteria::NOT_EQUAL);` 
    380 **Autres opérateurs de comparaison**                         |  
    381 `> , <`                                                      | `Criteria::GREATER_THAN, Criteria::LESS_THAN` 
    382 `>=, <=`                                                     | `Criteria::GREATER_EQUAL, Criteria::LESS_EQUAL` 
    383 `IS NULL, IS NOT NULL`                                       | `Criteria::ISNULL, Criteria::ISNOTNULL` 
    384 `LIKE, ILIKE`                                                | `Criteria::LIKE, Criteria::ILIKE` 
    385 `IN, NOT IN`                                                 | `Criteria::IN, Criteria::NOT_IN` 
    386 **Autres mots clés SQL**                                     | 
    387 `ORDER BY colonne ASC`                                       | `->addAscendingOrderByColumn(colonne);` 
    388 `ORDER BY colonne DESC`                                      | `->addDescendingOrderByColumn(colonne);` 
    389 `LIMIT limite`                                               | `->setLimit(limite)` 
    390 `OFFSET offset`                                              | `->setOffset(offset) ` 
    391 `FROM table1, table2 WHERE table1.col1 = table2.col2`        | `->addJoin(col1, col2)` 
    392 `FROM table1 LEFT JOIN table2 ON table1.col1 = table2.col2`  | `->addJoin(col1, col2, Criteria::LEFT_JOIN)` 
    393 `FROM table1 RIGHT JOIN table2 ON table1.col1 = table2.col2` | `->addJoin(col1, col2, Criteria::RIGHT_JOIN)` 
     376    SQL                                                          | Criteria 
     377    ------------------------------------------------------------ | ----------------------------------------------- 
     378    `WHERE colonne = valeur`                                     | `->add(colonne, valeur);` 
     379    `WHERE colonne <> valeur`                                    | `->add(colonne, valeur, Criteria::NOT_EQUAL);` 
     380    **Autres opérateurs de comparaison**                         |  
     381    `> , <`                                                      | `Criteria::GREATER_THAN, Criteria::LESS_THAN` 
     382    `>=, <=`                                                     | `Criteria::GREATER_EQUAL, Criteria::LESS_EQUAL` 
     383    `IS NULL, IS NOT NULL`                                       | `Criteria::ISNULL, Criteria::ISNOTNULL` 
     384    `LIKE, ILIKE`                                                | `Criteria::LIKE, Criteria::ILIKE` 
     385    `IN, NOT IN`                                                 | `Criteria::IN, Criteria::NOT_IN` 
     386    **Autres mots clés SQL**                                     | 
     387    `ORDER BY colonne ASC`                                       | `->addAscendingOrderByColumn(colonne);` 
     388    `ORDER BY colonne DESC`                                      | `->addDescendingOrderByColumn(colonne);` 
     389    `LIMIT limite`                                               | `->setLimit(limite)` 
     390    `OFFSET offset`                                              | `->setOffset(offset) ` 
     391    `FROM table1, table2 WHERE table1.col1 = table2.col2`        | `->addJoin(col1, col2)` 
     392    `FROM table1 LEFT JOIN table2 ON table1.col1 = table2.col2`  | `->addJoin(col1, col2, Criteria::LEFT_JOIN)` 
     393    `FROM table1 RIGHT JOIN table2 ON table1.col1 = table2.col2` | `->addJoin(col1, col2, Criteria::RIGHT_JOIN)` 
     394 
    394395 
    395396>**TIP** 
    396 > Le meilleur moyen de découvrir les méthodes disponibles dans les classes générées est de jetez un coup d'œil aux fichiers `Base` du répertoire `lib/model/om/` après la génération. Les noms des méthodes sont suffisamment explicite, mais si vous avez besoin de plus de commentaires sur elles, passez le paramètre `propel.builder.addComments` à `true` dans le fichier `config/propel.ini` et générez le modèle. 
    397  
    398 le listing 8-14 montre d'autres exemples de `Criteria` à conditions multiples. On récupère alors tous les commentaires de Steve comprenant le mot "enjoy" et trié par date. 
     397> Le meilleur moyen de découvrir les méthodes disponibles dans les classes générées est de jeter un coup d'œil aux fichiers `Base` du répertoire `lib/model/om/` après la génération. Les noms des méthodes sont suffisamment explicite, mais si vous avez besoin de plus de commentaires, passez le paramètre `propel.builder.addComments` à `true` dans le fichier `config/propel.ini` et générez le modèle. 
     398 
     399Le listing 8-14 montre d'autres exemples de `Criteria` à conditions multiples. On récupère alors tous les commentaires de Steve comprenant le mot "enjoy" , triés par date. 
    399400 
    400401Listing 8-14 - Autres exemples de récupération d'enregistrements par `Criteria` avec `doSelect()` -- Critère avec condition 
    417418    ORDER BY blog_comment.CREATED_AT ASC 
    418419 
    419 Tout comme SQL est un langage simple qui vous permet de construire des requêtes très complexes, l'objet Criteria permet de manipuler des conditions de différents niveaux de complexité. Beaucoup de développeurs réfléchissent en SQL avant de penser orienté objet donc pour ceux qui sont habitué à SQL plutôt qu'à la logique objet, le concept de `Criteria` risque d'être difficile à comprendre au premier abord. La meilleure façon l'appréhender est d'apprendre par l'exemple. Le site de Symfony regorge d'exemple d'utilisation de `Criteria` qui pourront vous éclairer de bien des manières. 
    420  
    421 En plus de la méthode `doSelect()`, chaque classe Peer possède une méthode `doCount()`, qui compte le nombre d'enregistrements correspondant à une requête. Le résultat est un entier. Etant donné que dans ce cas précis, aucun objets n'est traité, l'hydrating n'intervient pas. La méthode `doCount()` est donc plus rapide que `doSelect()` 
     420Tout comme SQL est un langage simple qui vous permet de construire des requêtes très complexes, l'objet Criteria permet de manipuler des conditions de différents niveaux de complexité. Beaucoup de développeurs réfléchissent en SQL avant de penser orienté objet, donc pour ceux qui sont habitué à SQL plutôt qu'à la logique objet, le concept de `Criteria` risque d'être difficile à comprendre au premier abord. La meilleure façon l'appréhender est d'apprendre par l'exemple. Le site de Symfony regorge d'exemples d'utilisation de `Criteria` qui pourront vous éclairer de bien des manières. 
     421 
     422En plus de la méthode `doSelect()`, chaque classe Peer possède une méthode `doCount()`, qui compte le nombre d'enregistrements correspondant à une requête. Le résultat est un entier. Etant donné que dans ce cas précis aucun objets n'est traité, l'hydrating n'intervient pas. La méthode `doCount()` est donc plus rapide que `doSelect()` 
    422423 
    423424Les classes Peer possèdent aussi les méthodes `doDelete()`, `doInsert()` et `doUpdate()` qui acceptent toute un paramètre `Criteria` 
    424 Ces méthodes vous permette d'exécuter les ordres `DELETE`, `INSERT` et `UPDATE` sur vos bases. Regardez les classes Peer générées pour en en savoir à propos de ces méthodes Propel
    425  
    426 Enfin, si vous ne souhaitez qu'un seul objet et que vous êtes certain que le `Criteria` ne correspond qu'à un seul résultat, vous préfèrerez la méthode `doSelectOne()` à `doSelect()`. L'avantage est que cette méthode renvoie un objet à la place d'un tableau d'objets. 
     425Ces méthodes vous permette d'exécuter les ordres `DELETE`, `INSERT` et `UPDATE` sur vos bases. Pour en savoir plus à propos de ces méthodes Propel, regardez les classes Peer générées
     426 
     427Enfin, si vous ne souhaitez récuperer qu'un seul objet et que vous êtes certain que le `Criteria` ne correspond qu'à un seul résultat, utilisez la méthode `doSelectOne()` plutôt que `doSelect()`. L'avantage est que cette méthode renvoie un objet à la place d'un tableau d'objets. 
    427428 
    428429>**TIP** 
    429430>Lorsqu'un `doSelect()` renvoie un très grand nombre de résultats, vous pouvez préférer n'afficher qu'une partie de ces résultats. Pour ce faire, Symfony propose une classe de pagination sfPropelPager, qui automatise la pagination des résultats. Pour en apprendre plus à ce propos, consultez la documentation [http://www.symfony-project.org/cookbook/trunk/pager](http://www.symfony-project.org/cookbook/trunk/pager) 
    430431 
    431 ### Utilisation des requêtes SQL brut. 
    432  
    433 Certaines fois vous aurez besoin de résultats particuliers calculés par la base de données plutôt que d'objets. 
    434 Par exemple, pour récupérer la dernière date de création des articles, il serait stupide de récupérer tous les articles et de boucler sur le tableau résultat. Il serait mieux que la base puisse vous fournir immédiatement ce résultat, car cela éviterait tout le processus d'hydrating 
    435  
    436 De plus, il serait préférable de ne pas faire appelle aux commandes PHP pour ce faire, parce que vous perdriez tout le bénéfice de l'abstraction de données. Ceci veut donc dire que vous avez besoin de vous substituer à l'ORM (Propel) mais pas à l'abstraction de données (Creole) 
     432### Utilisation de requêtes SQL brut. 
     433 
     434Vous aurez parfois besoin de résultats particuliers, calculés par la base de données plutôt que d'objets. 
     435Par exemple, pour récupérer le dernier article créé (en foction de la date de création), il serait stupide de récupérer tous les articles et de boucler sur le tableau résultat. Il serait préférable que la base puisse vous fournir immédiatement ce résultat, car cela éviterait tout le processus d'hydrating 
     436 
     437De plus, il serait préférable de ne pas faire appel aux commandes PHP pour ce faire, parce que vous perdriez tout le bénéfice de l'abstraction de données. Ceci veut donc dire que vous avez besoin de vous substituer à l'ORM (Propel) mais pas à l'abstraction de données (Creole) 
    437438 
    438439Interroger la base avec Creole nécessite qui vous suiviez les étapes suivantes : 
    441442  2. Construire une requête. 
    442443  3. Créer une déclaration. 
    443   4. Boucler dans le résultat produit par la requête de la déclaration. 
     444  4. Boucler sur le résultat produit par la requête de la déclaration. 
    444445 
    445446C'est surement du charabia pour vous, mais le listing 8-15 devrait être un peu plus explicite. 
    456457    $max = $resultset->getInt('max'); 
    457458 
    458 Comme pour Propel, les requêtes Creole ne sont pas évidentes quand vous démarrez avec. Une fois de plus, les exemples des applications existantes et les tutoriels vous permettront de mieux comprendre. 
     459Comme pour Propel, les requêtes Creole ne sont pas évidentes à appréhender au départ. Une fois de plus, les exemples des applications existantes et les tutoriels vous permettront de mieux comprendre le principe. 
    459460 
    460461>**CAUTION** 
    461 >Si vous êtes tenté d'accéder directement à la base sans passer par ce procédé, vous risquez de perdre la sécurité et l'abstraction offertes par Creole. Utiliser Creole est certes plus long, mais garantit les performances, la portabilité et la sécurité de votre application. Ceci est d'autant plus vrai lorsque les requêtes contiennent des informations provenant d’une source non sûre (comme un utilisateur internet lambda). Creole effectue les échappements et autres opérations de sécurité nécessaires à votre base. Ce passer de Creole vous expose aux attaques par injection de SQL. 
     462>Si vous êtes tenté d'accéder directement à la base sans passer par ce procédé, vous risquez de perdre la sécurité et l'abstraction offertes par Creole. Utiliser Creole est certes plus long, mais garantit les performances, la portabilité et la sécurité de votre application. Ceci est d'autant plus vrai lorsque les requêtes contiennent des informations provenant d’une source non sûre (comme un utilisateur internet lambda). Creole effectue les échappements et autres opérations de sécurité nécessaires à votre base. Se passer de Creole vous expose aux attaques par injection de SQL. 
    462463 
    463464### Utilisation des colonnes de dates spéciales 
    464465 
    465 Habituellement, lorsque table possède une colonne nommée `created_at`, elle est utilisé une variable timstamp de la date de création de l'enregistrement. Il en est de même pour la colonne `updated_at` qui est mise à jour à chaque fois que l'enregistrement correspondant est modifié. 
    466  
    467 La bonne nouvelle est que Symfony reconnait les noms de ces colonnes et gère leur mise à jour pour vous. Vous n'avez plus à vous soucier de la mise à jour des colonnes `created_at` ni `updated_at`. Leur mise à jour devient transparente comme le montre le listing 8-16. Il en est de même pour les colonnes `created_on` et `updated_on` 
     466Habituellement, lorsque table possède une colonne nommée `created_at`, elle est utilisé pour stocker la date de création de l'enregistrement au format timestamp. Il en est de même pour la colonne `updated_at` qui est mise à jour à chaque fois que l'enregistrement est modifié. 
     467 
     468La bonne nouvelle est que Symfony reconnait les noms de ces colonnes et gère leur mise à jour pour vous. Vous n'avez pas à vous soucier de la mise à jour des colonnes `created_at` ni `updated_at`. Leur mise à jour devient transparente comme le montre le listing 8-16. Il en est de même pour les colonnes `created_on` et `updated_on` 
    468469 
    469470Listing 8-16 - Les colonnes `created_at` et `updated_at` sont gérées automatiquement. 
    485486>**SIDEBAR** 
    486487> 
    487 >Refactorisation du modèle de donnée 
    488 > 
    489 >Quand on développe un projet avec Symfony, on commence souvent pas coder la logique de domaine au sein des actions. Mais les requête à la base et la manipulation du modèle ne doit pas être stocké au niveau du contrôleur. Ainsi toutes la logique concernant les donnes doit être déplacée dans le modèle. Si vous êtes amené à écrire plusieurs fois la même requête à différent endroit, vous devriez envisager de transférer ce code au niveau du modèle. Cela aide à conserver un minimum de code lisible pour les actions. 
    490 > 
    491 >Par exemple, imaginez le code nécessaire à la récupération des dix articles les plus populaire pour un tag donné (passé en paramètre à la requête). Ce code ne devrait pas se trouver dans une action mais dans le modèle. En fait, vous devriez afficher cette liste via un gabarit et l'action correspondante devrait ressembler à ça : 
     488>Refactorisation du modèle de données 
     489> 
     490>Quand on développe un projet avec Symfony, on commence souvent par coder la logique au sein des actions. Mais les requêtes à la base et la manipulation du modèle ne doivent pas être stockées au niveau du contrôleur. Ainsi toute la logique concernant les données doit être déplacée dans le modèle. Si vous êtes amené à écrire plusieurs fois la même requête à différents endroits, vous devriez envisager de transférer ce code au niveau du modèle. Cela aide à conserver un minimum de code lisible pour les actions. 
     491> 
     492>Par exemple, imaginez le code nécessaire à la récupération des dix articles les plus populaires pour un tag donné (passé en paramètre à la requête). Ce code ne devrait pas se trouver dans une action mais dans le modèle. En fait, vous devriez afficher cette liste via un gabarit et l'action correspondante devrait ressembler à ça : 
    492493> 
    493494>     [php] 
    501502> L'action crée une classe d'objet `Tag`. Ainsi tout le code nécessaire à l'interrogation de la base est localisé dans la méthode `getPopularArticles()` de cette classe. Cela rend le code plus lisible et ce code peut facilement être réutilisé par une autre action. 
    502503> 
    503 >Déplacer du code dans un endroit plus approprié est une des techniques de refactorisation. Si vous l'adopter comme habitude, le code sera plus compréhensible et plus facile à maintenir pour un autre développeur. Nous pouvons admettre qu'une bonne règle pour savoir quand refactoriser la couche de donnée, est de ne pas dépasser dix lignes de code PHP par action. 
    504  
    505 Connexions à la base de données 
     504>Déplacer du code dans un endroit plus approprié est une des techniques de refactorisation. Si vous l'adoptez comme habitude, le code sera plus compréhensible et plus facile à maintenir pour un autre développeur. Nous pouvons admettre qu'une bonne règle pour savoir quand refactoriser la couche de donnée, est de ne pas dépasser dix lignes de code PHP par action. 
     505 
     506Connexion à la base de données 
    506507------------------------------- 
    507508 
    508 Le modèle de données est indépendant de la base employée, mais vous êtes obligé d'utiliser une base de données. Les informations minimums nécessaires à Symfony pour interroger les bases de données sont le nom, le code d'accès et le type de base de données. Ces informations doivent être précisées dans le fichier `databases.yml` du répertoire `config\`. Le listing 8-17 monte l'exemple d'un tel fichier. 
     509Le modèle de données est indépendant de la base utilisée, mais vous êtes obligé d'utiliser une base de données. Les informations minimums nécessaires à Symfony pour interroger les bases de données sont le nom, le code d'accès et le type de base de données. Ces informations doivent être précisées dans le fichier `databases.yml` du répertoire `config`. Le listing 8-17 monte l'exemple d'un tel fichier. 
    509510 
    510511Listing 8-17 - Exemple de paramétrage d'une connexion à une base de données, dans `myproject/config/databases.yml` 
    530531          persistent:         true      # Use persistent connections 
    531532 
    532 Les paramètres de connexion sont dépendants de l'environnement. Vous pouvez définir des paramétrages différents pour les environnements `prod`, `dev` et `test` ou tout autre environnement. De même ce paramétrages peut être définit par application en renseignant des valeurs particulières dans des fichiers de configuration spécifique aux applications comme `apps/myapp/config/databases.yml`. Par exemple, vous pouvez utiliser cette approche pour définir des politiques de sécurité différentes pour vos applications de front-end ou back-end, et définir différents utilisateurs avec des privilèges différents pour gérer tout ça. 
     533Les paramètres de connexion sont dépendants de l'environnement. Vous pouvez définir des paramétrages différents pour les environnements `prod`, `dev` et `test` ou tout autre environnement. De même ce paramétrage peut être définit par application en renseignant des valeurs particulières dans des fichiers de configuration spécifiques aux applications comme `apps/myapp/config/databases.yml`. Par exemple, vous pouvez utiliser cette approche pour définir des politiques de sécurité différentes pour vos applications de front-end ou back-end, et définir différents utilisateurs avec des privilèges différents pour gérer tout ça. 
    533534 
    534535Vous pouvez définir plusieurs connexions pour chaque environnement. Chaque connexion pointe vers un schéma identifié par le même nom.