Development

Documentation/fr_FR/jobeet/doctrine/6 (diff)

You must first sign up to be able to contribute.

Changes between Version 1 and Version 2 of Documentation/fr_FR/jobeet/doctrine/6

Show
Ignore:
Author:
sebastien.b (IP: 82.251.154.4)
Timestamp:
03/22/09 14:57:50 (8 years ago)
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Documentation/fr_FR/jobeet/doctrine/6

    v1 v2  
    77 * Traduction : Sébastien B 
    88 * Date de traduction : 12 Mars 2009 
    9  * Date de dernière modification : 12 Mars 2009 
     9 * Date de dernière modification : 
    1010{{{ 
    1111#!html 
    1212</div> 
     13<div style="width:75%"> 
    1314}}} 
    1415= Jour 6: Aller plus loin avec le Modèle = 
    1516 
    16 Hier était un grand jour. Vous avez appris comment créer des URLs propres et comment[[BR]] 
    17 utiliser symfony pour automatiser beaucoup de choses.[[BR]][[BR]] 
    18  
    19 Aujourd'hui, nous allons améliorer Jobeet en optimisant le code ci et là. Vous en[[BR]] 
    20 apprendrez plus sur toutes les fonctions que nous avons déjà présenté au cours[[BR]] 
    21 des jours précédents.[[BR]][[BR]] 
     17Hier était un grand jour. Vous avez appris comment créer des URLs propres et comment 
     18utiliser symfony pour automatiser beaucoup de choses. 
     19 
     20Aujourd'hui, nous allons améliorer Jobeet en optimisant le code ci et là. Vous en 
     21apprendrez plus sur toutes les fonctions que nous avons déjà présenté au cours 
     22des jours précédents. 
    2223 
    2324== __L'objet Doctrine Query__ == 
    2425 
    25 Conditions du Jour 2 :[[BR]] 
     26Conditions du Jour 2 : 
    2627 
    2728  === "Quand un utilisateur arrive sur Jobeet, il doit voir la liste des jobs actifs." === 
    2829 
    29 Mais pour l'instant, tous les jobs sont affichés, qu'ils soient actifs ou non :[[BR]] 
     30Mais pour l'instant, tous les jobs sont affichés, qu'ils soient actifs ou non : 
    3031{{{ 
    3132#!php 
    4344    } 
    4445}}} 
    45 Un job est considéré actif s'il a été posté il y a moins de 30 jours. La méthode[[BR]] 
    46 `~Doctrine_Query~::execute()` crée la requête à exécuter sur la base de données.[[BR]] 
    47 Dans le code ci-dessus, aucune condition n'est spécifiée, ce qui signifie que[[BR]] 
    48 tous les enregistrements seront retournés.[[BR]] 
     46Un job est considéré actif s'il a été posté il y a moins de 30 jours. La méthode 
     47`~Doctrine_Query~::execute()` crée la requête à exécuter sur la base de données. 
     48Dans le code ci-dessus, aucune condition n'est spécifiée, ce qui signifie que 
     49tous les enregistrements seront retournés. 
    4950 
    5051Modifions cela pour n'afficher que les jobs actifs : 
    6465== __Debugging Doctrine generated SQL__ == 
    6566 
    66 Etant donné que vous n'écrivez pas les requêtes SQL, c'est Doctrine qui prend en[[BR]] 
    67 charge la génération des requêtes propres au moteur de base de donnée choisi le[[BR]] 
    68 3ème jour. Mais il est parfois utile de connaître le code SQL généré par Doctrine;.[[BR]] 
    69 Par exemple, pour debugger une requête qui ne fonctionne pas. Dans l'environnement[[BR]] 
    70 de développement, symfony enregistre toutes ces requêtes ( ainsi que beaucoup[[BR]] 
    71 d'autres informations ) dans le répertoire `log/`. There is one log file for every[[BR]] 
    72 combination of an application and an environment. Le fichier qui nous intéresse[[BR]] 
     67Etant donné que vous n'écrivez pas les requêtes SQL, c'est Doctrine qui prend en 
     68charge la génération des requêtes propres au moteur de base de donnée choisi le 
     693ème jour. Mais il est parfois utile de connaître le code SQL généré par Doctrine;. 
     70Par exemple, pour debugger une requête qui ne fonctionne pas. Dans l'environnement 
     71de développement, symfony enregistre toutes ces requêtes ( ainsi que beaucoup 
     72d'autres informations ) dans le répertoire `log/`. There is one log file for every 
     73combination of an application and an environment. Le fichier qui nous intéresse 
    7374est `frontend_dev.log` : 
    7475{{{ 
    8485    WHERE j.created_at > ? (2008-11-08 01:13:35) 
    8586}}} 
    86 Comme vous pouvez le voir, Doctrine a généré une clause WHERE pour la colonne[[BR]] 
    87 `created_at` column (`WHERE j.created_at > ?`).[[BR]] 
     87Comme vous pouvez le voir, Doctrine a généré une clause WHERE pour la colonne 
     88`created_at` column (`WHERE j.created_at > ?`). 
    8889 
    8990>>'''__NOTE__''' 
    90 >Dans la requête, `?` indique que Doctrine utilise les conditions déclarées.[[BR]] 
    91 >La valeur actuelle de `?` ( '2008-11-08 01:13:35' dans l'exemple ci-dessus )[[BR]] 
    92 >est passée pendant l'exécution de la requête. L'utilisation de conditions[[BR]] 
     91>Dans la requête, `?` indique que Doctrine utilise les conditions déclarées. 
     92>La valeur actuelle de `?` ( '2008-11-08 01:13:35' dans l'exemple ci-dessus ) 
     93>est passée pendant l'exécution de la requête. L'utilisation de conditions 
    9394>déclarées reduit considérablement le risque d'attaques du type [~SQL injection~](http://en.wikipedia.org/wiki/Sql_injection) 
    9495 
    95 Le travail est facilité mais devoir basculer entre le navigateur, l'IDE et le[[BR]] 
    96 fichier log à chaque fois que l'on veut tester une modification est assez contraignant.[[BR]] 
    97 Heureusement, symfony possède une barre d'outil de débuggage. Toutes les informations[[BR]] 
    98 nécessaire sont disponibles dans votre navigateur :[[BR]] 
     96Le travail est facilité mais devoir basculer entre le navigateur, l'IDE et le 
     97fichier log à chaque fois que l'on veut tester une modification est assez contraignant. 
     98Heureusement, symfony possède une barre d'outil de débuggage. Toutes les informations 
     99nécessaire sont disponibles dans votre navigateur : 
    99100 
    100101[[Image(web_debug_sql.png)]] 
    102103== __Object ~Serialization~__ == 
    103104 
    104 Jusqu'à présent, notre code fonctionne mais il est loin d'être parfait et ne prend[[BR]] 
    105 pas en charge les contraintes évoqués le 2ème jour :[[BR]] 
     105Jusqu'à présent, notre code fonctionne mais il est loin d'être parfait et ne prend 
     106pas en charge les contraintes évoqués le 2ème jour : 
    106107 
    107108  === "Un utilisateur peut activer à nouveau ou augmenter la validité de l'offre d'emploi pour une période de 30 jours supplémentaires..." === 
    108109 
    109 Le code actuel se base sur la valeur de la colonne `created_at` qui stocke la[[BR]] 
    110 date de création ce qui ne nous permet pas de satisfaire la condition ci-dessus.[[BR]][[BR]] 
    111  
    112 Mais si vous vous rappelez le schéma de la base décrit le 3ème jour, nous avons[[BR]] 
    113 aussi défini une colonne `expires_at`. Pour l'instant cette valeur est vide car[[BR]] 
    114 nous ne l'avons pas renseignée dans le fichier du répertoire fixture. Cette valeur[[BR]] 
    115 peut être automatiquement renseignée à plus 30 jours à partir de la date courante[[BR]] 
    116 lors de la création d'un job.[[BR]] 
    117  
    118 Quand vous devez créer une action automatique avant que l'objet Doctrine soit[[BR]] 
    119 sérialisé dans la base, vous pouvez surpasser la méthode `save()` de la classe[[BR]] 
     110Le code actuel se base sur la valeur de la colonne `created_at` qui stocke la 
     111date de création ce qui ne nous permet pas de satisfaire la condition ci-dessus. 
     112 
     113Mais si vous vous rappelez le schéma de la base décrit le 3ème jour, nous avons 
     114aussi défini une colonne `expires_at`. Pour l'instant cette valeur est vide car 
     115nous ne l'avons pas renseignée dans le fichier du répertoire fixture. Cette valeur 
     116peut être automatiquement renseignée à plus 30 jours à partir de la date courante 
     117lors de la création d'un job. 
     118 
     119Quand vous devez créer une action automatique avant que l'objet Doctrine soit 
     120sérialisé dans la base, vous pouvez surpasser la méthode `save()` de la classe 
    120121du modèle : 
    121122{{{ 
    138139    } 
    139140}}} 
    140 La méthode `~isNew()~` renvoie `true` quand l'objet n'est pas encore sérialisé[[BR]] 
    141 dans la base et `false` dans la cas contraire.[[BR]][[BR]] 
    142  
    143 A présent, modifions l'action pour récupérer les jobs actifs en utilisant la[[BR]] 
    144 colonne `expires_at` au lieu de la colonne `created_at` : [[BR]] 
     141La méthode `~isNew()~` renvoie `true` quand l'objet n'est pas encore sérialisé 
     142dans la base et `false` dans la cas contraire. 
     143 
     144A présent, modifions l'action pour récupérer les jobs actifs en utilisant la 
     145colonne `expires_at` au lieu de la colonne `created_at` :  
    145146{{{ 
    146147#!php 
    154155    } 
    155156}}} 
    156 La requête sélectionnera seulement les jobs possédant une date `expires_at`.[[BR]][[BR]] 
     157La requête sélectionnera seulement les jobs possédant une date `expires_at`. 
    157158 
    158159== __Aller plus loin avec Fixtures__ == 
    159160 
    160 Si vous actualisez la page d'accueil de Jobeet, vous ne constaterez aucun[[BR]] 
     161Si vous actualisez la page d'accueil de Jobeet, vous ne constaterez aucun 
    161162changement. Modifions le fichier fixture pour ajouter un job qui a expiré : 
    162163{{{ 
    178179        email:          job@example.com 
    179180}}} 
    180 >>'''__NOTE__'''[[BR]] 
    181 >Faites bien attention quand vous faîtes un copier/coller du code. il faut conserver[[BR]] 
    182 >l'indentation. Il doit y avoir deux espaces devant `expired_job`.[[BR]] 
    183  
    184 Comme vous pouvez le constater, il est possible de définir une valeur pour la colonne[[BR]] 
    185 `created_at` même si elle est automatiquement remplie par Doctrine. La valeur[[BR]] 
    186 définie sera utilisé à la place de la valeur automatique. Rechargez les fixtures[[BR]] 
    187 et actualisez la page d'accueil pour vérifier que l'ancien job n'apparaisse pas :[[BR]] 
     181>>'''__NOTE__''' 
     182>Faites bien attention quand vous faîtes un copier/coller du code. il faut conserver 
     183>l'indentation. Il doit y avoir deux espaces devant `expired_job`. 
     184 
     185Comme vous pouvez le constater, il est possible de définir une valeur pour la colonne 
     186`created_at` même si elle est automatiquement remplie par Doctrine. La valeur 
     187définie sera utilisé à la place de la valeur automatique. Rechargez les fixtures 
     188et actualisez la page d'accueil pour vérifier que l'ancien job n'apparaisse pas : 
    188189{{{ 
    189190    $ php symfony Doctrine:data-load 
    190191}}} 
    191 Vous pouvez aussi exécuter la requête suivante pour être sûr que la colonne `expires_at`[[BR]] 
    192 soit automatiquement renseignée en fonction de la valeur de la colonne `created_at`[[BR]] 
    193 grâce à la méthode `save()` :[[BR]] 
     192Vous pouvez aussi exécuter la requête suivante pour être sûr que la colonne `expires_at` 
     193soit automatiquement renseignée en fonction de la valeur de la colonne `created_at` 
     194grâce à la méthode `save()` : 
    194195{{{ 
    195196    SELECT `position`, `created_at`, `expires_at` FROM `jobeet_job`; 
    197198== __Configuration Personnalisée__ == 
    198199 
    199 Dans la méthode `JobeetJob::save()`, nous avons figé le nombre de jours qui détermine[[BR]] 
    200 l'expiration d'un job. Il serait préférable que la valeur de 30 jours soit paramétrable.[[BR]] 
    201 symfony utilise le fichier configuration interne `~app.yml~` qui permet de définir[[BR]] 
    202 des paramètres spécifiques à l'application. Ce fichier YAML peut contenir[[BR]] 
     200Dans la méthode `JobeetJob::save()`, nous avons figé le nombre de jours qui détermine 
     201l'expiration d'un job. Il serait préférable que la valeur de 30 jours soit paramétrable. 
     202symfony utilise le fichier configuration interne `~app.yml~` qui permet de définir 
     203des paramètres spécifiques à l'application. Ce fichier YAML peut contenir 
    203204n'importe quel paramètre nécessaire : 
    204205{{{ 
    207208      active_days: 30 
    208209}}} 
    209 Dans l'application, ces paramètres sont disponibles à travers la classe globale[[BR]] 
     210Dans l'application, ces paramètres sont disponibles à travers la classe globale 
    210211`~sfConfig~` : 
    211212{{{ 
    213214    sfConfig::get('app_active_days') 
    214215}}} 
    215 Les paramètres utilisent le préfixe `app_` car la classe `sfConfig` fournit[[BR]] 
    216 également des accès aux paramètres symfony que nous verrons plus tard.[[BR]] 
     216Les paramètres utilisent le préfixe `app_` car la classe `sfConfig` fournit 
     217également des accès aux paramètres symfony que nous verrons plus tard. 
    217218 
    218219Mettez le code à jour pour prendre en compte ce nouveau paramètre : 
    230231    } 
    231232}}} 
    232 Le fichier de configuration `app.yml` est un bon moyen de centraliser les paramètres[[BR]] 
    233 globaux de votre application.[[BR]][[BR]] 
    234  
    235 Pour finir, si vous avez besoin de définir des paramètres étendus, il suffit de[[BR]] 
    236 créer un nouveau fichier `app.yml` dans le répertoire `config` à la racine de[[BR]] 
    237 votre projet symfony.[[BR]][[BR]] 
     233Le fichier de configuration `app.yml` est un bon moyen de centraliser les paramètres 
     234globaux de votre application. 
     235 
     236Pour finir, si vous avez besoin de définir des paramètres étendus, il suffit de 
     237créer un nouveau fichier `app.yml` dans le répertoire `config` à la racine de 
     238votre projet symfony. 
    238239 
    239240== __Refactoring__ == 
    240241 
    241 Bien que notre code fonctionne correctement, il n'est pas encore parfait.[[BR]] 
    242 Etes-vous capable de repérer le problème ?[[BR]][[BR]] 
     242Bien que notre code fonctionne correctement, il n'est pas encore parfait. 
     243Etes-vous capable de repérer le problème ? 
    243244 
    244245Le code `Doctrine_Query` n'appartient pas à l'action ( couche Controlleur ), mais 
    261262    } 
    262263}}} 
    263 Il est maintenant possible de récupérer les jobs actifs grâce à cette méthode dans[[BR]] 
     264Il est maintenant possible de récupérer les jobs actifs grâce à cette méthode dans 
    264265les actions : 
    265266{{{ 
    270271    } 
    271272}}} 
    272 La refactorisation présente plusieurs avantages :[[BR]][[BR]] 
    273  
    274  * Le code pour récupérer les jobs actifs se trouve dans la Modèle, là ou est sa place[[BR]] 
    275  * Le code du Controlleur est plus lisible[[BR]] 
    276  * La méthode `getActiveJobs()` est réutilisable ( dans une autre action par exemple )[[BR]] 
    277  * Le code du modèle peut être testé indépendemment[[BR]] 
     273La refactorisation présente plusieurs avantages : 
     274 
     275 * Le code pour récupérer les jobs actifs se trouve dans la Modèle, là ou est sa place 
     276 * Le code du Controlleur est plus lisible 
     277 * La méthode `getActiveJobs()` est réutilisable ( dans une autre action par exemple ) 
     278 * Le code du modèle peut être testé indépendemment 
    278279 
    279280Récupérons les jobs grâce à la colonne `expires_at` : 
    289290    } 
    290291}}} 
    291 La méthode `orderBy` ajoute une clauser `ORDER BY` à la requête.[[BR]] 
    292 Il existe aussi la méthode `addOrderBy()`.[[BR]] 
     292La méthode `orderBy` ajoute une clauser `ORDER BY` à la requête. 
     293Il existe aussi la méthode `addOrderBy()`. 
    293294 
    294295== __Catégories en page d'accueil__ == 
    295296 
    296 Conditions du 2ème jour :[[BR]][[BR]] 
     297Conditions du 2ème jour : 
    297298 
    298299  === "Les jobs sont affichés par catégorie et par leur date de publication ( les nouveaux jobs en tête de liste." === 
    299300 
    300 Jusqu'à présent, nous n'avons pas pris en compte la catégorie associée aux jobs.[[BR]] 
    301 Afin d'afficher les jobs par catégorie, nous allons d'abord récupérer toutes les[[BR]] 
    302 catégories asscoiées à au moins un job.[[BR]][[BR]] 
     301Jusqu'à présent, nous n'avons pas pris en compte la catégorie associée aux jobs. 
     302Afin d'afficher les jobs par catégorie, nous allons d'abord récupérer toutes les 
     303catégories associées à au moins un job. 
    303304 
    304305Editer la classe `JobeetCategoryTable` et ajouter la méthode `getWithJobs()` : 
    328329    } 
    329330}}} 
    330 Dans le template, nous devons rechercher les jobs actifs dans chaque catégorie et[[BR]] 
     331Dans le template, nous devons rechercher les jobs actifs dans chaque catégorie et 
    331332les afficher. 
    332333{{{ 
    364365    </div> 
    365366}}} 
    366 >>'''__NOTE__'''[[BR]] 
    367 >Pour afficher le nom d'une catégorie, nous utilisons `echo $category` dans le template.[[BR]] 
    368 >Ca vous paraît bizarre ? `$category` n'est pas un objet, comment peut-on afficher[[BR]] 
    369 >le nom de la catégorie avec un `echo`. La réponse se trouve au jour 3 quand nous[[BR]] 
    370 >avons défini la méthode magique `__toString()` pour toutes les classes du modèle.[[BR]] 
    371  
    372 Nous devons ajouter la méthode `getActiveJobs()` à la classe `JobeetCategory` qui[[BR]] 
     367>>'''__NOTE__''' 
     368>Pour afficher le nom d'une catégorie, nous utilisons `echo $category` dans le template. 
     369>Ca vous paraît bizarre ? `$category` n'est pas un objet, comment peut-on afficher 
     370>le nom de la catégorie avec un `echo`. La réponse se trouve au jour 3 quand nous 
     371>avons défini la méthode magique `__toString()` pour toutes les classes du modèle. 
     372 
     373Nous devons ajouter la méthode `getActiveJobs()` à la classe `JobeetCategory` qui 
    373374retoune les jobs actifs pour l'objet catégorie : 
    374375{{{ 
    384385    } 
    385386}}} 
    386 La méthode JobeetCategory::getActiveJobs()` utilise la méthode `Doctrine::getTable('JobeetJob')->getActiveJobs()`[[BR]] 
    387 pour rechercher les jobs actifs de la catégorie donnée.[[BR]] 
    388  
    389 A l'appel de `Doctrine::getTable('JobeetJob')->getActiveJobs()`, nous voulons[[BR]] 
    390 restreindre la condition autrement qu'en fournissant uniquement une catégorie.[[BR]] 
    391 Au lieu de passer l'objet catégorie, nous avons décidé de passer un objet `Doctrine_Query`[[BR]] 
    392 qui est la meilleure solution pour encapsuler une condition générique.[[BR]] 
    393  
    394 Pour ce faire, il faut fusionner cet objet `Doctrine_Query` avec les criteria de la[[BR]] 
    395 méthode`getActiveJobs()`. `Doctrine_Query` étant un objet, ce sera simple :[[BR]] 
     387La méthode JobeetCategory::getActiveJobs()` utilise la méthode `Doctrine::getTable('JobeetJob')->getActiveJobs()` 
     388pour rechercher les jobs actifs de la catégorie donnée. 
     389 
     390A l'appel de `Doctrine::getTable('JobeetJob')->getActiveJobs()`, nous voulons 
     391restreindre la condition autrement qu'en fournissant uniquement une catégorie. 
     392Au lieu de passer l'objet catégorie, nous avons décidé de passer un objet `Doctrine_Query` 
     393qui est la meilleure solution pour encapsuler une condition générique. 
     394 
     395Pour ce faire, il faut fusionner cet objet `Doctrine_Query` avec les criteria de la 
     396méthode`getActiveJobs()`. `Doctrine_Query` étant un objet, ce sera simple : 
    396397{{{ 
    397398#!php 
    414415== __Limiter les résultats__ == 
    415416 
    416 Il reste encore une condition à implémenter pour la liste des jobs en page d'accueil :[[BR]] 
     417Il reste encore une condition à implémenter pour la liste des jobs en page d'accueil : 
    417418 
    418419  === "Chaque catégorie doit afficher les 10 premiers jobs et un lien doit permettre d'afficher tous les jobs d'une catégorie choisie." === 
    432433    } 
    433434}}} 
    434 La clause `~LIMIT~` est figée dans le code du Modèle, mais il est préférable de[[BR]] 
    435 pouvoir configurer cette valeur. Modifiez le template pour utiliser le nombre[[BR]] 
     435La clause `~LIMIT~` est figée dans le code du Modèle, mais il est préférable de 
     436pouvoir configurer cette valeur. Modifiez le template pour utiliser le nombre 
    436437maximum de jobs configuré dans `app.yml` : 
    437438{{{ 
    451452== __Fixtures dynamiques__ == 
    452453 
    453 A moins de passer la valeur `max_jobs_on_homepage` à une, vous ne verrez aucune[[BR]] 
    454 différence. Nous devons ajouter des jobs ans le fichier ~fixture~s. Evidemment,[[BR]] 
    455 vous pouvez faire 20, 30, ... copier/coller des jobs existants mais il y a une[[BR]] 
    456 meilleure solution. La duplication n'est pas une bonne méthode, même pour les fichiers[[BR]] 
    457 fixture.[[BR]][[BR]] 
    458  
    459 symfony à la rescousse ! Dans symfony, les fichiers ~YAML~ peuvent contenir du code[[BR]] 
    460 PHP qui sera évalué juste avant l'analyse du fichier. Editez le fichier fixture[[BR]] 
     454A moins de passer la valeur `max_jobs_on_homepage` à une, vous ne verrez aucune 
     455différence. Nous devons ajouter des jobs ans le fichier ~fixture~s. Evidemment, 
     456vous pouvez faire 20, 30, ... copier/coller des jobs existants mais il y a une 
     457meilleure solution. La duplication n'est pas une bonne méthode, même pour les fichiers 
     458fixture. 
     459 
     460symfony à la rescousse ! Dans symfony, les fichiers ~YAML~ peuvent contenir du code 
     461PHP qui sera évalué juste avant l'analyse du fichier. Editez le fichier fixture 
    461462`jobs.yml` et ajoutez le code suivant à la fin : 
    462463{{{ 
    480481    <?php endfor; ?> 
    481482}}} 
    482 Attention ! L'analyseur de YAML n'aime pas les erreurs de formatage. Gardez bien[[BR]] 
    483 à l'esprit les conseils suivants si vous ajoutez du code PHP dans un fichier YAML :[[BR]][[BR]] 
    484  
    485  * `<?php ?>` doit toujours commençer une ligne ou être intégré dans une valeur.[[BR]] 
    486  * Si `<?php ?>` fint une ligne, vous devez indiquer clairement une nouvelle ligne ("\n").[[BR]] 
    487  
    488 Rechargez les données fixtures avec `Doctrine:data-load` et vérifiez que seulement[[BR]] 
    489 `10` jobs soient affichés en page d'accueil pour la catégorie `Programming`.[[BR]] 
    490 Dans la capture d'écran suivante, nous avons modifié le nombre maximum de jobs sur[[BR]] 
     483Attention ! L'analyseur de YAML n'aime pas les erreurs de formatage. Gardez bien 
     484à l'esprit les conseils suivants si vous ajoutez du code PHP dans un fichier YAML : 
     485 
     486 * `<?php ?>` doit toujours commençer une ligne ou être intégré dans une valeur. 
     487 * Si `<?php ?>` fint une ligne, vous devez indiquer clairement une nouvelle ligne ("\n"). 
     488 
     489Rechargez les données fixtures avec `Doctrine:data-load` et vérifiez que seulement 
     490`10` jobs soient affichés en page d'accueil pour la catégorie `Programming`. 
     491Dans la capture d'écran suivante, nous avons modifié le nombre maximum de jobs sur 
    4914925 pour avoir une image de taille raisonnable : 
    492493 
    495496== __Sécuriser la page Job__ == 
    496497 
    497 Même si vous connaissez l'URL d'un job qui a expiré, il ne doit plus être possible[[BR]] 
    498 d'y accéder. Essayez l'URL d'un job expiré ( remplaçer l'`id` par l'`id`[[BR]] 
    499 correspondant dans la base de donnée - `SELECT id, token FROM jobeet_job WHERE[[BR]] 
     498Même si vous connaissez l'URL d'un job qui a expiré, il ne doit plus être possible 
     499d'y accéder. Essayez l'URL d'un job expiré ( remplaçer l'`id` par l'`id` 
     500correspondant dans la base de donnée - `SELECT id, token FROM jobeet_job WHERE 
    500501expires_at < NOW()` ) : 
    501502{{{ 
    502503    /frontend_dev.php/job/sensio-labs/paris-france/ID/web-developer-expired 
    503504}}} 
    504 Au lieu d'afficher le job, nous devons rediriger l'utilisateur vers une erreur 404.[[BR]] 
    505 Mais comment faire alors que le job est recherché automatiquement par la route ?[[BR]][[BR]] 
     505Au lieu d'afficher le job, nous devons rediriger l'utilisateur vers une erreur 404. 
     506Mais comment faire alors que le job est recherché automatiquement par la route ? 
    506507{{{ 
    507508    # apps/frontend/config/routing.yml 
    537538    } 
    538539}}} 
    539 Maintenant, si vous essayez d'accéder à un job qui a expiré, vous serez redirigé[[BR]] 
     540Maintenant, si vous essayez d'accéder à un job qui a expiré, vous serez redirigé 
    540541vers une page d'erreur 404. 
    541542 
    544545== __Lien vers la page des Catégories__ == 
    545546 
    546 A présent, nous allons ajouter un lien vers la catégorie et créer la page de cette[[BR]] 
    547 catégorie.[[BR]] 
    548  
    549 Une minute. L'heure n'est pas encore écoulée et nous n'avons pas beaucoup travaillé.[[BR]] 
    550 En fait, vous avez tout le temps nécessaire pour mettre en pratique tout ce que[[BR]] 
    551 nous avons déjà appris et implémenter cette fonction par vous-même. Vous pourrez[[BR]] 
    552 vérifier votre travail demain.[[BR]] 
     547A présent, nous allons ajouter un lien vers la catégorie et créer la page de cette 
     548catégorie. 
     549 
     550Une minute. L'heure n'est pas encore écoulée et nous n'avons pas beaucoup travaillé. 
     551En fait, vous avez tout le temps nécessaire pour mettre en pratique tout ce que 
     552nous avons déjà appris et implémenter cette fonction par vous-même. Vous pourrez 
     553vérifier votre travail demain. 
    553554 
    554555== __A demain__ == 
    555556 
    556 Travaillez votre projet Jobeet. N'hésitez pas à abuser de la documentation en ligne[[BR]] 
     557Travaillez votre projet Jobeet. N'hésitez pas à abuser de la documentation en ligne 
    557558[http://www.symfony-project.org/api/1_2/ API documentation] et de toutes les 
    558 ressources [http://www.symfony-project.org/doc/1_2/ documentation] disponibles[[BR]] 
    559 sur le site pour vous aider. On se retrouve demain pour découvrir l'implémentation[[BR]] 
    560 des catégories.[[BR]][[BR]] 
     559ressources [http://www.symfony-project.org/doc/1_2/ documentation] disponibles 
     560sur le site pour vous aider. On se retrouve demain pour découvrir l'implémentation 
     561des catégories. 
    561562 
    562563Bonne chance ! 
     564{{{ 
     565#!html 
     566</div> 
     567}}}