I’ll introduce this topic with a warning – This article doesn’t show you how to completely reorder your entire Navigation, it does however show you how you could populate a new container from an existing one and reorder it.
Zend Navigation currently doesn’t allow you to nominate a default Navigation Container class. So while we could extend the Zend_Navigation_Container creating our own customised one, you’d almost have to duplicate the code for the Zend Page and Zend Container classes to do a thorough job, as they both call each other – so won’t know to use your new one.
My goal was to achieve:
- a container of all pages in my navigation configuration (ignoring hierarchy)
- exclude pages that had sub pages (so I only had the leaves on the branch so to speak)
- order these pages by a date set for each page in the nav configuration
Step 1 – Add dates to Navigation configuration
You can add new properties to Zend Navigation Pages without needing to do anything. See my “dateadded” in the example below on some pages.
<security> <label>Security</label> <module>computers</module> <controller>security</controller> <action>index</action> <pages> <password> <label>Password generator</label> <module>computers</module> <controller>security</controller> <action>password-generator</action> <dateadded>01/08/2009</dateadded> </password> <encrypt> <label>Hash generator</label> <title>Hash generator (string encryption)</title> <module>computers</module> <controller>security</controller> <action>encrypt</action> <dateadded>25/08/2009</dateadded> </encrypt> </pages> </security>
Step 2 – Create a custom container type
By creating a custom container extending Zend_Navigation_Container we can add our own sorting function. The trick of this is converting the dates to the linux time stamp i.e. number of seconds since 1 January 1970. This is also a logical place to but build a function to extract lowest level pages from another container. This one class services all three of my requirements.
class Utilitiesman_Navigation_Container_Utilities extends Zend_Navigation_Container { public function addLowestPages($page) { $iterator = new RecursiveIteratorIterator($page,RecursiveIteratorIterator::SELF_FIRST); foreach ($iterator as $page) { // don't add page if it has children if(!$page->hasPages()) { $lowestPages[] = $page; } } $this->addPages($lowestPages); } public function sortByDate($property = 'dateadded') { $newIndex = array(); $index = 0; foreach ($this->_pages as $hash => $page) { $pageDate = $page->get($property); if(Zend_Date::isDate($pageDate)) { $date = new Zend_Date($pageDate); $timestamp = $date->getTimestamp(); $newIndex[$hash] = $timestamp; } else { // there wasn't a valid date for this page, use an incremental number start at 0 $newIndex[$hash] = $index; $index++; } } //sort the array using those timestamp versions of the dates arsort($newIndex); $this->_index = $newIndex; $this->_dirtyIndex = false; // flag index as clean - prevent default sort } }
Step 3 – Call it and render the result
This is all done within the context of a view script (the layout in my case) I should mention:
$containerByDate = new Utilitiesman_Navigation_Container_Utilities(); $rootPage = current($this->navigation()->getContainer()->getPages()); $containerByDate->addLowestPages($rootPage); $containerByDate->sortByDate(); echo $this->navigation()->menu()->render($containerByDate);
To see a cool example of this in action check out the calculator section of my utilities man website, or any section mind you.
My implementation is a little more complex than this though, I’m using a partial view script for the menu and I’m also only displaying pages under the section your on.
