Making a TAG Cloud out of Zend_Cache

If you're new here, you may want to subscribe to my RSS feed. Thanks for visiting!

As some of you may or may not know I have been working on a large project based upon the Zend Framework. I have in a previous post posted a few screenshots of a couple of the tools I have written to administer some of the frameworks abilities. Today I thought I would release a small section of one of them that may be of use.

Zend_Cache is a caching mechanism that either lets you cache chunks of output or chunks of data. Both concepts are easy to implement within your code and given time they become second nature to use. And because they are simple to implement you find yourself using them anywhere and everywhere.

To give you an example I have a large category tree which has a number of items under each category. To display a single level of navigation (say from the root) I have to first grab all the children then for each child count how many items are under it (not fast).

Although the data is live and the number of items under each category may very well change over the course of 30 minutes it still means it is worth caching as that page may well be requested several thousand times in the course of that 30 minutes. The following code example shows a simple use of Zend_Cache.

$cache = Zend_Registry::get('cache');
if(!$children = $cache->load('cache_children_'.$category))) {
 ....{CHILDREN BUILDING CODE WENT HERE}...
 $cache->save($children,'cache_children_'.$category,array('category','frontend'));
}

First you have to make a unique name up for each of your cache entries. Here I am generating a name based upon the category we are building the data for by adding ‘cache_children_’ and $category. If the cache hit fails then it runs the build code and then finally saves. The important parameter here is the last array(’category’, ‘frontend’) this is telling the cache to associate two tags ‘category’ & ‘frontend’ with that cache entry.

Tagging the Cache
Tagging of the cache entries is to me a touch of genius on the part of the Zend Framework team. It may seem a simple concept but given a large project you end up with literally hundreds of cached chunks which named individually would be unmanageable. Within my ‘category’ model I have lots of methods which invalidate the category data which means the cache needs to be cleared. To clear only those parts of the cache associated with category all I have to do is clear using a keyword.

$cache->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array('category'));

What became clear to me was that although most cache clearance was done by the system it was becoming hard work to test my code once it was wrapped in a cache. The only way round this was to either.

1. Delete the relevant cache files (or SQL depending on what cache storage you are using)
2. Make the cache expiry very short
3. Alter the code in question to not cache while testing. (not good)

(One quick note here that Zend_Cache is very easy to use within PHPUnit and I encourage anyone to always write a unit test for each of your models.)

Most of the time I ended up using option 1 which was taking longer and longer as I created multiple levels of caching. When you find yourself repeating a manual operating more than 5 times you should then look at the time implications of writing a tool vs how many more times you are going to perform that manual operation again. In this case things were only going to get worse.

We needed an interface
What I wanted was an interface that allowed quick and easy ways to clear the cache. Zend_Cache gives two clear ways, either as we have already demonstrated by TAG, or by the specific NAME of the cache entry. As of Framework 0.92 the Zend_Cache framework did not have any functionality for reading the current contents of the cache so I had to write an extension that worked with one of the caching mechanisms (Zend_Cache_Frontend_File and Zend_Cache_Backend_File).

The most obvious way to display the most commonly used TAGS was to generate a tag cloud. This would allow me to see each tag and how many corresponding entries linked to that tag. I could then just click on the tag to delete all those entries.

I have put the code up on the code bank as it is a bit long to include here. The function ‘cloud’ reads from the specified cache directory and returns two arrays. The first is a list of the the cache entries and their expiry, the second is a tag cloud array. Below is a example of how to call the cloud function and then how to generate the HTML. In this example we attach a link to each tag which could then be used to clear that tag from the cache.

list($entries,$cachetags) = cloud();
 
// Now display the tag cloud (for cache)
if(count($cachetags) > 0) {
	foreach($cachetags as $tagname => $tagdata) {
		$disp = $this->escape($tagname)." (".$tagdata['qty'].")";
		$disp = '<a href="/clear/'.$this->escape($tagname).'">'.$disp.'</a>';
		echo '<div style="font-size:'.$tagdata['size'].'px">'.$disp.'</div>';
	}
}

I hope that at some point that the Zend team will add some methods to read back from all of the different cache mechanisms (File, SQLite, memcache, ZendPlatform).

There Are 3 Responses So Far. »

  1. Nick Halstead’s Blog: Making a TAG Cloud out of Zend_Cache…

  2. [...] his example, he grabs treed category data and dumps it (formatted) into a Zend_Cache object. He also mentions [...]

  3. [...] organised. Here is why you should learn to use PHP in a MVC style. As you will see from my other articles, I’m using the Zend Framework but there are many popular [...]

Post a Response