Cloud Behavior

Posted by Felix Geisendörfer, on Aug 31, 2008 - in PHP & CakePHP » DataSources, Models & Behaviors

Hey folks,

this is post #12 of my 30 day challenge.

While preparing the application we use for our Raleigh, NC workshop, I had to implement an algorithm to display the records of a table in tag-cloud kind of view. Since the approach I took turned out fairly neat I thought other people might like to use this, so I refactored everything into a little behavior this morning.

In order to download & install the behavior, please go here: Cloud Behavior at Debuggable Scraps.

The code for the behavior itself looks like this:

php
  1. class CloudBehavior extends ModelBehavior{
  2.   var $mapMethods = array('/^_findCloud$/' => '_findCloud');
  3.  
  4.   function setup(&$Model, $settings = array()) {
  5.     if (!isset($this->settings[$Model->alias])) {
  6.       $this->settings[$Model->alias] = array(
  7.         'scale' => 2,
  8.         'shuffle' => true,
  9.         'query' => array(),
  10.         'countField' => 'count',
  11.       );
  12.     }
  13.     if (!is_array($settings)) {
  14.       $settings = array();
  15.     }
  16.     $Model->__findMethods['cloud'] = true;
  17.     $this->settings[$Model->alias] = array_merge($this->settings[$Model->alias], $settings);
  18.   }
  19.  
  20.   function _findCloud(&$Model, $method, $state, $query, $results = array()) {
  21.     if ($state == 'before') {
  22.       $query = array_merge($query, $this->settings[$Model->alias]['query']);
  23.       return $query;
  24.     }
  25.     if (empty($results)) {
  26.       return array();
  27.     }
  28.  
  29.     $countField = $this->settings[$Model->alias]['countField'];
  30.     if (!$countField || !$Model->hasField($countField)) {
  31.       trigger_error('CloudBehavior: You have to configure a valid countField for querying this Model\'s records as a cloud!');
  32.       return array();
  33.     }
  34.  
  35.     $max = $results[0][$Model->alias][$countField];
  36.     $min = $results[count($results)-1][$Model->alias][$countField];
  37.     $range = $max - $min;
  38.     if (!$range) {
  39.       $range = 1;
  40.     }
  41.  
  42.     foreach ($results as &$command) {
  43.       $command[$Model->alias]['scale'] =
  44.         (($command[$Model->alias][$countField] - $min) / $range)
  45.         * $this->settings[$Model->alias]['scale']
  46.         + 1;
  47.     }
  48.     if ($this->settings[$Model->alias]['shuffle']) {
  49.       srand();
  50.       shuffle($results);
  51.     }
  52.     return $results;
  53.   }
  54. }

Please note how I have to violate the concept behind private methods and properties to make this work. My follow up post on this topic is close to completion ; ).

The elegant part about this approach is that you can really keep your view logic down to a minimum:

php
  1. $out = array();
  2. foreach ($tags as $tag) {
  3.   $size = 10 * $tag['Tag']['scale'];
  4.   $out[] = $html->link(
  5.     $tag['Tag']['name'],
  6.     array('controller' => 'tags', 'action' => 'view', $tag['Tag']['id']),
  7.     array('style' => 'font-size: '.$size.'px;')
  8.   );
  9. }
  10. echo join(', ', $out);

Anyway, I hope this code is helpful to some of you out there. Feedback is welcome as always. Please comment!

-- Felix Geisendörfer aka the_undefined

Print this Post | Digg This | Stumble It | Delicious

4 Comments

Mariano Guezuraga on Sep 22, 2008:

Hey Felix, can you confirm if this breaks in breaks in the latest revisions of cake? It was working ok in 1.2 rc2, but in rev. 7644 (and before) I get:

Warning (512): SQL Error: 1054: Unknown column 'cloud' in 'where clause' [CORE/cake/libs/model/datasources/dbo_source.php, line 518]

Query: SELECT `Tag`.`id`, `Tag`.`name`, `Tag`.`count` FROM `alm_tags` AS `Tag` WHERE cloud LIMIT 1

Felix Geisendörfer on Sep 22, 2008:

Mariano Guezuraga: don't have any time to look into this right now, but if you find a moment to trace down what core change might have triggered this I could have a look and verify.

Mariano Guezuraga on Sep 23, 2008:

Thanks for your reply! It works ok in #7639 (and earlier) and starts to fail in #7640 (inclusive)
https://trac.cakephp.org/changeset/7640. My guess is "Making Model::$_findMethods protected"

Add a comment