CakePHP

Simple Breadcrumbs Components/Helper

I made this component/helper a while ago for a site i was building and i thought i would share it with you. It’s a very simple and straight forward way to add breadcrumbs to your site with minimal mess or fuss.

Component Code (app/controllers/components/breadcrumb.php):

<?php
/*
author: Matthew Nessworthy
http://www.devmatt.co.za/
*/
 
class BreadcrumbComponent extends Object {
 
  var $controller;
  var $breadcrumbs;
 
  //called before Controller::beforeFilter()
  function initialize(&$controller, $settings = array()) {
    // saving the controller reference for later use
    $this->controller =& $controller;
  }
 
  //called after Controller::beforeRender()
  function beforeRender(&$controller) {
    $this->controller->set('__breadcrumbs', $this->breadcrumbs);
  }
 
  function add() {
    $args = func_get_args();
 
    if(!$args) {
      $args = array(
        array(
          $this->controller->name,
          $this->controller->here
        )
      );
    }
 
    foreach($args AS $breadcrumb) {
      $this->breadcrumbs[] = $breadcrumb;
    }
  }
 
  function reset() {
    $this->breadcrumbs = array();
  }
 
}
?>

Helper Code (app/views/helpers/breadcrumb.php):

<?php
/*
author: Matthew Nessworthy
http://www.devmatt.co.za/
*/
 
class BreadcrumbHelper extends AppHelper {
 
  var $helpers = array(
    'Html'
  );
 
  var $breadcrumbs;
 
  function beforeRender() {
    $view =& ClassRegistry::getObject('view');
    if ($view && isset($view->viewVars['__breadcrumbs'])) {
      $this->breadcrumbs = $view->viewVars['__breadcrumbs'];
    }
  }
 
  function generate() {
    return $this->output($this->build_nav($this->breadcrumbs));
  }
 
  function build_nav($breadcrumbs, $level=0) {
    $i = 0;
    $count = count($breadcrumbs);
    $out = '
<ul>';
    foreach($breadcrumbs AS $breadcrumb) {
      $i++;
 
      $breadcrumb[1] = (isset($breadcrumb[1]) && $breadcrumb[1]) ? $breadcrumb[1] : '#';
      $breadcrumb[2] = (isset($breadcrumb[2]) && $breadcrumb[2]) ? $breadcrumb[2] : null;
      $breadcrumb[3] = (isset($breadcrumb[3]) && $breadcrumb[3]) ? $breadcrumb[3] : null;
 
      $out .= '
  <li>';
 
        $out .= $this->Html->link($breadcrumb[0], $breadcrumb[1], $breadcrumb[2]);
 
        if(isset($breadcrumb[3]) && is_array($breadcrumb[3]) && $breadcrumb[3]) {
          $out .= $this->build_nav($breadcrumb[3], $level+1);
        }
 
      $out .= '</li>
 
';
    }
 
    $out .= '</ul>
';
 
    return $out;
  }
 
}

Setup:

  • Create a file called breadcrumb.php in your components folder (e.g. app/controllers/components/breakcrumb.php) with the code above.
  • Create a file called breadcrumb.php in your helpers folder (e.g. app/views/helpers/breakcrumb.php) with the code above.
  • Include the Component in the controllers you want to use it in – i would suggest including it in your AppController – (e.g. var $components = array(‘Breadcrumb’);)
  • Include the Helper in the controllers you want to use it in – i would suggest including it in your AppController – (e.g. var $helpers = array(‘Breadcrumb’);)

Usage (Controller Code):

<?php
$this->Breadcrumb->add(
  array(
    'Home', //title
    array('controller' => 'pages', 'action' => 'home') //link - array based
  ),
  array(
    'Posts',
    '/posts/index' //link - string based,
    //dropdown links
    array(
      array(
        'Latest',
        '/posts/latest'
      )
    )
  )
);

OR

$this->Breadcrumb->add(
  array(
    'Home',
    array('controller' => 'pages', 'action' => 'home')
  )
);
 
$this->Breadcrumb->add(
  array(
    'Posts',
    '/posts/index',
    array(
      array(
        'Latest',
        '/posts/latest'
      )
    )
  )
);
?>

Usage (View Code):

<div id="breadcrumbs">
 <?php echo $breadcrumb->generate(); ?>
</div>

The output generated will look a lot like this:

<ul>
  <li><a href="/">Home</a></li>
  <li><a href="/posts/index">Posts</a>
    <ul>
      <li><a href="/posts/latest">Latest</a></li>
    </ul>
  </li>
</ul>

My preferred menu is the excellent Superfish JS/CSS menu package

CakePHP Daemon Shell

A really excellent and useful CakePHP shell task is the Daemon Task. It allows you to run a pseudo daemon process. I say pseudo because the is no child process detached or anything of that sort. It would actually be more accurate to say that it allows you to run 1 instance of a specific task.

This is great to do things like an email sendout where multiple iterations of the same script could potentially cause problems (if for instance you run a cron job to start the script before the previous call to the same script exits). The Daemon Task takes care of this perfectly.

Pagination & Containable

Some people seem to have issues with using the Containable (CakePHP 1.2 – built-in) behavior and pagination. A very simple way of getting around this is just to set the last argument to false when setting the model relations via the $this->{ModelName}->contain(); method.

This example will not work:

$this->Post->recursive = -1;
//include approved comments
$this->Post->contain(
  array(
    'Comment' => array(
      'conditions' => array(
        'Comment.approved' => true
      )
    )
  )
);
$this->paginate();

The reason the above code will not work is not because the recursive level is set to -1, but because the paginate() function makes 2 calls (count records + retrieve records) and after the first call the model relations get reset. Simply adding a false to the end of the contain() function call, will cause the model relationships to not be reset and hence data will be returned as per your request.

e.g.

$this->Post->recursive = -1;
//include approved comments
$this->Post->contain(
  array(
    'Comment' => array(
      'conditions' => array(
        'Comment.approved' => true
      )
    )
  ),
  false
);
$this->paginate();

Don’t forget to reset the model bings after the call if you want to retrieve more information.

$this->Post->resetBindings();

It’s as simple as that.