Using Zend_Cache with Zend_Feed
Tuesday, August 31, 2010

I have described how to use Zend_Feed to retrieve a digest of a blog’s latest entries in a previous post. In the overall implementation described in my series of posts, this digest is fetched every time a page is loaded. Although, by using AJAX techniques, this does not slow the loading of the basic page, it does result in some unnecessary repetitive work, since the blogs are not updated that often. In this post, I shall look at how I am using caching on the recently revamped GM-RAM website to save the results and reuse them.

Here is the basic skeleton of the new feed controller:

class FeedController extends Zend_Controller_Action
{
  public function digestAction()
  {
    // TODO: Insert digest action handling code here
  }
 
  // TODO: Insert any additional member functions here
}

The controller contains one action handler, for the digest action.

The implementation of the action handler starts by disabling the standard layout, as it is an AJAX request:

    $this->_helper->layout->disableLayout();

It then tries to get the blog ID. If it cannot, it reports an error; if it can, it then tries to fetch the digest for the log.

    // Get the blog ID
    $id = $this->getRequest()->getParam('id');
 
    if (isset($id))
    {
      try
      {
        // TODO: Insert code to fetch blog digest and pass it to the view here
      }
      catch (Exception $e)
      {
        // Log the error
        $log = $this->getInvokeArg('bootstrap')->getResource('log');
        $log->err('Error retrieving feed - ' . $e->getMessage());
 
        // Report the error
        $this->view->errorMessage = 'Error retrieving feed';
      }
    }
    else
    {
      $this->view->errorMessage = 'Blog ID not specified';
    }

Note that the process of fetching the digest is wrapped in a try/catch block to handle any errors; these are logged in detail.

Now we go through a two stage process:

  1. First we check whether the digest for the specified blog ID is in the cache; if it is, we use that
  2. However, if it it not, we retrieve the feed URL from the database, then fetch the digest from the feed

In both cases, either the digest is passed to the view script, or an error message, should an error occur.

The implementation of this is given below.

        // See if we can get the feed info from the cache
        $cache = $this->_getCache();
 
        if (!$this->view->digest = $cache->load('feed_' . $id))
        {
          // Get the blog information from the database
          $dbTableBlog = new Application_Model_DbTable_Blog();
          $select = $dbTableBlog->select()->where('id = ?', $id);
          $row = $dbTableBlog->fetchRow($select);
 
          if (isset($row))
          {
            // Get the blog digest from the feed and cache it
            $this->view->digest = $this->view->feedDigest($row['feed']);
            $cache->save($this->view->digest, 'feed_' . $id);
          }
          else
          {
            $this->view->errorMessage = 'Blog ID not found in database';
          }
        }

The cache object is created by a call to the following private member function of the controller’s class:

  private function _getCache()
  {
    // Set the cache frontend and backend options
    $frontendOptions = array(
      'lifetime' => 7200, // Cache lifetime of 2 hours
      'automatic_serialization' => true
    );
 
    $backendOptions = array(
      'cache_dir' => APPLICATION_PATH . '/cache/' 
        // Directory where to put the cache files
    );
 
    // Get a Zend_Cache_Core object
    $cache = Zend_Cache::factory('Core', 'File', 
      $frontendOptions, $backendOptions);
 
    return $cache;
  }

Note that we need to configure a front end and back end for the cache. The former is concerned with things like the lifetime of the cache, the latter with where the cached data is stored.

The view script is as follows:

<?php
if (isset($this->errorMessage))
{
  if (APPLICATION_ENV == 'development')
  {
    printf('<p class="error">%s</p>', $this->errorMessage);
  }
  else
  {
    echo '<p>No posts found</p>' . PHP_EOL;
  }
}
else
{
  if (strlen($this->digest) > 0)
  {
    echo $this->digest . PHP_EOL;
  }
  else
  {
    echo '<p>No posts found</p>' . PHP_EOL;
  }
}

Note that the script is set to render a more descriptive error message in development mode, to assist with debugging. Otherwise, the script should be self-explanatory.

Posted by James at 6:58 pm   1 comment

One Response to “Using Zend_Cache with Zend_Feed”

Leave a Reply