Cette partie de la documentation est en cours de traduction. Cela signifie qu'elle est traduite de manière soit incomplète, soit inexacte. En attendant que cette traduction soit terminée, vous pouvez consulter la version en anglais pour des informations plus fiables.
Mon premier projet avec Symfony
Alors, vous voulez essayer ? Construisons ensemble en une heure une application web pleinement fonctionnelle. Que voulez-vous faire ? Une application de vente de livres ? Une autre idée ? Un blog! Bonne idée, allons-y.
Nous supposons que vous travaillez avec apache/PHP5 installés et lancés sur votre serveur local. Vous aurez aussi besoin de l'extension SQLite qui est fournie et compilée par défaut avec PHP5. Néanmoins, depuis PHP 5.1.0, vous devez activer manuellement l'extension dans php.ini. (infos ici)
Installer Symfony et initialiser le projet
Pour faire vite, nous allons utiliser le bac à sable de Symfony (sandbox) (Vous pouvez aussi télécharger le code source final). Il s'agit d'un projet Symfony vierge dans lequel toutes les bibliothèques sont déjà inclues et toutes les configurations standards déjà réalisées. Le grand avantage du bac à sable par rapport à d'autres types d'installations est que vous pouvez immédiatement commencer à expérimenter.
Téléchargez le ici : sf_sandbox.tgz, décompressez-le à la racine de votre répertoire web. Voir le readme inclus pour plus d'informations. L'arborescence des fichiers devrait ressembler à :
www/
sf_sandbox/
apps/
frontend/
batch/
cache/
config/
data/
sql/
doc/
api/
lib/
model/
log/
test/
web/
css/
images/
js/
uploads/
Le projet sf_sandbox contient donc une application frontend. Testez le bac à sable en saisissant l'URL suivante :
[php] http://localhost/sf_sandbox/web/index.php/
Vous devriez voir la page de configuration suivante :
NOTE (NdT) Si vous ne voyez par cette page, vérifiez que
magic_quotes_gpcest bien àoffdans votre fichier de configuration php.ini. Pour plus d'informations, consultez la partie installation du forum dans laquelle beaucoup de cas particuliers ont déjà été résolus.
Vous pouvez aussi installer Symfony dans un dossier quelconque et configurer votre serveur web avec un Virtual Host ou un Alias. Le livre de Symfony contient des chapitres détaillés sur l'installation et la structure des fichiers.
Initialiser le modèle de données
Le blog contiendra des articles qu'il sera possible de commenter. Créez et éditez le fichier sf_sandbox/config/schema.yml et collez-y la configuration suivante :
propel:
weblog_post:
_attributes: { phpName: Post }
id:
title: varchar(255)
excerpt: longvarchar
body: longvarchar
created_at:
weblog_comment:
_attributes: { phpName: Comment }
id:
post_id:
author: varchar(255)
email: varchar(255)
body: longvarchar
created_at:
Ce fichier de configuration utilise la syntaxe YAML. Il s'agit d'un langage très simple permettant l'emploie d'arborescences style XML décrites par indentation. De plus, c'est plus simple à lire et a écrire que XML. Il faut cependant retenir que l'indentation à un sens et que les tabulations sont strictement interdites. Pensez à n'utiliser que les espaces. Pour plus d'informations que YAML, lisez le chapitre concernant la configuration.
Ce code décrit deux tables Post et Comment. Sauvegardez-le et, en ligne de commande sous le répertoire sf_sandbox/, saisissez :
$ symfony propel-build-model
NOTE Assurez-vous d'être à la racine du projet (sf_sandbox/) avant de lancer la commande
symfony
Certaines classes sont crées dans le répertoire sf_sandbox/lib/model/. Ce sont les classes du mappage objet-relationnel (ORM) qui nous permet d'avoir accès à une base de données relationnelle à partir d'un code orienté objet sans avoir à écrire une seule requête SQL. Symfony utilise la bibliothèque Propel pour cela. Nous appellerons ces objets : le modèle (Vous en apprendrez plus sur ce point au chapitre 8 - Inside the Model Layer).
Sur une de commande saisissez :
$ symfony propel-build-sql
Un fichier lib.model.schema.sql est créé dans sf_sandbox/data/sql/. Cette requête SQL peut être utilisée pour initialiser une base de données avec une structure identique. Vous pourriez créer une base de données dans MySQL avec la ligne de commande ou une interface web (tel que décrit dans le chapitre modèle). Heureusement, le bac à sable de Symfony est configuré pour fonctionner de façon autonome avec un simple fichier SQLite. Vous n'avez donc pas à initialiser une base de données. Par défaut, le projet sf_sandbox utilisera une base de données nommée sandbox.db située dans sf_sandbox/data/. Pour créer la structure de table à partir du fichier SQL, saisissez :
$ symfony propel-insert-sql
NOTE Ne vous inquiétez pas, il est normal qu'un avertissement apparaisse à ce moment là. La commande
insert-sqlefface les tables existantes avant de créer celles de votre fichierlib.model.schema.sqlor il n'existe pas encore de tables à effacer.
Créer la structure de l'application
Les fonctionnalités classiques d'un blog sont de créer, récupérer, modifier et supprimer des articles et des commentaires. En anglais "Create, Retrieve, Update, Delete" donne l'acronyme CRUD. Comme vous découvrez Symfony, vous n'écrirez pas de code Symfony dans le vide, mais vous laisserez Symfony fabriquer une structure que vous pourrez ensuite utiliser et modifier comme il vous plaira. Symfony peut interpréter le modèle de données pour générer l'interface CRUD automatiquement.
> $ php symfony propel-generate-crud frontend post Post > $ php symfony propel-generate-crud frontend comment Comment > $ php symfony clear-cache > > Sur les système *nix, vous devrez modifier certains droits : > $ chmod 777 data > $ chmod 777 data/sandbox.db
Vous avez maintenant deux modules (post et comment) qui vont vous permettre de manipuler les enregistrements des tables Post et Comment. Un module représente généralement une page ou un groupe de pages ayant un même but. Les nouveaux modules sont placés dans le répertoire sf_sandbox/apps/frontend/modules/ et accessibles via les URLs :
[php] http://localhost/sf_sandbox/web/frontend_dev.php/post http://localhost/sf_sandbox/web/frontend_dev.php/comment
N'hésiter pas à créer un nouvel article pour que le blog soit un peu moins vide.
Plus d'informations sur le CRUD et la structure des projets Symfony (projet, application, module).
NOTE Dans les URLs ci-dessus, le nom du script principal (le contrôleur principal dans Symfony) a été changé de
index.phpàfrontend_dev.php. Les deux scripts accèdent à la même application mais dans deux environnements différents . Avecfrontend_dev.php, vous accédez à l'application dans l'environnement de développement qui possède des outils pratiques comme la barre d'outils de debug dans le coin supérieur droit de l'écran et l'outil de configuration rapide. C'est pourquoi la création de chaque page est plus lente que lors de l'utilisation deindex.phpqui est le contrôleur principal de l'environnement de production, prévu pour être plus rapide. Si vous préférez utiliser l'environnement de production, remplacezfrontend_dev.php/parindex.php/dans les URLs suivantes et n'oubliez pas de vider le cache après :
$ symfony clear-cache
http://localhost/sf_sandbox/web/index.php/
Plus d'informations sur les environnements.
Modifier la mise en page
Afin de naviguer entre les deux modules, le blog a besoin d'une navigation globale.
Modifiez le gabarit principal sf_sandbox/apps/frontend/templates/layout.php et changez le contenu de la balise
[php]
<div id="container" style="width:600px;margin:0 auto;border:1px solid grey;padding:10px">
<div id="navigation" style="display:inline;float:right">
<ul>
<li><?php echo link_to('List of posts', 'post/list') ?></li>
<li><?php echo link_to('List of comments', 'comment/list') ?></li>
</ul>
</div>
<div id="title">
<h1><?php echo link_to('My first symfony project', 'default/index') ?></h1>
</div>
<div id="content" style="clear:right">
<?php echo $sf_content ?>
</div>
</div>
Veuillez excuser la pauvreté du design et l'utilisation des styles à l'intérieur des balises, mais une heure c'est peu de temps.
Profitez-en pour changer le titre de vos pages. Editez le fichier de configuration de la vue de l'application (sf_sandbox/apps/frontend/config/view.yml), trouvez la ligne de la clef title et changez-là par ce qui suit :
default: http_metas: content-type: text/html; charset=utf-8
metas:
title: The best weblog ever
robots: index, follow
description: symfony project
keywords: symfony, project
language: en
La page d'accueil elle-même a besoin d'être modifiée. Elle utilise le modèle par défaut du module default, qui est enregistré dans le framework et non dans un répertoire de votre application. Pour ce faire, vous devez créer un module main :
$ php symfony init-module frontend main
Par défaut, le fichier index affiche un message de félicitation. Pour l'enlever éditez le fichier sf_sandbox/apps/frontend/modules/main/actions/actions.class.php et supprimez-en le contenu comme suit :
[php]
public function executeIndex()
{
}
Editez aussi le fichier sf_sandbox/apps/frontend/modules/main/templates/indexSuccess.php pour personnaliser le message d'accueil :
[php]
<h1>Bienvenue sur mon weblog</h1>
<p>Vous êtes le <?php echo rand(1000,5000) ?>ème visiteur aujourd'hui.</p>
Maintenant vous devez indiquer à Symfony quelle action sera exécutée à l'appel de la page d'accueil. Pour ce faire, éditez sf_sandbox/apps/frontend/config/routing.yml et changez les règles de homepage comme suit :
[php]
homepage:
url: /
param: { module: main, action: index }
Testez le résultat en ré-affichant la page d'accueil
http://localhost/sf_sandbox/web/frontend_dev.php/
Dès maintenant vous pouvez commencez à utiliser votre nouvelle application web : Créez un nouveau article de test et un nouveau commentaire de test à cet article.
Plus d'informations sur les vues et la mise en page.
Passer des données depuis l'action au modèle
Rapide n'est-ce pas ? Maintenant il est temps d'associer le module comment avec post afin d'afficher les commentaires sous les articles.
Tout d'abord, il faut que les commentaires associés soient mis à disposition du gabarit des articles. Dans Symfony, ce type de logique est classée dans les actions. Editez le fichier des actions sf_sandbox/apps/frontend/modules/post/actions/actions.class.php et modifiez la méthode executeShow() en y ajoutant les 4 dernières lignes :
[php]
public function executeShow ()
{
$this->post = PostPeer::retrieveByPk($this->getRequestParameter('id'));
$c = new Criteria();
$c->add(CommentPeer::POST_ID, $this->getRequestParameter('id'));
$c->addAscendingOrderByColumn(CommentPeer::CREATED_AT);
$this->comments = CommentPeer::doSelect($c);
$this->forward404Unless($this->post instanceof Post);
}
Les objets Criteria et -Peer font partie de la couche ORM Propel. Ces 4 lignes exécuteront une requête SQL sur la table Comment pour récupérer les commentaires liés à l'article courant (celui désigné par le paramètre id dans l'URL). La ligne $this->comments dans l'action donnera accès à la variable $comment dans le modèle correspondant. Maintenant modifiez le gabarit d'affichage de l'article dans sf_sandbox/apps/frontend/modules/post/templates/showSuccess.php en y ajoutant à la fin :
[php]
...
<?php use_helper('Text') ?>
<?php use_helper('Date') ?>
<hr />
<?php if($comments) : ?>
<p><?php echo count($comments) ?> comment<?php if(count($comments)>1) : ?>s<?php endif ?> to this post.</p>
<?php foreach ($comments as $comment): ?>
<p><em>posted by <?php echo $comment->getAuthor() ?> on <?php echo format_date($comment->getCreatedAt()) ?></em></p>
<div class="comment" style="margin-bottom:10px;">
<?php echo simple_format_text($comment->getBody()) ?>
</div>
<?php endforeach ?>
<?php endif ?>
Cette page utilise de nouvelles fonction PHP (format_date() et simple_format_text()) fournies par Symfony, appelées 'helpers' (NdT : Volontairement non traduits) parce qu'elles font certaines tâches à votre place qui auraient normalement exigées plus de temps et de code. Créez un nouveau commentaire à votre premier article, puis vérifiez le de nouveau, soit en cliquant sur son numéro dans la liste, soit en saisissant directement :
http://localhost/sf_sandbox/web/frontend_dev.php/post/show?id=1
Ca avance.
Apprenez en plus sur les conventions de nommage.
Ajouter un enregistrement relatif à une autre table
En ajoutant un commentaire, vous pouvez choisir l'id de l'article relatif, mais ce n'est pas très intuitif. Par conséquent nous allons changer ça et nous assurer que l'utilisateur reviendra à l'article qu'il lisait avant d'y ajouter un commentaire.
D'abord, dans le modèle modules/post/templates/showSuccess.php, ajouter cette ligne à la fin :
[php]
<?php echo link_to('Add a comment','comment/create?post_id='.$post->getId()) ?>
Le helper link_to() crée un hyperlien poitant vers l'action create du module comment, vous pouvez ainsi ajouter un commentaire directement depuis la page de détails de l'article. Ensuite, ouvrez modules/comment/templates/editSuccess.php et remplacez-y les lignes suivantes :
[php]
<tr>
<th>Post*:</th>
<td><?php echo object_select_tag($comment, 'getPostId', array (
'related_class' => 'Post',
)) ?></td>
</tr>
Par:
[php]
<?php if ($sf_request->hasParameter('post_id')): ?>
<?php echo input_hidden_tag('post_id',$sf_request->getParameter('post_id')) ?>
<?php else: ?>
<tr>
<th>Post*:</th>
<td><?php echo object_select_tag($comment, 'getPostId', array ('related_class' => 'Post')) ?></td>
</tr>
<?php endif ?>
Dans la page comment/create le formulaire pointe vers une action comment/update, qui redirige vers comment/show quand il est soumis (ceci est le comportement standard dans les CRUDs générés). Pour un blog, cela veut dire qu'après avoir ajouté un commentaire à un article, le détail de ce commentaire est affiché. Il serait plus logique d'afficher l'article avec ses commentaires. Ouvrez donc modules/comment/actions/actions.class.php et observez la méthode executeUpdate(). Notez que le champ created_at n'est pas défini dans l'action : Symfony sait qu'un champ nommé created_at doit être mis à jour avec la valeur de l'heure système quand un enregistrement est créé. La redirection finale de l'action doit être modifiée pour pointer vers la bonne action. Changez-la en :
[php] public function executeUpdate () { if (!$this->getRequestParameter('id', 0)) { $comment = new Comment(); } else { $comment = CommentPeer::retrieveByPk($this->getRequestParameter('id')); $this->forward404Unless($comment); }
$comment->setId($this->getRequestParameter('id'));
$comment->setPostId($this->getRequestParameter('post_id'));
$comment->setAuthor($this->getRequestParameter('author'));
$comment->setEmail($this->getRequestParameter('email'));
$comment->setBody($this->getRequestParameter('body'));
$comment->save();
return $this->redirect('post/show?id='.$comment->getPostId());
}
Les utilisateurs peuvent maintenant ajouter des commentaires à des articles et revenir sur cet article après coup. Vous vouliez un Blog ? Vous avez un blog
Plus d'informations sur les actions.
Le formulaire de validation
Le visiteur peut valider un commentaire sans rien y saisir et cela risque de polluer la base de données. Afin d'éviter cela, créez un fichier update.yml dans le répertoire sf_sandbox/apps/frontend/modules/comment/validate/ (créez-le si besoin est) et saisissez-y :
methods:
post: [author, email, body]
get: [author, email, body]
fillin:
activate: on
names:
author:
required: Yes
required_msg: The name field cannot be left blank
email:
required: No
validators: emailValidator
body:
required: Yes
required_msg: The text field cannot be left blank
emailValidator:
class: sfEmailValidator
param:
email_error: The email address is not valid.
NOTE Faites attention à ne pas copier les 4 espaces au début de chaque lignes sinon l'interpreteur YAML échouera. Le premier caractère du fihicer doit être le 'm' de 'methods'.
L'activation de fillin permet de renseigner les champs du formulaire avec les valeurs précédemment saisies au cas où la validation échouerait. L'ensemble des déclarations de la partie names précise les règles associés à chacun de ces champs du formulaire.
Par lui même, le contrôleur redirigera l'utilisateur vers le gabarit updateError.php si une erreur est détectée. Il serait mieux que la page soit réaffichée avec un message d'erreur. Pour ce faire, ajoutez une méthode handleError à la classe d'actions du fichier modules/comment/actions/actions.class.php:
[php]
public function handleError()
{
$this->forward('comment', 'create');
}
Pour finir, editez le modèle modules/comment/templates/editSuccess.php et insérez-y au début :
[php]
<?php if ($sf_request->hasErrors()): ?>
<div id="errors" style="padding:10px;">
Corrigez les erreurs suivantes et validez à nouveau :
<ul>
<?php foreach($sf_request->getErrors() as $error): ?>
<li><?php echo $error ?></li>
<?php endforeach ?>
</ul>
</div>
<?php endif ?>
Vous obtenez une formulaire efficace.
Pour en apprendre plus à propos des formulaires de validations
Changer l'aspect des URL
Avez-vous noté que les URL sont interprétées ? Il est possible de les rendre plus compréhensible pour l'utilisateur mais surtout pour les moteurs de recherche. Nous allons utiliser les titres des articles comme URL pour ces articles
Les problème est alors que les titres contiennent des caractères spéciaux comme les espaces et que cela risque de polluer les URL finales avec des '%20' et autres symboles dans le genre. Vous allez donc devoir créer une nouvelle méthode dans l'objet Post afin d'obtenir des titres propres et dépouillés.
Pour faire cela, éditez le fichier Post.php situé dans le répertoire sf_sandbox/lib/model/ directory et ajoutez-y la méthode suivante :
[php]
public function getStrippedTitle()
{
$result = strtolower($this->getTitle());
// strip all non word chars
$result = preg_replace('/\W/', ' ', $result);
// replace all white space sections with a dash
$result = preg_replace('/\ +/', '-', $result);
// trim dashes
$result = preg_replace('/\-$/', '', $result);
$result = preg_replace('/^\-/', '', $result);
return $result;
}
Vous pouvez dès à présent créer une action permalink pour le module post. Ajoutez la méthode suivante au fichier modules/post/actions/actions.class.php :
[php]
public function executePermalink()
{
$posts = PostPeer::doSelect(new Criteria());
$title = $this->getRequestParameter('title');
foreach ($posts as $post)
{
if ($post->getStrippedTitle() == $title)
{
break;
}
}
$this->forward404Unless($post);
$this->getRequest()->setParameter('id', $post->getId());
$this->forward('post', 'show');
}
La liste des articles peut maintenant utiliser l'action `permalinkà la place de l'actionshowpour chacun des articles. Dans le modulemodules/post/templates/listSuccess.php', supprimer l'entête id et ces cellules et modifier la cellule Title de :
[php]
<td><?php echo $post->getTitle() ?></td>
en :
[php]
<td><?php echo link_to($post->getTitle(), '/'.$sf_last_module.'/permalink?title='.$post->getStrippedTitle()) ?></td>
Une dernière chose à faire : éditez le fichier routing.yml du répertoire sf_sandbox/apps/frontend/config/ et ajoutez-y ces règles au début :
list_of_posts:
url: /latest_posts
param: { module: post, action: list }
post:
url: /weblog/:title
param: { module: post, action: permalink }
Maintenant, parcourez de nouveaux votre application et observez les URL.
Pour en savoir plus sur les Url intelligentes.
Nettoyer le frontend
S'il s'agit d'un weblog, tout le monde a le droit de poste. Ce n'est pas exactement ce à quoi vous pensiez, n'est-ce pas ? Très bien, nettoyons un peut nos gabarits.
Dans le gabarit modules/post/templates/showSuccess.php débarssez-vous du lien 'edit' en supprimant la ligne :
[php]
<?php echo link_to('edit', 'post/edit?id='.$post->getId()) ?>
Faites de même pour le gabarit modules/post/templates/listSuccess.php et supprimer
[php]
<?php echo link_to('create', 'post/create') ?>
Vous devez aussi supprimer les méthodes suivantes de modules/post/actions/actions.class.php :
- executeCreate
- executeEdit
- executeUpdate
- executeDelete
Voilà, les lecteurs ne peuvent plus poster.
Generation du backend
Pour que vous puissiez rédiger des articles, créons une application backend par la ligne de commande (toujours à partir du répertoire sf_sandbox du projet ) :
$ symfony init-app backend $ symfony propel-init-admin backend post Post $ symfony propel-init-admin backend comment Comment
Cette fois-ci nous utiliserons le générateur d'administration qui offre plus d'options et de personnalisations que le très simple générateur CRUD.
Comme vous l'avez fait pour le frontend, éditez le gabarit principal (apps/backend/template/layout.php) et ajoutez-y la navigation globale :
[php]
<div id="navigation">
<ul style="list-style:none;">
<li><?php echo link_to('Manage posts', 'post/list') ?></li>
<li><?php echo link_to('Manage comments', 'comment/list') ?></li>
</ul>
</div>
<div id="content">
<?php echo $sf_content ?>
</div>
Vous pouvez maintenant accéder à votre nouvelle application back-office dans l'environnement de développement en saisissant l'URL :
http://localhost/sf_sandbox/web/backend_dev.php/post
Le grand avantage du générateur d'administration est que vous pouvez aisément les personnaliser en éditant le fichier de configuration :
Modifiez backend/modules/post/config/generator.yml en :
generator:
class: sfPropelAdminGenerator
param:
model_class: Post
theme: default
fields:
title: { name: Title }
excerpt: { name: Exerpt }
body: { name: Body }
nb_comments: { name: Comments }
created_at: { name: Creation date }
list:
title: Post list
layout: tabular
display: [=title, excerpt, nb_comments, created_at]
object_actions:
_edit: -
_delete: -
max_per_page: 5
filters: [title, created_at]
edit:
title: Post detail
fields:
title: { type: input_tag, params: size=53 }
excerpt: { type: textarea_tag, params: size=50x2 }
body: { type: textarea_tag, params: size=50x10 }
created_at: { type: input_date_tag, params: rich=on }
Notez que parmi les colonnes existantes de la table Post, l'administration recherchera un nb_comments. Il n'y a pas encore de getter associés, mais il est simple dans ajouter dans le fichier sf_sandbox/lib/model/Post.php :
[php]
public function getNbComments()
{
return count($this->getComments());
}
Maintenant rafraîchissez la page d'administration et observez les changements :
Restreindre l'accès au backend
Pour le moment, le backend est accessible à tous. Vous devez y ajouter une restriction d'accès.
Dans apps/backend/modules/post/config/, ajoutez un security.yml avec le contenu suivant :
all:
is_secure: on
Répetez cette opération pour le module comment. Maintenant vous ne pouvez plus accéder à ces modules à moins d'être identifié.
Mais l'action d'identification n'existe pas! Très bien, vous pouvez l'ajouter simplement. Tout d'abord, créez le squelette du module de sécurité :
$ symfony init-module backend security
Ce nouveau module sera utilisé pour gérer le login et ces requêtes associées. Editez apps/backend/modules/security/templates/indexSuccess.php pour créer le formulaire de login :
[php]
Authentication
<?php if ($sf_request->hasErrors()): ?>
L'identification a échoué - Essayez de nouveau.
<?php endif ?>
<?php echo form_tag('security/login') ?>
<label for="login">login:</label>
<?php echo input_tag('login', $sf_params->get('login')) ?>
<label for="password">password:</label>
<?php echo input_password_tag('password') ?>
<?php echo submit_tag('submit', 'class=default') ?>
</form>
Ajoutez l'action login qui sera employée pour le module sécurité (dans le fichier apps/backend/modules/security/actions/actions.class.php) :
[php]
public function executeLogin()
{
if ($this->getRequestParameter('login') == 'admin' && $this->getRequestParameter('password') == 'password')
{
$this->getUser()->setAuthenticated(true);
return $this->redirect('main/index');
}
else
{
$this->getRequest()->setError('login', 'incorrect entry');
return $this->forward('security', 'index');
}
}
De même que pour le module main supprimer le code du fichier index comme suit :
[php]
public function executeIndex()
{
}
La dernière chose à faire est de spécifier que le module security est le module par défaut pour la prise en charge de l'authentification. Pour cela, ouvrez le fichier de configuration apps/backend/config/settings.yml et ajoutez-y :
all:
.actions:
login_module: security
login_action: index
A partir de maintenant, si vous essayez d'accéder à l'administration des articles, vous devrez entrer un nom d'utilisateur et un mot de passe :
En savoir plus sur la sécurité.
Conclusion
C'est terminé, l'heure est écoulée. Vous avez réussi. Vous pouvez maintenant utiliser les deux applications dans l'environnement de production et jouer avec:
frontend: http://localhost/sf_sandbox/web/index.php/
backend: http://localhost/sf_sandbox/web/backend.php/
A ce stade, si vous rencontrez une erreur, il est fort possible que ce soit parce que vous avez changé le modèle après que certaines actions aient été mises en cache (le cache n'est pas activé dans l'environnement de développement). Pour vider le cache, saisissez :
$ symfony cc
Et voilà, l'application fonctionne maintenant rapidement. Génial n'est ce pas ? Sentez-vous libre d'explorer le code, d'ajouter de nouveaux modules et de changer le design des pages.
Et n'oubliez pas de mentionner votre application symfony sur le wiki!