Project alpha: Passbook - Tag clouds Cake PHP tutorial

A key feature I wanted for Passbook that I found lacking in other password applications is a tag cloud of my password groups/lists. A HTML tag cloud is actually a very simple element. All it contains is a list of links with classes that adjusts the font size based on the weight of each link. In the case of Passbook the weight is determined by the number of passwords in a group. I will start by showing the end result:
From that it is easy to see that the group efwfe (yeah, I am pretty lazy with test data) has the most passwords and is what I am most likely to refer to often. Less popular groups fade into the background with their smaller font so that focus can quickly be placed on the high weight items.

The first step in creating a tag cloud is setting up how you want your fonts to look. I have the following CSS styles set for the font sizes (.c1 to .c5) as well as the spacing between tag items (.cloud .a).

.c1 { font-size:100%; }
.c2 { font-size:120%; }
.c3 { font-size:140%; }
.c4 { font-size:160%; }
.c5 { font-size:180%; }
.cloud a { margin-left:0.8em; }
.cloud a:first-child { margin-left:0; }

Calculating the weights is a bit more involved. I wrote the following function in my Pgroup model, which is what my main tag cloud elements of password groups are, with each PGroup model containing a cache field called pitem_count that stores the number of password items belonging to that group. The function setCloudWeights(groups) takes the output of a $Pgroup->find('all') and sets the weights.

// Set cloud weights, expects $groups to be results of find('all')
function setCloudWeights($groups) {
// Vars
$cloud = array('min_weight' => 1, 'max_weight' => 5);
$ceil = max(array_keys(Set::combine($groups, '{n}.Pgroup.pitem_count')));
if ($ceil < $cloud['max_weight']) $cel = $cloud['max_weight']; $floor = round($ceil / $cloud['max_weight']); for ($gi = 0; $gi < g ="&"> $cloud['max_weight']) $g['cloud_weight'] = $cloud['max_weight'];

return $groups;

The function returns an array containing a cloud_weight attribute that is between 1 and 5, which we can use to reference the correct CSS style. The function uses minimum and maximum weights to stop all tag items looking like the maximum font size; the maximum is also used to scale down counts into weights that fit between 1 and 5 when a tag item with more than the preset max is found. You can change 1 and 5 to anything you want and the code will do the rest. Although you will need to create CSS class for n..m depending on what you change 1..5 to.

The function makes very little actual change to the result set created from Cake PHP therefore you can still use it normally. Therefore to generate the cloud I use the following code in my view. It assumes that you have put the results of setCloudWeights(...) into a view variable (using $this->set(...) in the controller) called $cloud. The view code is shown below.

<div class="cloud">
<? if (empty($cloud)): ?>
You have no groups right now.
<? else: ?>
<? foreach ($cloud as $group): ?>
<? $g =& $group['Pgroup'] ?>
<a href="<?= $html->url("/passwords/{$g['name']}") ?>" class="c<?= $g['cloud_weight'] ?>"><?= $g['name'] ?></a>
<? endforeach; ?>
<? endif; ?>

The code provides the basics of a tag cloud by creating our list of links and setting the link class between c1 and c5. You will need to change the model names and attributes to suit your circumstances, however implementing the three sections should not be too difficult. If it is, then leave a comment and I'll try to help our as well as improve on this Cake PHP tutorial.


Post a Comment