It’s been a long time since my last posting. Today I’m going to show you my cycle-helper for cakePHP. If you haven’t read my other posts on alternating row colors, do so now: Alternate Table Rows in CakePHP (and ZF, Rails, Smarty)
The cycle-helper is easy to use and install and if your familiar with the rails cycle-helper you already know how it works…. So: how does it look when you use my helper for alternating row colors:
<table> <?php foreach($rows as $row):?> <tr<?php echo $cycle->cycle('', ' class="altrow"');?>> <td><?php echo $row['rowdata'];?></td> </tr> <?php endforeach ?> </table>
I think it’s pretty nice and a more beautiful approach then what cake bake produces.
Of course you can also use it with css-classes “even” and “odd”:
<table> <?php foreach($rows as $row):?> <tr class="<?php echo $cycle->cycle('odd', 'even');?>"> <td><?php echo $row['rowdata'];?></td> </tr> <?php endforeach ?> </table>
If you have nested loops you have the possibility to give your cycle a name via the “name”-option:
<?php $animals = array("Dogs" => array("Santa's Little Helper", "Beethoven", "Lassie", "Pluto", "Brian"), "Cats" => array("Snowball", "Snowball II", "Snowball III", "Garfield"), "Monkeys" => array("Mojo", "Lazlo", "King Kong"), "Frogs" => array("Kermit", "Ed Bighead"), "Kangaroos" => array("Skippy", "Jack"));?> <?php foreach($animals as $key => $value): ?> <?php echo $key;?> (<?php echo $cycle->cycle("1", "2");?>)<br /> <?php foreach($value as $v):?> <?php echo $cycle->current();?> <?php echo $cycle->cycle("1", "2", "3", array("name" => "test"));?> <?php echo $v;?> <br /> <?php endforeach;?> <hr /> <?php endforeach ?>
The helper code contains comments that should explain how it all works. The code for the helper itself looks like this:
<?php /* * Cycle Helper for cakePHP * Copyright (c) 2009 Andreas * http://functino.com * * @author andreas * @version 1.0 * @license MIT * */ /** * The CycleHelper is used to cycle through the provided strings. * You can use it for example to set alternate classes for table rows. * Usage is simple: * <code> * <table> * <?php foreach($items as $item):?> * <tr class="<?php echo $cycle->cycle("odd", "even");?>""> * <td><?php echo $item;?></td> * </tr> * <?php endforeach;?> * </code> * * This will create rows where the class alternates between "odd" and "even". * * If you need more than one cycle you can use named cycles: * <code> * <?php $items = array("Car" => array("VW", "Fiat", "Ford"), "Food" => array("Pizza", "Hotdog"), "..." => array("..."));?> * <table> * <?php foreach($items as $item => $aliases):?> * <tr class="<?php echo $cycle->cycle("odd", "even");?>""> * <td> * <?php echo $item;?>: * <?php foreach($aliases as $alias):?> * <div class="<?php echo $cycle->cycle("one", "two", "three", array("name" => "second_cycle"));?>"> * <?php echo $alias;?> * </div> * <?php endforeach?> * </td> * </tr> * <?php endforeach;?> * </table> * </code> * */ class CycleHelper extends AppHelper { /** * @var array * @access private */ private $cycles = array(); /** * Creates a Cycle object. Cycles through elements of an array everytime it is called. This is useful for example if you want to * use alternate classes for table rows etc. * This method takes an arbitrary number of strings to cycle through. The last parameter can be an array with options. * If you pass in an options array with the key "name" you create a named cycle. * If you don't pass in this name the name "default" is used. You can use named cycles to use more than one cycle in a loop. * @param string $name aribtrary number of strings to cycle through * @param array $options Options is an array. Currently only array("name" => "xyz") is implemented * @return string $options Link attributes e.g. array('id'=>'selected') * @access public */ public function cycle() { $params = func_get_args(); if(is_array(end($params))) { $options = array_pop($params); $name = $options["name"]; } else { $name = "default"; } $cycle = $this->getCycle($name); if($cycle) { return $cycle; } return $this->setCycle($name, $params); } /** * Resets a cycle. If you reset a cycle it starts form the first element again. * If you don't pass in a name the default cycle is reset. To reset a named cycle pass in it's name. * @param string $name Name of the cycle to reset * @return Cycle * @access public */ public function reset($name = "default") { $this->cycles[$name]->reset(); return $this; } /** * Returns the current cycle string. Normally you simply call the cycle() method to get the current cycle string. This current() * method is useful if you need to get the current cycle string more than one times. * Pass in a name to get the value of a named cycle. * @param string $name Name of the cycle * @return string The current cycle string * @access public */ public function current($name = "default") { return $this->cycles[$name]->current(); } /** * Creates a ViewCycle and stores it in the cycle array by it's name * @param string $name Name of the cycle * @param array $params array of cycle strings * @return ViewCycle * @access public */ public function setCycle($name, $params) { $this->cycles[$name] = new ViewCycle($params); return $this->cycles[$name]; } /** * Returns a cycle by it's name * @param string $name Name of the cycle * @return mixed ViewCycle or false * @access private */ private function getCycle($name) { if(!isset($this->cycles[$name])) { return false; } return $this->cycles[$name]; } } /** * ViewCycle is used by the Cycle helper to cycle through an array of elements (in most cases: strings) */ class ViewCycle { /** * Holds the name of this Cycle * @var string * @access private */ private $name; /** * Holds an array of strings * @var array * @access private */ private $cycle; /** * number of cycle strings * @var integer * @access private */ private $count; /** * iteration counter * @var string * @access private */ private $i; /** * Takes an array of strings to cycle through * @param array $cycle * @return void * @access public */ public function __construct($cycle) { $this->assign($cycle); } /** * Returns the current cycle string and then sets the next cycle string * @return string current cycle string * @access public */ public function __toString() { $this->current = $this->cycle[$this->i % $this->count]; $this->i++; return $this->current; } /** * Returns the current cycle string * @return string * @access public */ public function current() { return $this->current; } /** * Resets this cycle * @return void * @access public */ public function reset() { $this->i = 0; } /** * Set an array of strings to cycle through * @param array $cycle array of strings * @return void * @access public */ public function assign($cycle) { $this->cycle = $cycle; $this->count = count($this->cycle); $this->reset(); } }
If you want to use this helper just copy the code to a file “cycle.php” in app/view/helpers and add it in your app_controller.php to the $helpers array:
<?php class AppController extends Controller { var $helpers = array('Html', 'Form', 'Cycle'); }
That’s it!
thaJeztah
/ July 18, 2009the HTML-helper of CakePHP 1.2 already supports alternating colors by default.
have a look at HTML->tableCells() (oddTrOptions, evenTrOptions)
http://book.cakephp.org/view/841/tableCells
Andreas
/ July 18, 2009Hi thaJeztah,
thanks for your hint. I must admit that I never use the tableCells() or the tableHeaders() helper and didn’t know about that possibility.
Personally I like my solution over that one: It’s more generic (you can use it in tables, divs, etc. to achieve alternating row colors or just to alternate over some strings in other use cases).