I’m currently wrapping up a fairly large Zend Framework-driven project that mines data from the Amazon Product Advertising API. According to the API license agreement, this data can be cached for a period of up to 24 hours. Therefore, I’ve created several database tables to store the data, and I employ a number of CRON-driven scripts to rebuild the data store once daily.
However, because the product data will not change during that 24-hour period, it doesn’t make sense to repeatedly execute the fairly complex JOIN queries and looping statements required to retrieve and format the data. Instead, I used the Zend_Cache component to cache this data, expiring the cache just ahead of the daily update. In this article I’ll show you how to use Zend_Cache to cache your own data, considerably boosting your website performance in the process.
Configuring Zend_Cache
Zend_Cache can be configured to cache several types of output, including the results of function calls, the results of object and static method calls, entire pages, and configuration data. You determine what data is cached using Zend_Cache’s frontend. This data can be cached in several ways, including using system memory (RAM), using memcached, within text files, or within a SQLite database. You determine exactly how your data is cached using Zend_Cache’s backend.
The Zend_Cache frontend and backend are each configured separately, using a variety of configuration options that you can review by clicking on the aforementioned links, respectively. One of the most important frontend configuration options is the cache lifetime, defined in seconds with a default of 3,600 (one hour). I wanted the data to be cached for 24 hours and 10 minutes (allowing an additional five minutes for the API update to take place, just to be safe). So I configured my Zend_Cache frontend like this:
$frontendOptions = array( 'lifetime' => 1450, 'caching' => true, 'automatic_serialization' => true );
The
caching
option determines whether caching is enabled. Although not required (it is set to true
by default), I include the option in order to easily disable caching during the development phase. The automatic_serialization
option must be set to true if you plan on caching data that isn’t a string, such as an array or object. I’ve set this to true
because I’m caching arrays of objects.I’m using text files to cache the data, and so configure my Zend_Cache backend like this:
$backendOptions = array( 'cache_dir' => '/var/www/beta.example.com/cache/' );
Make sure your Web server possesses the necessary permissions to write to/read from the designated cache directory.
Of course, in my actual application I retrieve these configuration values from the application’s
application.ini
file in order to ensure maximum flexibility when migrating the site from the development server to the production server. See my earlier article, Introducing the Zend Framework’s Application Configuration Component, for more information about this powerful Zend Framework feature.Caching Database Results
With the frontend and backend caching configured, you can then declare the types of frontend and backend caches you want to use and begin caching your data. You complete the first task by creating a new Zend_Cache object using its factory method and then passing in the frontend and backend cache types and the respective configuration options:
$cache = Zend_Cache::factory( 'Core', 'File', $frontendOptions, $backendOptions );
Caching works by assigning a unique token to each cached result. You can then use Zend_Cache methods to refer to this token and determine whether it’s expired. Therefore, when using Zend_Cache you’ll first attempt to load the cached data using the
load()
method, which will return the cached data if it hasn’t yet expired, or false
if it has expired. If the cached data has expired, you’ll execute whatever mechanism is necessary to rebuild the data, subsequently caching it anew. Keeping this sequence of events in mind, the typical database query result caching process looks like this:$frontendOptions = array( 'lifetime' => 1450, 'caching' => true, 'automatic_serialization' => true );
$backendOptions = array( 'cache_dir' => '/var/www/beta.example.com/cache/' );
$cache = Zend_Cache::factory( 'Core', 'File', $frontendOptions, $backendOptions );
if ( ($gamesPaginator = $cache->load('games')) === false) {
$gamesPaginator = $platform->retrieveGames($currentPage, $resultsPerPage, $sort); $cache->save('games'); }
In this example, Zend_Cache looks to the cache directory for a cache file associated with the unique token
games
. If the file exists and has not expired, its contents will be retrieved, unserialized and assigned to the variable $gamesPaginator
. Otherwise, my $platform
model will retrieve a paginated list of the video games associated with it. That retrieved list is saved to the cache using the games
token.