September 12, 2010

A dynamic sidebar implementation in Zend Framework

This is for displaying a dynamic set of small boxes or modules of content on a side column of a website, like maybe a box that displays a shopping cart summary, or a box that shows advertisement.

The outline of this method is:
- Declare an array of classes to run, each class represents a boxed module on the page.
- Each module's data is collected as an associative array and sent to the view.
- In the layout, loop through this data and then call each partial passing along the data set when there is one.

Here is a picture of the outcome:



Below is an example of 3 sidebar items to be loaded.
$s = new App_Sidebar_Loader();
$this->view->sidebar = $s->load(array(
    array('SomeAlert', 'hideEmpty'=> true),
    array('FavsList'),
    array('StaticContent', 'viewOnly'=>'true'),
));

File locations:
Library / App / Sidebar / Loader.php
Library / App / Sidebar / Modules / SomeAlert.php
Library / App / Sidebar / Modules / FavsList.php
Library / App / Sidebar / Modules / StaticContent.php

Partials (Zend framework view helper):
View / script / Sidebar / SomeAlert.phtml
View / script / Sidebar / FavsList.phtml
View / script / Sidebar / StaticContent.phtml

I didn't want to pre-process the view file names, like from "SomeAlert" to "some-alert.phtml", so I'll just stick to the camel casing for the partial file names.

The Loader class currently supports 2 types of options:
- "viewOnly": Load the view only, no class to execute.
- "hideEmpty": Show module or not when there is no data for it.

/**
 * @author 2010 Edward Hew
 * @license http://creativecommons.org/licenses/MIT/ Creative Commons MIT License
 *
 * Options accepted are:
 * - viewOnly: boolean, when true grab only view script, no class to exec
 * - hideEmpty: boolean, default false, don't show sidebar module id 'data' is empty
 */
class App_Sidebar_Loader
{
    public function load($loadList){

        $len = count($loadList);
  
        for($i = 0; $i < $len; ++$i){
   
            $sidebarHandle = $loadList[$i][0];
            // viewOnly check
            if(empty($loadList[$i]['viewOnly'])) {
                $class = 'App_Sidebar_Modules_'.$sidebarHandle;
                $c = new $class;
                $runData = $c->run();
                if (sizeof($runData) > 0)
                    $data[$sidebarHandle]['data'] = $runData;
                else if (empty($loadList[$i]['hideEmpty'])) {
                    $data[$sidebarHandle]['data'] = null;
                }
            } else {
                $data[$sidebarHandle]['data'] = null;
            }
        }
        return $data;
    }
}

A module class looks like this:

class App_Sidebar_Modules_FavsList
{
    public function run() {

        // Call model normally, but I'll just show a sample resulting array
        $fav[] = array( 'id'=>1 , 'name'=> 'Blade Runner' );
        $fav[] = array( 'id'=>2 , 'name'=> 'Alien' );
        return $fav;
    }
}

For this module, the return value is an empty array on purpose

/*
 * To test loader option hideEmpty
 */
class App_Sidebar_Modules_SomeAlert
{
    public function run() {
        return array();
    }
}

Finally the view helper partial template is called in the layout like this:
Location: layout / script / layout.phtml
if($this->sidebar) {
        foreach($this->sidebar as $key => $data){
            echo $this->partial( ('sidebar/'.$key.'.phtml'), $data);
        }
    }

That's all of it, uploaded a working ZF project to Github here (apologies, its in the Branches link on that page). If you have any comments or criticism, please drop a comment. And thanks for visiting!

1 comment:

Anonymous said...

Works like a charm Edward, ;-)