Un blog avec Symfony (8/)
publié le 15/09/2008 à 00:56 dans Pas à pas
Administration des commentaires
On génère le module d'administration :
$ symfony init-module back blogcomment
Nous ajoutons le nombre de commentaires dans la liste des billets et dans le filtre.
Dans le fichier back/modules/post/config/generator.yml :
generator:
class: sfPropelAdminGenerator
param:
...
fields:
...
number_of_comments: { name: Nb Comment. }
list:
...
display: [=title, category_name, excerpt, created_at, number_of_comments]
...
filters: [title, blog_category_id, created_at, _number_of_comments]
Par défaut, le champ d'un filtre sur les nombres est de type input.
Nous allons utiliser un partial afin de pouvoir créer 2 listes déroulantes (min et max) pour filtrer les commentaires. C'est pourquoi, au niveau de "filters" nous avons écrit _number_of_comments et non pas number_of_comments.
On crée un partial _number_of_comments.php dans back/modules/post/templates :
<?php
// nouveau critère de sélection
$c = new Criteria();
// selection uniquement du champ number_of_comments
$c->addSelectColumn(PostPeer::NUMBER_OF_COMMENTS);
// trie ascendant
$c->addAscendingOrderByColumn(PostPeer::NUMBER_OF_COMMENTS);
// execution de la requête
$rs = PostPeer::doSelectRS($c);
// génération d'un tableau avec les valeurs récupérées
while($rs->next())
$vals[$rs->getInt(1)] = $rs->getInt(1);
echo 'entre ';
// création de la balise <select>...</select>
echo select_tag(
// nom de la balise html
'filters[number_of_comments_min]'
// la liste des options du <select>...</select>
,options_for_select(
// les données de la base de données
$vals
// la valeur par défaut
,isset($filters['number_of_comments_min'])?$filters['number_of_comments_min']:''
// options supplémentaires ; ici pour ajouter une valeur "vide" dans la la liste
,array('include_blank' => true)
)
);
echo ' et ';
echo select_tag(
'filters[number_of_comments_max]'
,options_for_select(
$vals
,isset($filters['number_of_comments_max'])?$filters['number_of_comments_max']:''
,array('include_blank' => true)
)
);
?>
Les critères des filtres sont ajoutés à la requête SQL de sélection des données à l'aide de la méthode addFiltersCriteria().
Pour filtrer les billets de notre blog en fonction d'un intervalle de nombre de commentaires, nous allons surcharger la méthode addFiltersCriteria() dans la classe postActions (back/modules/post/actions/actions.class.php) :
protected function addFiltersCriteria($c)
{
// vérification si les champs ont été selctionnés pour filtrer
$existMin = isset($this->filters['number_of_comments_min']) && $this->filters['number_of_comments_min'] !== '';
$existMax = isset($this->filters['number_of_comments_max']) && $this->filters['number_of_comments_max'] !== '';
$existMinAndMax = $existMin && $existMax;
if ($existMinAndMax)
{
// ajout d'un criterion pour le minimum
$criterion = $c->getNewCriterion(PostPeer::NUMBER_OF_COMMENTS, $this->filters['number_of_comments_min'], Criteria::GREATER_EQUAL);
// ajout d'un criterion pour le maximum
$criterion->addAND($c->getNewCriterion(PostPeer::NUMBER_OF_COMMENTS, $this->filters['number_of_comments_max'], Criteria::LESS_EQUAL));
$c->add($criterion);
}
elseif ($existMin)
{
$c->add(PostPeer::NUMBER_OF_COMMENTS, $this->filters['number_of_comments_min'], Criteria::GREATER_EQUAL);
}
elseif ($existMax)
{
$c->add(PostPeer::NUMBER_OF_COMMENTS, $this->filters['number_of_comments_max'], Criteria::LESS_EQUAL);
}
parent::addFiltersCriteria($c);
}
Avec Symfony, pour écrire une requête à multiple conditions pour un champ, nous devons utiliser les criterions, sinon la 2e condition remplace la 1ère.

En cliquant sur le nombre de commentaires, nous accéderons à la liste des commentaires du billet.
Pour créer un lien dans une liste vers un autre module, nous devons utiliser un partial.
Dans back/modules/blog/config/generator.yml, nous remplaçons le champ number_of_comments par _list_number_of_comments (generator > param >list > display) et lui affectons un nom dans la section fields :
list_number_of_comments: { name: Nb Comment. }
Nous créons le partial back/modules/blog/templates/_list_number_of_comments.php avec le code suivant :
<?php
if ($blog_post->getNumberOfComments()>0)
echo link_to($blog_post->getNumberOfComments(), 'blogcomment/list', array('query_string' => 'filter=Filtrer&filters[blog_post_id]='.$blog_post->getId()));
else
echo '0';
?>
Le 3e paramètre de link_to() est un tableau de paramètres. Nous indiquons à l'aide de query_string que l'url comportera un query string avec les options qui suivents.
Ici, notre url sera http://grunzig/back_dev.php/blogcomment/list?filter=Filtrer&filters[blog_post_id]=1
En suivant le lien, on s'aperçoit que la liste des commentaires n'est pas filtré. Il faut activer le filtre dans back/modules/blogcomment/config/generator.yml. En même temps, précisons les champs à afficher. Le fichier devrait ressembler à celui-ci :
generator:
class: sfPropelAdminGenerator
param:
model_class: BlogComment
theme: default
fields:
blog_post_title: { name: Billet }
author_name: { name: Auteur }
author_email: { name: Mail }
author_site: { name: Site web }
created_at: { name: Créé le, params: date_format='dd/MM/yyyy H:mm' }
body: { name: Message }
list:
filters: [blog_post_id]
display: [created_at, author_name, author_email, author_site, body]
layout: stacked
params: |
le <strong>%%created_at%%</strong> par <strong>%%author_name%%</strong> <em>(%%author_email%% - %%author_site%%)</em>
<p>%%=body%%</p>
object_actions:
_edit: ~
_delete: ~
Nous obtenons alors :

Afin de masquer le formulaire de filtre, nous créons un partial (back/modules/blogcomment/templates/_filters.php) et nous le laissons vide. (Note: il existe peut être un autre moyen que je ne connais pas encore). Ce partial sera utilisé à la place de _filters.php créé par l'admin-generator (disponible dans monprojet/cache/back/dev/modules/autoBlogcomment/templates/).
Pour l'édition d'un commentaire, nous allons dans un premier temps afficher le titre du billet à la place de son identifiant.
Dans back/modules/blogcomment/config/generator.yml, nous ajoutons :
edit:
title: Détail du billet "%%blog_post_title%%"
display: [blog_post_title, author_name, author_email, author_site, created_at, body]
fields:
blog_post_title:{ type: plain }
body: { params: size=75x15 }
Mais le champ blog_post_title n'existe pas ! et il n'existera pas réellement. Nous pouvons récupérer le titre sans créer un nouveau champ.
Nous ajoutons la méthode suivante à la classe BlogComment (lib/model/BlogComment.php) :
public function getBlogPostTitle()
{
return BlogPostPeer::retrieveByPK($this->blog_post_id);
}
et celle-ci dans BlogPost (lib/model/BlogPost.php) :
public function __toString()
{
return $this->getTitle();
}
Ainsi, lors de l'affichage de blog_post_title, symfony utilise la méthode getBlogPostTitle() qui renvoie le titre du billet (et non pas un objet BlogPost) grâce à la méthode __toString() de BlogPost.
Lors de l'édition d'un billet, il serait appréciable de pouvoir accéder à la liste des commentaires associés. Nous allons nous en occuper. Je tiens tout de même à préciser que la présentation finale laisse à désirer et nécessiterait d'être refaite (CSS et HTML).
Ajoutons un partial pour BlogPost (back/modules/blogpost/templates/_edit_header.php) :
<ul class="navigation">
<li>
<?php echo link_to('Détail', $sf_request->getUri()); ?>
</li>
<li> | </li>
<li>
<?php
if ($blog_post->getNumberOfComments()>0)
echo link_to('Commentaires ('.$blog_post->getNumberOfComments().')', 'blogcomment/list', array('query_string' => 'filter=Filtrer&filters[blog_post_id]='.$blog_post->getId()));
else
echo 'Commentaires (0)';
?>
</li>
</ul>
Grâce à cela, lors de l'édition d'un billet, nous obtenons 2 liens avant le formulaire : un pour accéder à l'édition du billet et un pour accéder à la liste des commentaires.
Nous créons un 2e partial pour obtenir ce menu à partir de la liste des commentaires du billet (back/modules/blogcomment/templates/_list_header.php):
<?php $bpId = $sf_request->getParameter('filters[blog_post_id]') ?>
<ul class="navigation">
<li>
<?php echo link_to('Détail', 'blogpost/edit?id='.$bpId); ?>
</li>
<li> | </li>
<li>
<?php
echo link_to('Commentaires ('.BlogPostPeer::getNumberOfCommentsByPK($bpId).')', 'blogcomment/list', array('query_string' => 'filter=Filtrer&filters[blog_post_id]='.$bpId));
?>
</li>
</ul>
et un 3 pour l'édition d'un commentaire (back/modules/blogcomment/templates/_edit_header.php) :
<ul class="navigation">
<li>
<?php echo link_to('Détail', 'blogpost/edit?id='.$blog_comment->getBlogPostId()); ?>
</li>
<li> | </li>
<li>
<?php
echo link_to('Commentaires ('.$blog_comment->getBlogPost()->getNumberOfComments().')', 'blogcomment/list', array('query_string' => 'filter=Filtrer&filters[blog_post_id]='.$blog_comment->getBlogPostId()));
?>
</li>
</ul>
et nous ajoutons à la classe BlogPostPeer :
public static function getNumberOfCommentsByPK($pk)
{
$bp = BlogPostPeer::retrieveByPK($pk);
return $bp->getNumberOfComments();
}
Note: je pense qu'il serait possible de faire la même chose avec un slot.
A suivre... l'ajout d'un système de tags (tags pour les billetq + TagCloud).














































