Previously on symfony
The askeet application is ready to be launched in a (early) beta stage. As a matter of fact, it could already seduce lots of users since the core features (ask questions, read answers, contribute new answers) are built. The trouble is that recurrent users will find it difficult to keep up-to-date with the latest events on the askeet website. You need to provide them with fresh news without effort, and there is a media for that: news feed. So let's add news feed to askeet today.
Popular questions feed
Link to the feed in the head
What we want is an RSS popular questions feed inserted in the <head>
of the global layout. The resulting HTML should look like:
<link rel="alternate" type="application/rss+xml" title="Popular questions on askeet" href="http://askeet/frontend_dev.php/feed/popular" />
To do this, open the layout.php
and add in the <head>
:
<?php echo auto_discovery_link_tag('rss', 'feed/popular') ?>
That's all. The auto_discovery_link_tag
helper (autoloaded with the AssetHelper.php
helper library) transforms the module/action
into a site URI, passing by the routing engine.
Install the plug-in
Symfony provides a sfFeed
plug-in that automates most of the feed generation. To install it, you will use the symfony command line.
$ symfony plugin-install http://plugins.symfony-project.com/sfFeedPlugin $ symfony clear-cache
This installs the classes of the plug-in in the askeet/lib/symfony/plugins/
directory.
If you want to learn more about plug-ins, how they extend the framework and how you can package the features that you use across several projects into a plug-in, read the plug-in chapter of the symfony book.
Don't forget to clear the cache since the project lib/
folder was modified because of the plugin. By the way, if you experiment problems with the plugin-install
command, it's probably because you don't have PEAR installed.
We will talk about this sfFeed
class later. But first, we need to write a few lines of code.
Create the action
The feed points to a popular
action of the feed
action. To create it, type:
$ symfony init-module frontend feed
Then edit the askeet/apps/frontend/modules/feed/actions/action.class.php
and add in the following method:
public function executePopular() { // questions $c = new Criteria(); $c->addDescendingOrderByColumn(QuestionPeer::INTERESTED_USERS); $c->setLimit(sfConfig::get('app_feed_max')); $questions = QuestionPeer::doSelectJoinUser($c); $feed = sfFeed::newInstance('rss201rev2'); // channel $feed->setTitle('Popular questions on askeet'); $feed->setLink('@homepage'); $feed->setDescription('A list of the most popular questions asked on the askeet site, rated by the community.'); // items $feed->setFeedItemsRouteName('@question'); $feed->setItems($questions); $this->feed = $feed; }
Define the app_feed_max_question
custom parameter in your askeet/apps/frontend/config/app.yml
configuration file:
all: feed: max: 10
Change the view configuration
By default, the result of our feed/popular
action will be decorated by the layout, and will have a text/html
content-type. That's not what we want. So create a view.yml
in the askeet/apps/frontend/modules/feed/config/
directory containing:
all: has_layout: off template: feed
This deactivates the decorator and forces the output template to feedSuccess.php
, whatever the action.
Write the template
That's because the template is very simple and can be reused for other feeds. Just write this simple askeet/apps/frontend/modules/feed/templates/feedSuccess.php
template:
<?php echo $feed->getFeed() ?>
Test it
Now clear the cache (because the configuration has changed), refresh any page of the site, and notice the feed icon of your favorite web browser. Check the feed by requesting manually:
http://askeet/feed/popular
The result is:
<?xml version="1.0" encoding="UTF-8" ?> <rss version="2.0"> <channel> <title>Popular questions on askeet</title> <link>http://askeet/frontend_dev.php/</link> <description>A list of the most popular questions asked on the askeet site, rated by the community.</description> <language>en</language> <item> <title>What can I offer to my step mother?</title> <description>My stepmother has everything a stepmother is usually offered (watch, vacuum cleaner, earrings, [del.icio.us](http://del.icio.us) account). Her birthday comes next week, I am broke, and I know that if I don't offer her something *sweet*, my girlfriend won't look at me in the eyes for another month.</description> <link>http://askeet/frontend_dev.php/question/what-can-i-offer-to-my-step-mother</link> <guid>11</guid> <pubDate>Sat, 10 Dec 2005 09:44:11 +0100</pubDate> </item> <item> <title>What shall I do tonight with my girlfriend?</title> <description>We shall meet in front of the __Dunkin'Donuts__ before dinner, and I haven't the slightest idea of what I can do with her. She's not interested in _programming_, _space opera movies_ nor _insects_. She's kinda cute, so I __really__ need to find something that will keep her to my side for another evening.</description> <link>http://askeet/frontend_dev.php/question/what-shall-i-do-tonight-with-my-girlfriend</link> <guid>10</guid> <author>fp@example.com (Fabien Potencier)</author> <pubDate>Sat, 10 Dec 2005 09:44:11 +0100</pubDate> </item> <item> <title>How can I generate traffic to my blog?</title> <description>I have a very swell blog that talks about my class and mates and pets and favorite movies.</description> <link>http://askeet/frontend_dev.php/question/how-can-i-generate-traffic-to-my-blog</link> <guid>12</guid> <author>fz@example.com (François Zaninotto)</author> <pubDate>Sat, 10 Dec 2005 09:44:12 +0100</pubDate> </item> </channel> </rss>
That fast?
The magic
Now you might say: how did symfony know where to find the question's author, his/her email, and how did symfony guess about the URI to a question detail? The answer is: That's magic.
If you don't believe in magic, then come beyond the curtain and meet the sfFeed
class. This class is able to interpret the names of the methods of the object that is passed as a parameter to its ->setItems()
methods. The Question
object has a ->getUser()
method, so it is used to find the author of a question. The User
object has a ->getEmail()
method, so this one is also used to determine the author's email. And the rule name passed to the ->setFeedItemsRouteName()
method is:
question: url: /question/:stripped_title param: { module: question, action: show }
It contains a stripped_title
parameter, so the ->getStrippedTitle()
method of the Question
object is called to determine the question URI.
All that happens because the getter method names make sense - and the sfFeed
class understands objects designed that way. The inference mechanisms of this class are described in detail in the feed chapter of the symfony book - refer to it to see how to ask, for instance, a feed without email addresses even if a ->getEmail()
method exists for the object's author.
note
The view of the feed has a XML content-type, so symfony will be smart enough not to add the web debug toolbar to it (otherwise the XML would'nt be valid anymore). If you ever need to disable the web debug toolbar manually, you can always call:
sfConfig::set('sf_web_debug', false);
(find more about the web debug toolbar in the debug chapter of the symfony book).
Interface improvements
Routing
The URL of a feed is as important as a regular one, so append the following to the routing.yml
:
# feeds feed_popular_questions: url: /feed/popular param: { module: feed, action: popular }
RSS image
Whenever a link to a list had a corresponding field, a nice RSS icon is displayed, together with a link to the RSS. As this will happen quite a few times, create a link_to_feed()
function in the GlobalHelper.php
:
function link_to_feed($name, $uri) { return link_to(image_tag('feed.gif', array('alt' => $name, 'title' => $name, 'align' => 'absmiddle')), $uri); }
You will find the feed.gif
image in the SVN repository.
Now, edit the modules/sidebar/templates/defaultSuccess.php
as follows:
<li><?php echo link_to('popular questions', '@popular_questions') ?> <?php echo link_to_feed('popular questions', '@feed_popular_questions') ?></li>
See you Tomorrow
This tutorial was supposed to last one hour, and only fifteen minutes passed. You are worried? Don't. That's another one of the lessons of agile programming: If you find a very simple solution to your problem, it is probably the right one. There is no need to pass too much time to develop a feature if it already works. And you now know that only fifteen minutes are necessary to setup, test and launch a RSS feed. After all, symfony offers professional web tools for lazy folks, so enjoy your free time and leave your computer for today.
If you want some more symfony stuff, try making a new feed for the latest questions, the latest answers in general, and the latest answers to a question in particular. It should not take you more than fifteen more minutes, so you will have time to download the full code from the askeet SVN repository, tagged release_day_11
, and check if you did it well. Beware that there is one hidden difficulty - pay attention to the routing rule used for the feed of the latest comments.
And if you still have a few minutes left, go to the askeet forum and express yourself.
Tomorrow, we will send emails with symfony, because we are sure that some of our users will forget their access codes. Until then, sleep tight.
This work is licensed under the Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Unported License license.