Tag: Add new tag

How to build a “dashboard” for your application in CakePHP

As an addition to my recent post, I wanted to share a technique, which should allow you to pretty easily build a “dashboard” for your app.
The dashboard would basically grab some information from a few different models and display it all on one page.

First, let’s go over some assumptions…

  1. We are not going to use requestAction(), because it’s the “worst” (and absolutely the last-resort approach). It has it’s purposes, but we want to avoid it as much as possible. (I’m not going into detail as to why, because that has been covered many times in many many places, so you can just fire-up your trusty search engine to learn more).
  2. The models from which we’ll gather the information are absolutely not related to one another, if they are related… this is not the best approach. Remember, we don’t want to reload any models (objects), which CakePHP has already loaded for us.

So, keeping both of those things in mind, here’s what we’ve got:

Post model, with a method getTop();
News model, with a method getRecent();
Employee model, with a method getTopPerformers();
Product model, with a method getTopSellers();

(You are welcome to come up with your own methods or use your imagination as to what they might return).
Even though it’s hard to believe that we have no relationship between any of the above models, we’ll assume that to be true for the sake of this example…

We are going to build a Dashboard Controller, with a single action (for now), called index() it’s only purpose is to grab the info from all of the above models and “set” it for the view.

Here’s what it might look like:

<?php
    class DashboardController extends AppController {

          var $name = 'Dashboard';
          var $uses = array();

          function index () {
               $this->set('topPosts', ClassRegistry::init('Post')->getTop());
               $this->set('recentNews', ClassRegistry::init('News')->getRecent());
               $this->set('topEmployees', ClassRegistry::init('Employee')->getTopPerformers());
               $this->set('topSellingProducts', ClassRegistry::init('Product')->getTopSellers());
          }
    }
?>

And that’s really it. Now we have all of our Models’ info available for the view, and we can display it any way we’d like.

Just a few things to point out:

  • We are using ClassRegistry::init('ModelName') to load the relevant models, only once we need them. The init() method will automagically instantiate the model object.
  • We are avoiding the use of the $uses array(), although it could have been used just as well, but this way the models are loaded only when required, and if you have additional actions that might need some other set of models, there is no need to “overburden” your app by loading something extra, before it’s actually needed.
  • If you’d like to make this new dashboard into your actual homepage of the site, please see my other post on how to setup the appropriate route.

How to build a "dashboard" for your application in CakePHP

As an addition to my recent post, I wanted to share a technique, which should allow you to pretty easily build a “dashboard” for your app.
The dashboard would basically grab some information from a few different models and display it all on one page.

First, let’s go over some assumptions…

  1. We are not going to use requestAction(), because it’s the “worst” (and absolutely the last-resort approach). It has it’s purposes, but we want to avoid it as much as possible. (I’m not going into detail as to why, because that has been covered many times in many many places, so you can just fire-up your trusty search engine to learn more).
  2. The models from which we’ll gather the information are absolutely not related to one another, if they are related… this is not the best approach. Remember, we don’t want to reload any models (objects), which CakePHP has already loaded for us.

So, keeping both of those things in mind, here’s what we’ve got:

Post model, with a method getTop();
News model, with a method getRecent();
Employee model, with a method getTopPerformers();
Product model, with a method getTopSellers();

(You are welcome to come up with your own methods or use your imagination as to what they might return).
Even though it’s hard to believe that we have no relationship between any of the above models, we’ll assume that to be true for the sake of this example…

We are going to build a Dashboard Controller, with a single action (for now), called index() it’s only purpose is to grab the info from all of the above models and “set” it for the view.

Here’s what it might look like:

<?php
    class DashboardController extends AppController {

          var $name = 'Dashboard';
          var $uses = array();

          function index () {
               $this->set('topPosts', ClassRegistry::init('Post')->getTop());
               $this->set('recentNews', ClassRegistry::init('News')->getRecent());
               $this->set('topEmployees', ClassRegistry::init('Employee')->getTopPerformers());
               $this->set('topSellingProducts', ClassRegistry::init('Product')->getTopSellers());
          }
    }
?>

And that’s really it. Now we have all of our Models’ info available for the view, and we can display it any way we’d like.

Just a few things to point out:

  • We are using ClassRegistry::init('ModelName') to load the relevant models, only once we need them. The init() method will automagically instantiate the model object.
  • We are avoiding the use of the $uses array(), although it could have been used just as well, but this way the models are loaded only when required, and if you have additional actions that might need some other set of models, there is no need to “overburden” your app by loading something extra, before it’s actually needed.
  • If you’d like to make this new dashboard into your actual homepage of the site, please see my other post on how to setup the appropriate route.

PHP5 and tiny foreach() improvement

While this issue is certainly not specific to CakePHP, I felt it was worthwhile to point out since we are often dealing with data arrays and foreach() loops to modify that data.

Consider the following example:

function afterFind($results, $primary=false) {
    	if($primary == true) {
    	  foreach($results as $key => $value) {
    	      $results[$key][$this->alias]['my_field'] = $this->modifyField($value[$this->alias]['my_field']);
    	  }
    	}

    	return $results;
}

While this works just fine for most cases, the main issue is that $value in the above example is actually a copy of the array’s content.

In PHP5 we have the option to reference the array elements of $results, by using: “$results as &$value”.

So the modified code for PHP5 would look like:

function afterFind($results, $primary=false) {
    	if($primary == true) {
    	  foreach($results as &$value) {
    	      $value[$this->alias]['my_field'] = $this->modifyField($value[$this->alias]['my_field']);
    	  }
    	}
    	unset($value);

        return $results;
}

The obvious improvement is that we are not creating any extra copies of our data. Sure, it may not cause any serious issues, but if making additional copies of the data can be easily avoided it probably should be. Secondly, it makes the code cleaner and more concise, which is always a good thing.

P.S. It is always a good idea to unset() the reference in case any further processing might accidentally change the value of our $results array.