Générer un flux RSS avec CakePHP

Proposer un flux RSS est devenu une fonctionnalité incontournable sur la plupart des sites, et CakePHP simplifie grandement le processus de création de flux.

Partons d’un blog publiant des articles. Nous souhaitons créer un flux des articles récents, à la norme RSS version 2.0 et disponible via l’URL suivante : /articles/flux.rss.

1. Prise en compte de l’extension .rss dans le Router

Nous commençons par configurer le Router pour qu’il reconnaisse l’extension .rss. Nous ajoutons la route suivante dans le fichier {app}/config/routes.php :

1
2
// {app}/config/routes.php
Router::parseExtensions('rss');

Ainsi, CakePHP reconnaîtra les URL terminant par ‘.rss’ et appellera la bonne action.

2. Le Contrôleur

Nous allons maintenant créer l’action flux dans le Contrôleur des articles. Cette action récupère simplement la liste des 10 articles les plus récents classés par ordre de date de création décroissante.

Mise à jour du 12/04/08 : nous devons également configurer les informations générales qui seront affichées dans l’entête du flux (titre, description, langue, email du webmaster, etc.). Merci à foxmask qui a décelé que la déclaration de ces informations dans la Vue plutôt que dans le Contrôleur déclenchait la duplication de la balise <description>.

Pour en savoir plus sur les balises disponibles dans la norme RSS, nous renvoyons le lecteur vers cet article complet et clair : Spécifications du format RSS.

Nous commençons par inclure le composant RequestHandler, qui en complément de la configuration du Router vue plus haut, va permettre d’appeler l’action flux lorsque l’url /articles/flux.rss est demandée. C’est ce composant qui va changer automatiquement le layout par défaut pour permettre la sortie du flux au format défini par l’extension requise (rss, xml, etc.).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// {app}/controllers/articles_controller.php
class ArticlesController extends AppController
{
	var $components = array('RequestHandler');
 
	function flux()
	{
		$articles = $this->Article->find(
			'all',
			array(
				'order' => 'created DESC',
				'limit' => 10
			)
		);
		$channel = array(
			'title' => utf8_encode("Mon flux RSS"),
			'description' => utf8_encode("Les derniers articles"),
			'language' => 'fr',
			'webMaster' => 'contact@monsite.com'
		);
 
		$this->set(compact('articles', 'channel'));
	}
}

3. La Vue

Nous créons un nouveau fichier {app}/views/articles/rss/flux.ctp (notez le sous-répertoire rss dans le répertoire articles) :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// {app}/views/articles/rss/flux.ctp
<?php
e($rss->items($articles, 'sortieRSS'));
 
function sortieRSS($article)
{
  return array(
    'title' => utf8_encode($article['Article']['titre']),
    'link'  => 'http://www.monsite.com/articles/view/'.$article['Article']['id'],
    'description' => utf8_encode($article['Article']['description']),
    'pubDate' => $article['Article']['created']
  );
}
?>

Quelques explications :

3
e($rss->items($articles, 'sortieRSS'));

CakePHP a créé automatiquement un objet $rss, duquel nous appelons la méthode items(). Cette dernière prend en premier paramètre un tableau de données, ici les 10 articles trouvés dans l’action flux, et en deuxième paramètre le nom d’une fonction que nous construisons juste après, sortieRSS, qui sera appliquée sur chaque élément du tableau $articles.

5
6
7
8
9
10
11
12
13
function sortieRSS($article)
{
  return array(
    'title' => utf8_encode($article['Article']['titre']),
    'link'  => 'http://www.monsite.com/articles/view/'.$article['Article']['id'],
    'description' => utf8_encode($article['Article']['description']),
    'pubDate' => $article['Article']['created']
);
}

Le rôle de cette fonction est de formater les données passées en paramètre avec les balises à la norme RSS.

Nous utilisons la fonction PHP utf8_encode pour rendre les caractères accentués lisibles par tous les agrégateurs de flux.

4. Liens vers le flux RSS

4.1 Dans l’entête HTML

La plupart des navigateurs récents peuvent détecter la présence d’un lien vers un flux RSS dans l’entête HTML d’une page et affichent une petite icône orange à droite de la barre d’adresse (comme nous le voyons sur ce site même). Nous établissons ce lien particulier dans notre layout général, quelque part entre les balises <head>...</head> :

1
2
// {app}/views/layouts/default.ctp
e($html->meta('rss', array('controller' => 'articles', 'action' => 'flux.rss'), array('title' => "Les derniers articles")));

4.2 Dans un lien classique

N’importe quel autre lien vers le flux se fera de la façon suivante :

e($html->link("Flux RSS des articles récents", array('controller' => 'articles', 'action' => 'flux.rss')));

Pierre-Emmanuel Fringant

Commentaires

Article très sympa !

Il faut penser à faire un petit Configure::write(’debug’, 0); sinon l’affichage n’est pas correct en mode hors-production.

J’ai néenmoins un petit soucis : lorsque j’accède à mon flux, firefox me propose de le télécharger au lieu de l’afficher. Les données à l’intérieur sont correctes. Je suppose que c’est un problème de type mime ! Mais mêmeen faisant echo $rss->header(); dans la vue, ca ne fonctionne pas …

une idée ?

merci !

Que contient le fichier que Firefox te propose de télécharger ? A première vue je penserai à un problème de layout, celui par défaut étant utilisé à la place du layout xml.
As-tu bien ajouté Router::parseExtensions('rss'); dans les routes ?
As-tu bien inclu le composant RequestHandler dans ton Contrôleur ?

Le fichier téléchargé contient le flux correctement formaté :

Neveldo : Flux RSSLes derniers articlesfrcontact@neveldo.frhttp://localhost/blog/…

J’ai bien rajouté l’extension RSS dans les routes et le composant RequestHandler dans le contrôleur.

Je vais voir du côté de la configuration de WAMP5 et tester avec un flux écrit en dur et je te tiens au courant.

Merci !

Ok problème résolu. Cela venait d’un caractère espace qui s’était glissé après la balise ?> dans l’appController ! Il s’est retrouvé en début de fichier , avant la balise (et sur toutes les autres pages).

Par contre, comment fait-on pour accéder à une méthode d’un helper à l’intérieur de la fonction outputRSS() ?

En faisant directement un $html->XXX(), il ne trouve pas l’objet et renvoie un flux vide … Même résultat en ajoutant un “global $html;”.

Une idée ?

merci !

Je suppose que tu voudrais utiliser les fonctions $html->link() ou $html->url()…
Si tu passes un array à ‘link’, Cake se charge de le passer dans Router::url(), inutile d’appeler une méthode du Helper Html.
Exemple :
function sortieRSS($article)
{
return array(
'title' => ...,
'link' => array('controller' => 'articles', 'action' => 'view', $article['Article']['id']),

);
}

Merci pour ta réponse ! En effet, pour les liens je les bidouillais grâce aux variables globales de Cake, ta solution est bien plus propre :)

Par contre, j’ai bien un helper que j’ai fait et qui contient une fonction permettant de raccourcir mes posts en fonction d’une balise html bien spécifique. Ceci afin de peupler le champ description. Et donc, dans ce cas, impossible d’accéder à cette méthode du helper à l’intérieur de la méthode (de la même façon, impossible d’accéder aux helpers intégrés à cake).

Tu ne peux pas appeler une fonction de Helper dans la fonction de callback. Par contre rien ne t’empêche d’effectuer un traitement préalable sur tes données dans la vue avant de les passer à la fonction $rss->items().

Exemple en coupant les textes trop long avec le Helper Text :
// {app}/views/articles/rss/flux.ctp
foreach($articles as $key => $article)
{
$articles[$key]['Article']['description'] = $text->truncate($article['Article']['description']);
}

e($rss->items($articles, ’sortieRSS’));

Ok merci !

Je pensais qu’il était possible de le faire directement dans la fonction de callback :p

merci pour l’info !

Participez