Aperçu général
Si votre application contient des messages, des images, des questions ou des listes, et que ces informations sont mises à jour plus d'une fois par mois, vous pouvez fournir un flux de syndication (RSS, Atom, etc.). Les utilisateurs peuvent ainsi lire les dernières mises à jour de votre site depuis un agrégateur externe.
Si votre modèle de données est construit correctement, quelques lignes de code suffisent pour mettre en place un flux grâce au plugin proposé par symfony.
Introduction
L'exemple décrit dans ce chapitre est un simple gestionnaire de blog, contenant une table Post
et Author
.
Post | Author |
---|---|
id | id |
author_id | first_name |
title | last_name |
description | |
body | |
created_at |
La classe Post
est enrichie d'une méthode getStrippedTitle()
qui retourne le titre correctement formaté pour une URI ( suppression des caractères spéciaux, remplacement des espaces par des underscores et conversion des majuscules en minuscules ).
public function getStrippedTitle() { $text = strtolower($this->getTitle()); // strip all non word chars $text = preg_replace('/\W/', ' ', $text); // replace all white space sections with a dash $text = preg_replace('/\ +/', '-', $text); // trim dashes $text = preg_replace('/\-$/', '', $text); $text = preg_replace('/^\-/', '', $text); return $text; }
La classe Author
est enrichie d'une méthode getName()
:
public function getName() { return $this->getFirstName().' '.$this->getLastName() }
Pour plus d'informations sur l'extension d'un modèle, référez-vous au Chapitre 8.
Le fichier routing.yml
contient la règle suivante:
post: url: /permalink/:stripped_title param: { module: post, action: read }
Pour plus d'information sur le système de routage, référez-vous au Chapitre 9.
On crée un module spécifique nommé feed
qui contiendra toutes les actions et les templates.
$ symfony init-module myapp feed
Résultats attendus
L'action feed
doit retourner un flux Atom. Voici un exemple décrivant les informations que doit contenir ce type de flux:
<?xml version="1.0" encoding="utf-8"?> <feed xmlns="http://www.w3.org/2005/Atom"> <title>The mouse blog</title> <link href="http://www.myblog.com/" /> <updated>2005-12-11T16:23:51Z</updated> <author> <name>Peter Clive</name> <author_email>pclive@myblog.com</author_email> </author> <id>4543D55FF756G734</id> <entry> <title>I love mice</title> <link href="http://www.myblog.com/permalink/i-love-mice" /> <id>i-love-mice</id> <author> <name>Peter Clive</name> <author_email>pclive@myblog.com</author_email> </author> <updated>2005-12-11T16:23:51Z</updated> <summary>Ever since I bought my first mouse, I can't live without one.</summary> </entry> <entry> <title>A mouse is better than a fish</title> <link href="http://www.myblog.com/permalink/a-mouse-is-better-than-a-fish" /> <id>a-mouse-is-better-than-a-fish</id> <author> <name>Bob Walter</name> <author_email>bwalter@myblog.com</author_email> </author> <updated>2005-12-09T09:11:42Z</updated> <summary>I had a fish for four years, and now I'm sick. They smell.</summary> </entry> </feed>
Installation du plug-in
Symfony fournit le plugin sfFeed
qui permet d'automatiser la génération de flux. Pour l'installer, tapez la ligne de commande suivante:
$ symfony plugin-install http://plugins.symfony-project.com/sfFeedPlugin
Les classes du plugin seront installé dans le répertoire plugins/
. Afin que symfony les charge automatiquement pendant l'exécution, le cache doit être vidé:
$ symfony cc
Pour plus d'informations sur les plugins, sur la manière dont elles étendent le framework et comment les réutiliser au sein d'autres projets, référez-vous au Chapitre 17 du livre.
Construction manuelle du flux
Dans le module feed
, créez une action lastPosts
:
public function executeLastPosts() { $feed = sfFeed::newInstance('atom1'); $feed->setTitle('The mouse blog'); $feed->setLink('http://www.myblog.com/'); $feed->setAuthorEmail('pclive@myblog.com'); $feed->setAuthorName('Peter Clive'); $c = new Criteria; $c->addDescendingOrderByColumn(PostPeer::CREATED_AT); $c->setLimit(5); $posts = PostPeer::doSelect($c); foreach ($posts as $post) { $item = new sfFeedItem(); $item->setFeedTitle($post->getTitle()); $item->setFeedLink('@permalink?stripped_title='.$post->getStrippedTitle()); $item->setFeedAuthorName($post->getAuthor()->getName()); $item->setFeedAuthorEmail($post->getAuthor()->getEmail()); $item->setFeedPubdate($post->getCreatedAt('U')); $item->setFeedUniqueId($post->getStrippedTitle()); $item->setFeedDescription($post->getDescription()); $feed->addItem($item); } $this->feed = $feed; }
La méthode construit une instance de la classe sfFeed
au format Atom
. Les classes complémentaires sfFeed
et sfFeedItem
se chargent de la construction du flux. À la fin de l'exécution de l’action, la variable $feed
contient une instance de ‘sfFeed’, qui contient elle-même plusieurs instances de sfFeedItem
.
Afin de transformer l'objet en flux Atom valide, le template lastPostsSuccess.php
contient simplement la ligne suivante:
<?php echo $feed->getFeed() ?>
Le template ne doit pas être décoré par un layout. De plus, le Content-type
de la page doit être déclaré en text/xml
dans le fichier view.yml
situé dans le répertoire config/
du module feed
:
all: has_layout: off http_metas: content-type: text/xml
Dans un agrégateur, le résultat de l'action correspond maintenant au flux Atom décrit ci-dessus:
http://www.myblog.com/feed/lastPosts
Utilisation d'un syntaxe plus courte
Vu le nombre important d'informations à définir pour un élément, l'utilisation des mutateurs peut vite devenir rébarbative. Symfony propose une syntaxe abrégée en utilisant un tableau associatif:
public function executeLastPosts() { $feed = sfFeed::newInstance('atom1'); $feed->setTitle('The mouse blog'); $feed->setLink('http://www.myblog.com/'); $feed->setAuthorEmail('pclive@myblog.com'); $feed->setAuthorName('Peter Clive'); $c = new Criteria; $c->addDescendingOrderByColumn(PostPeer::CREATED_AT); $c->setLimit(5); $posts = PostPeer::doSelect($c); foreach ($posts as $post) { $item = array( 'title' => $post->getTitle(), 'link' => '@permalink?stripped_title='.$post->getStrippedTitle(), 'authorName' => $post->getAuthor()->getName(), 'authorEmail' => $post->getAuthor()->getEmail(), 'pubdate' => $post->getCreatedAt(), 'uniqueId' => $post->getStrippedTitle(), 'description' => $post->getDescription(), ); $feed->addItemFromArray($item); } $this->feed = $feed; }
L'effet produit est exactement le même. La syntaxe, elle, est bien plus claire.
Laissez symfony travailler pour vous !
Les méthodes utilisées pour construire les champs étant toujours quasiment identiques, symfony peut produire le même résultat juste avec le code suivant:
public function executeLastPosts() { $feed = sfFeed::newInstance('atom1'); $feed->setTitle('The mouse blog'); $feed->setLink('http://www.myblog.com/'); $feed->setAuthorEmail('pclive@myblog.com'); $feed->setAuthorName('Peter Clive'); $c = new Criteria; $c->addDescendingOrderByColumn(PostPeer::CREATED_AT); $c->setLimit(5); $posts = PostPeer::doSelect($c); $feed->setFeedItemsRouteName('@permalink'); $feed->setItems($posts); $this->feed = $feed; }
Magique n'est-ce-pas ?
La magie de l'objet sfFeed
Les noms des accesseurs de l'objet Post
sont suffisamment explicites pour que symfony les comprenne. La classe sfFeed
contient des mécanismes internes pour extraire les informations pertinentes des classes bien structurées :
Pour définir le champs
titre
de l'élément, la classe essaye d'appeler une de ces méthodes :getFeedTitle()
,getTile()
,getName()
ou__toString()
.Dans cet exemple, l'objet
Post
a bien une méthodegetName()
.Pour définir le champs
link
, la classe cherche une route vers un element (définie par un appel desetFeedItemsRouteName()
). Si une route est présente, la classe cherche dans l'URL des paramètres pour lesquelles il existe des accesseurs. Si aucune route n'est définie, la classe cherche alors à appeler une de ces méthodes :getFeedLink()
,getLink()
ougetUrl()
.Dans cet exemple, une route est définie dans l'action (@permalink). Cette règle de routage contient un paramètre
:stripped_title
, et l'objetPost
a bien une méthodegetStripped_Title()
. L'objetsfFeed
sait donc définir l'URL du lien.Pour définir l'adresse email de l'auteur, la classe cherche a appeller la méthode
getFeedAuthorEmail
ougetAuthorEmail
. Si aucune de ces méthode n'est définie, elle essayegetAuthor()
,getUser()
ougetPerson()
. Si le résultat est un object, elle essaye d'appeler la méthodegetEmail
ougetMail
de cet objet.Dans cet exemple, l'objet
Post
a une méthodegetAuthor()
, et l'objetAuthor
a une méthodegetName()
. Le même genre de règle est utilisé pour le nom de l'auteur, ainsi que son URL.Pour définir la date de publication, la classe cherche à appeler une de ces méthodes :
getFeedPubDate()
,getPubDate()
,getCreatedAt()
ougetDate()
.Dans cet exemple, l'objet
Post
a une méthodegetCreatedAt()
Le principe est le même pour les autres champs possibles du flux (catégorie, résumé, identifiant etc...). Vous êtes fortement invité parcourir le code la classe "sfFeed" pour découvrir par vous même tout les mécanismes de déduction.
Les objets Post
et Author
, de part la construction de leur accesseurs, fournissent nativement les raccourcis nécéssaires à sfFeed
, rendant la création d'un flux si simple.
Definition personnalisée des valeurs du flux
Dans la liste ci-dessus, vous noterez que la première méthode que sfFeed
essaye d'appeler est toujours sous la forme ‘getFeedXXX()’. Cela vous permet de spécifier une valeur personnalisée pour chaque champ d'un élément en enrichissant simplement le modèle.
Par exemple, si vous ne voulez pas que l'adresse email de l'auteur soit publiée dans le flux, ajoutez simplement une méthode getFeedAuthorEmail()
dans l'objet Post
:
public function getFeedAuthorEmail() { return ''; }
Cette méthode sera trouvé et utilisé avant getAuthor()
, et le flux n'affichera pas les adresses des rédacteurs.
Utilisation d'autres formats
Les méthodes décrites ci-dessous peuvent être transposé à d'autres types de flux RSS. Changez simplement le paramètre de la fabrique de flux:
// RSS 0.91 $feed = sfFeed::newInstance('rssUserland091'); // RSS 2.01 $feed = sfFeed::newInstance('rss201rev2');
This work is licensed under the Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Unported License license.