6 min read

CakePHP 1.3 Application Development Cookbook

CakePHP 1.3 Application Development Cookbook

Over 70 great recipes for developing, maintaining, and deploying web applications    

Creating an RSS feed

RSS feeds are a form of web services, as they provide a service, over the web, using a known format to expose data. Due to their simplicity, they are a great way to introduce us to the world of web services, particularly as CakePHP offers a built in method to create them.

In this recipe, we will produce a feed for our site that can be used by other applications.

Getting ready

To go through this recipe we need a sample table to work with. Create a table named posts, using the following SQL statement:

CREATE TABLE `posts`(posts
`id` INT NOT NULL AUTO_INCREMENT,
`title` VARCHAR(255) NOT NULL,
`body` TEXT NOT NULL,
`created` DATETIME NOT NULL,
`modified` DATETIME NOT NULL,
PRIMARY KEY(`id`)
);


Add some sample data, using the following SQL statements:

INSERT INTO `posts`(`title`,posts `body`, `created`, `modified`)
VALUES
(‘Understanding Containable’, ‘Post body’, NOW(), NOW()),
(‘Creating your first test case’, ‘Post body’, NOW(), NOW()),
(‘Using bake to start an application’, ‘Post body’, NOW(), NOW()),
(‘Creating your first helper’, ‘Post body’, NOW(), NOW()),
(‘Adding indexes’, ‘Post body’, NOW(), NOW());


We proceed now to create the required controller. Create the class PostsController in a file named posts_controller.php and place it in your app/controllers folder, with the following contents:

<?php
class PostsController extends AppController {
public function index() {
$posts = $this->Post->find(‘all’);
$this->set(compact(‘posts’));
}
}
?>


Create a folder named posts in your app/views folder, and then create the index view in a file named index.ctp and place it in your app/views/posts folder, with the following contents:

<h1>Posts</h1>
<?php if (!empty($posts)) { ?>
<ul>
<?php foreach($posts as $post) { ?>
<li><?php echo $this->Html->link(
$post[‘Post’][‘title’],
array(
‘action’=>’view’,
$post[‘Post’][‘id’]
)
); ?></li>
<?php } ?>
</ul>
<?php } ?>


How to do it…

  1. Edit your app/config/routes.php file and add the following statement at the end:
    Router::parseExtensions('rss');
  2. Edit your app/controllers/posts_controller.php file and add the following property to the PostsController class:
    public $components = array('RequestHandler');
  3. While still editing PostsController, make the following changes to the index() method:

    public function index() {
    $options = array();
    if ($this->RequestHandler->isRss()) {
    $options = array_merge($options, array(
    ‘order’ => array(‘Post.created’ => ‘desc’),
    ‘limit’ => 5
    ));
    }
    $posts = $this->Post->find(‘all’, $options);
    $this->set(compact(‘posts’));
    }

    
    
  4. Create a folder named rss in your app/views/posts folder, and inside the rss folder create a file named index.ctp, with the following contents:

    <?php
    $this->set(‘channel’, array(
    ‘title’ => ‘Recent posts’,
    ‘link’ => $this->Rss->url(‘/’, true),
    ‘description’ => ‘Latest posts in my site’
    ));

    $items = array();
    foreach($posts as $post) {
    $items[] = array(
    ‘title’ => $post[‘Post’][‘title’],
    ‘link’ => array(‘action’=>’view’, $post[‘Post’][‘id’]),
    ‘description’ => array(‘cdata’=>true, ‘value’=>$post[‘Post’]
    [‘body’]),
    ‘pubDate’ => $post[‘Post’][‘created’]
    );
    }

    echo $this->Rss->items($items);
    ?>

    
    
  5. Edit your app/views/posts/index.ctp file and add the following at the end of the view:

    <?php echo $this->Html->link(‘Feed’, array(‘action’=>’index’,
    ‘ext’=>’rss’)); ?>

    
    

If you now browse to http://localhost/posts, you should see a listing of posts with a link entitled Feed. Clicking on this link should produce a valid RSS feed, as shown in the following screenshot:

CakePHP 1.3 Application Development Cookbook

If you view the source of the generated response, you can see that the source for the first item within the RSS document is:

<item>
<title>Understanding Containable</title>
<link>http://rss.cookbook7.kramer/posts/view/1</link>
<description><![CDATA[Post body]]></description>
<pubDate>Fri, 20 Aug 2010 18:55:47 -0300</pubDate>
<guid>http://rss.cookbook7.kramer/posts/view/1</guid>
</item>


How it works…

We started by telling CakePHP that our application accepts the rss extension with a call to Router::parseExtensions(), a method that accepts any number of extensions. Using extensions, we can create different versions of the same view. For example, if we wanted to accept both rss and xml as extensions, we would do:

Router::parseExtensions(‘rss’, ‘xml’);


In our recipe, we added rss to the list of valid extensions. That way, if an action is accessed using that extension, for example, by using the URL http://localhost/posts.rss, then CakePHP will identify rss as a valid extension, and will execute the ArticlesController::index() action as it normally would, but using the app/views/posts/rss/index.ctp file to render the view. The process also uses the file app/views/layouts/rss/default.ctp as its layout, or CakePHP’s default RSS layout if that file is not present.

We then modify how ArticlesController::index() builds the list of posts, and use the RequestHandler component to see if the current request uses the rss extension. If so, we use that knowledge to change the number and order of posts.

In the app/views/posts/rss/index.ctp view, we start by setting some view variables. Because a controller view is always rendered before the layout, we can add or change view variables from the view file, and have them available in the layout. CakePHP’s default RSS layout uses a $channel view variable to describe the RSS feed. Using that variable, we set our feed’s title, link, and description.

We proceed to output the actual item files. There are different ways to do so, the first one is making a call to the RssHelper::item() method for each item, and the other one requires only a call to RssHelper::items(), passing it an array of items. We chose the latter method due to its simplicity.

While we build the array of items to be included in the feed, we only specify title, link, description, and pubDate. Looking at the generated XML source for the item, we can infer that the RssHelper used our value for the link element as the value for the guid (globally unique identifier) element.

Note that the description field is specified slightly differently than the values for the other fields in our item array. This is because our description may contain HTML code, so we want to make sure that the generated document is still a valid XML document.

By using the array notation for the description field, a notation that uses the value index to specify the actual value on the field, and by setting cdata to true, we are telling the RssHelper (actually the XmlHelper from which RssHelper descends) that the field should be wrapped in a section that should not be parsed as part of the XML document, denoted between a <![CDATA[ prefix and a ]]> postfix.

The final task in this recipe is adding a link to our feed that is shown in the index.ctp view file. While creating this link, we set the special ext URL setting to rss. This sets the extension for the generated link, which ends up being http://localhost/posts.rss.

 

LEAVE A REPLY

Please enter your comment!
Please enter your name here