Author Archives: Tom Van Herreweghe

A smarter strategy for using Zend_Navigation

What I love about Zend Framework is that it has so many components you can use. One of these components that can make your life easier is Zend_Navigation. The documentation says, it’s a component “for managing trees of pointers to web-pages”. So basically you can use it for all your navigational needs on your website: menu, breadcrumbs, sitemaps, …

One site menu please, with caching

Most examples on how to use Zend_Navigation show you how to create a relatively simple site structure. The amount of pages is limited, and this is great to demonstrate the different functionalities of this component. And to be honest, most sites you’ll create will just have a simple site structure.

Sometimes, you’ll build your site menu from a database, and usually this means your site structure will be bigger than what the examples show you. One way of making sure that everything stays fast, is making use of another great Zend Framework component: Zend_Cache. By caching your site structure, you bypass the fetching of data from the database and molding them into Zend_Navigation_Page’s or -Containers. Here’s a small example:

/**
 * Site service
 *
 * @category	Service
 * @package		Site
 */
/**
 * Service for general site related stuff
 *
 * @category	Service
 * @package		Site
 */
class Application_Service_Site
{
	const USE_CACHE_TRUE = true;
	const USE_CACHE_FALSE = false;

	/**
	 * Returns the site navigation from the database
	 *
	 * @param boolean $useCache OPTIONAL flag to specify if caching should be used
	 * @return Zend_Navigation
	 */
    public function getNavigation ($useCache = self::USE_CACHE_TRUE)
    {
		// if caching is enabled, try to load the navigation from the cache:
        if (self::USE_CACHE_TRUE === $useCache) {
            $cache = $this->_getCacheObject();
			if (!$container = $cache->load('sitenavigation')) {
				// cache was invalid, so regenerate the data, and cache it:
				$container = $this->getNavigation(self::USE_CACHE_FALSE);
				$cache->save($container, 'sitenavigation');
			}
			return $container;
        }

		// fetch data from DB:
		$results = $this->getCompleteCategoryTree();

		// recursively build the navigation:
		$container = $this->_buildNavigationTree($container, $results);

        return $container;
    }

	/**
	 * Transforms a tree of data to a tree in Zend_Navigation
	 *
	 * @param Zend_Navigation $container
	 * @param object $tree
	 * @return Zend_Navigation
	 */
	protected function _buildNavigationTree ($container, $tree)
	{
		foreach ($tree as $node) {
			$page = new Zend_Navigation_Page_Mvc(array(
				'label'         => $node->label,
				'controller'    => $node->controller,
				'action'        => $node->action,
				'params'        => unserialize($node->params)
			));

			if ($node->hasChildren()) {
				$page = $this->_buildNavigationTree($page, $node->getChildren());
			}

			$container->addPage($page);
		}

		return $container;
	}

	/**
     * Get a cache object from the cache manager
     *
     * @return Zend_Cache
     */
    protected function _getCacheObject ($cacheName)
    {
		// get the bootstrap:
		$bootstrap = Zend_Controller_Front::getInstance()->getParam('bootstrap');

		// get cachemanager from the bootstrap:
    	$cacheManager = $bootstrap->getResource('cachemanager');

		// get requested cache:
    	$cache = $cacheManager->getCache($cacheName);

    	return $cache;
    }
}

Never mind that the example isn’t really realistic and that the code isn’t complete. I’ve added in-line comments everywhere, so it should be self-explanatory. In short, the code fetches data from the database, and transforms it into a Zend_Navigation object. Basically, you fetch a tree of data, and recursively create a tree in Zend_Navigation for your entire site structure. Optionally, you can specify to use caching or not. For convenience, the cache is managed by the ‘cachemanager’ Application Resource. This makes it easy to have a different setup for production/development environment via your application.ini config:

resources.cachemanager.sitenavigation.frontend.name = Core
resources.cachemanager.sitenavigation.frontend.customFrontendNaming = false
resources.cachemanager.sitenavigation.frontend.options.lifetime = 1209600
resources.cachemanager.sitenavigation.frontend.options.automatic_serialization = true
resources.cachemanager.sitenavigation.backend.name = File
resources.cachemanager.sitenavigation.backend.customBackendNaming = false
resources.cachemanager.sitenavigation.backend.options.cache_dir = APPLICATION_PATH "/../tmp"
resources.cachemanager.sitenavigation.frontendBackendAutoload = false

And then it goes horribly wrong!

The example above works fine, and you just start coding away on other stuff. You fill up the database with some test data, and you’re happy that everything works just fine. But you’ve already made your first mistake: premature optimization. By defaulting to using cache, you don’t really know how fast or slow things are without using a cache mechanism. But no worries, let’s assume you didn’t make that mistake, and you turn on caching after you’ve evaluated the current site speed, and you see that caching really makes things faster.

What went horribly wrong for me is that by using the cache, I saw the page loading time go down from 4 seconds to 1.8 seconds. That’s quite a speed bump, but 1.8 seconds still is slow. And since there was no other optimization option available to me, I had to start looking in the code. Turns out that my navigation was a big time consumer. If I totally disabled my navigation, the page loading time went down to 0.9 seconds. So there was definitely something fishy going on there.

Who needs a big tree anyway?

A bonsai is nice too! Sorry, bad joke. But that’s exactly what was wrong: There was so much data in the database, the navigation tree just became too big. Everything was read from the file cache and loaded into the memory. On each request. Ouch! That hurt the server (and my ego). Loading more than 10.000 pages into memory isn’t that efficient. And when you think about it, who really needs the entire tree in memory on each request anyway? No-one does, that’s who.

My fault was assuming that the practices that work for small and static site navigations would just work for large and dynamic site navigations. My last project was a website for a company that offers trainings and courses. There were more than 6.000 courses, nicely put in a category structure of sometimes 3 levels deep. For the navigation, I always needed the first level of categories, optionally the subcategories of a selected category, and optionally a selected course. This came down to 30′ish pages I needed. Compare that to the more than 10.000 I initially loaded into the memory.

How do you start optimizing your code so you end up with a Zend_Navigation container that’s populated depending on your request, instead of just loading everything? Quite simple really, by just passing some extra parameters from the request to the method that builds the navigation. Here’s an example:

/**
 * Site service
 *
 * @category	Service
 * @package		Site
 */
/**
 * Service for general site related stuff
 *
 * @category	Service
 * @package		Site
 */
class Application_Service_Site
{
	const USE_CACHE_TRUE = true;
	const USE_CACHE_FALSE = false;

	/**
	 * Returns the site navigation from the database
	 *
	 * @return Zend_Navigation
	 */
    public function getNavigation (array $params)
    {
		// fetch data from DB:
		$results = $this->getCategoriesAndBranchForParams($params);

		// recursively build the navigation:
		$container = $this->_buildNavigationTree($container, $results);

        return $container;
    }

	/**
	 * Get the path in the tree that leads from the root to current category
	 *
	 * @param array $params
	 * @return array
	 */
	public function getCategoriesAndBranchForParams (array $params)
	{
		// get the first level of categories:
		$categories = $this->_getCategoriesOnLevel(0);

		foreach ($categories as &$category) {
			if ($category->getHasChildWithId((int) $params['category_id'])) {
				// get the leaf of the tree we're currently on:
				$leafNode = $this->_getCategoryById($params["category_id"]);

				// get the path from the leaf to the root:
				$category = $this->_retraceToNode($leafNode, $category);
			}
		}

		return $categories;
	}

	/**
	 * Recursively retrace the path from given node to the root of the tree
	 *
	 * @param object $node
	 * @return object
	 */
	protected function _retraceToNode ($node, $rootNode)
	{
		if (null !== $node->getParentNodeId()) {
			$parent = $this->_getCategoryById($node->getParentNodeId());
			$parent->addChild($node);

			if ($parent->getCategoryId() != $rootNode->getCategoryId()) {
				// we haven't reached our desired $rootNode yet, so continue
				return $this->_retraceToRoot($parent, $rootNode);
			}
		}

		return $node;
	}

	/**
	 * Returns the navigation from the cache
	 *
	 * @return Zend_Navigation
	 */
	public function getCachedNavigation ()
	{
		$cache = $this->_getCacheObject();
		if (!$container = $cache->load('sitenavigation')) {
			// cache was invalid, so regenerate the data, and cache it:
			$container = $this->getNavigation();
			$cache->save($container, 'sitenavigation');
		}
		return $container;
	}

	/**
	 * Transforms a tree of data to a tree in Zend_Navigation
	 *
	 * @param Zend_Navigation $container
	 * @param object $tree
	 * @return Zend_Navigation
	 */
	protected function _buildNavigationTree ($container, $tree)
	{
		foreach ($tree as $node) {
			$page = new Zend_Navigation_Page_Mvc(array(
				'label'         => $node->label,
				'controller'    => 'category',
				'action'        => 'overview',
				'params'        => unserialize($node->params)
			));

			if ($node->hasChildren()) {
				$page = $this->_buildNavigationTree($page, $node->getChildren());
			}

			$container->addPage($page);
		}

		return $container;
	}

	/**
     * Get a cache object from the cache manager
     *
     * @return Zend_Cache
     */
    protected function _getCacheObject ($cacheName)
    {
		// get the bootstrap:
		$bootstrap = Zend_Controller_Front::getInstance()->getParam('bootstrap');

		// get cachemanager from the bootstrap:
    	$cacheManager = $bootstrap->getResource('cachemanager');

		// get requested cache:
    	$cache = $cacheManager->getCache($cacheName);

    	return $cache;
    }
}

First, but least important: the caching has been moved to a dedicated method called “getCachedNavigation”. Personally, I find it more readable than working with flags.

Secondly, and much more important, a parameter has been introduced in the “getNavigation” method. This parameter is what you would get from the request object, and contains the controller name, action name, and query parameters. This query parameter is then used to fetch the part of the tree that’s relevant for current page. Instead of fetching the entire tree, we only fetch the first level of categories, and 1 branch we need in order to determine the correct breadcrumb path. All the rest is irrelevant.

A thousand words

A picture often says more than a thousand words. Here’s how I have reduced the memory footprint of my navigation, by simply keeping in mind which page is being looked at.

navigation_tree.png

This is just a small representation of what was originally in memory for the Zend_Navigation object. Imagine each level 1 category to have at least 2 second level categories. Each second level category has at least 10 pages. After optimizing, the result is:

navigation_branch.png

As you can see, the end result is a much simpler and smaller tree. I have kept the first level of categories, as I needed them for my menu. Then I have 1 branch which reaches out to the page I’m currently on. This branch is used for the breadcrumbs.

Conclusion

Needless to say that going from a very big tree in memory to just a very small tree will dramatically impact your site’s responsiveness. This optimization roughly translated into a 50% speed boost for my project. Best of all, it took only 1 hour of work to achieve this. I have learned from this, that caching should never be implemented and used from the beginning. It’s a premature optimization mistake which can lead us to think that something else is the bottleneck, not the code. Taking away the cache forced me to actually think again about the code I had written. Sometimes improvements are obvious, if you open up your mind for them.

Book review: Pragmatic Guide to Git

When I first heard about Version Control Software, I thought it was nothing for me. But working in a team, and sharing the same source code poses interesting questions: “can I edit that file now?”, “who the hell removed my code?”, … If this sounds familiar to you, then maybe it’s time to do what I did: start using Version Control Software. Even if you’re working alone, it can never hurt to be able to revert back to an earlier version of your code.

Review

If you’re anything like me, then you want having a good reference for the tool you’re going to use. I prefer that reference to be a physical book. Nothing beats being able to browse through a book when searching for something. The one I’ll be reviewing is called “Pragmatic Guide to Git” and it’s written by Travis Swicegood. If you’ve ever been to a conference and seen him give a session about Git, then you’ll know Travis knows what he’s talking about. If you haven’t had the pleasure, then take it from me :)

The book is aimed at beginners who “don’t need a lot of hand-holding”. This just means that it’s for everyone who just wants to get started using Git, without much theory. And that’s exactly what this book delivers. The book is divided into parts, containing several tasks. A task can be translated as a single command in Git, while a part is a group of commands which all serve a common purpose.

These parts are:

  1. Getting started
  2. Working with Git
  3. Organizing your repository with branches and tags
  4. Working with a team
  5. Branching and merging revisited
  6. Working with the repository’s history
  7. Fixing things
  8. Moving beyond the basics

As you can see, things start off slowly, and gradually you start learning more and more. The good news is that all these parts are ordered in exactly the same way as you’re probably going to need them. Sometimes I find myself skipping some chapters in a book, because the things I needed were not ordered logically. Not so with this book.

Each of these parts contains tasks. A task could be “Committing changes” or “Creating and switching to a branch”. A task gives an explanation about a single command, and some of the options for that command. What’s handy is that for each task, the explanation is on the left page, while the code is on the right page. No need for you to start searching through paragraphs where the exact code is you need. Good chance you’ll quickly find it on the right hand side.

Conclusion

If you’re all new to Git, then this book is exactly what you need. You start of with the basics, and with each task you learn new stuff. The layout of the book is of great advantage when you quickly need to find something back. Travis did a great job organizing the different subjects in a way that gives you a very natural order to learn Git. For those of you who want to dive deeper, or need more advanced knowledge, then this book isn’t for you. As a first book on Git, or a quick reference, you won’t be disappointed when buying Pragmatic Guide to Git.

My ZendCon 2010 Experience

This year, for the first time, I went to the yearly ZendCon conference in Santa Clara California. My plan was to absorb as much information as I could, and even participate in the uncon. But along the way, my plans got changed. I’m not going to talk about which sessions were most interesting, or which speaker annoyed me. Instead, I’m going to talk about how I experienced the whole ZendCon conference.

How I used to go to a conference

I started going to PHP conferences about one and a half year ago. My first conference was Dutch PHP Conference, DPC short. A colleague and me both proposed this conference to management, as a way to improve our skills and learn new architectural designs. Management took the bite, and sent us off with 4 people. As we had hoped, we did learn a lot. In fact, we had enough information to maul over for at least 8 months.

Being with people you’re familiar with is of great comfort when you’re in a rather larger crowd like the DPC attendees. You have people to fall back to, and you have a good time with your colleagues. When you go back home, you feel as if you’ve grown towards each other. This would be awesome, if we had a team-building weekend. But this was a conference, and team-building isn’t really a conference’s intention.

How I attended ZendCon

I was planning on going to ZendCon together with a (new) colleague. But due to circumstances my colleague had to return home upon landing in Washington. This left me all alone in unknown territory. I wasn’t worried about traveling alone, but rather about just being alone. Hence I decided I would have to go out and meet new people or this would be the worst experience ever. Going out and meeting new people isn’t something I usually do when I’m in company. But now was as good a time as any to start.

So the first morning there (one day before the conference kicked off), I got on the hotel’s wifi and started checking out the #zendcon hashtags on twitter. Just to see if people were gathering to meet up somewhere. And yes, about half an hour later I had my first appointment: breakfast with @nanderoo and @DASPRiD. As it turns out I had met @DASPRiD before, on DPC actually, so there was no problem to start a conversation.

After breakfast, we decided to hang out in the hotel lobby and see if other people wanted to meet up. By the end of the afternoon, a whole bunch of us were gathered in the lobby. Old friends meeting up again, new friends getting acquainted. The atmosphere was great and I was very happy to have met so many nice people.

During the conference days, I regularly met up with the people I met that first day. Exchanging experiences from the conference or just chatting away and having fun. From this point forward, getting to know new people became quite easy. Friends met new friends and gradually your network is expanding. It kind of baffled me how easy it was to just go sit at a table and start talking to people. Generally speaking, everyone was quite cool about talking to total strangers. This gave me the confidence I needed to just go out and meet these new people.

All this socializing never gave me a dull moment. There were always people around to have a chat with, have a drink with, discuss issues with, have fun with, go to the swimming pool with, go to In-N-Out Burger with, go to a Microsoft VIP Party with (thanks Josh for the invite!), go to Taco Bell with, visit the Apple Campus at One Infinite Loop with, have expensive steaks with at Mortons, discuss tv shows with, dream of Yellowstone-PHP-conference with, go to IHOP with, have a laugh with funny stories from a certain adult video streaming company in Charlotte, …

What will I remember from this experience?

I hope I’ll remember all the great people I’ve met, when I meet them again. Sessions and tutorials are what make a PHP conference a good learning experience. But the other people are what make a PHP conference an incredible experience. My only advice to other people is to just go out and talk to new faces. Use the social media to your advantage, and turn a conference into an experience you’ll never forget.

Custom colored UITabBar icons

On the iPhone, there is no such thing as a menu. When you create an application, you will usually work with a drill-down structure called NavigationController, or with the TabBarController. The difference between them is that the NavigationController ties screens together with increasing granular information, and the TabBarController lets you switch between screens which aren’t really connected to each other. It’s about that TabBarController I want to write this blog post about. Or rather, about a “missing feature” in it.

The TabBarController can be customized with either custom titles, custom icons or both. If you want custom icons, you will see that even though you created them in different colors, the iPhone SDK will always render them in blue when active, and in grey when inactive. Wouldn’t it be nice if you could have them in any color you’d like? I know designers would like that. More often than not, they design these pieces of the UI without remembering that in the end these icons will be blue/grey. But unfortunately there is no obvious way of achieving this. But when means are limited, creativity can help you solve many issues.

Custom colored icons

There is a trick to make your designer happy, and give him his colored icons. However, it still is a work around, and the method isn’t very stylish. It comes down to this:

  • Don’t give icons or titles to your different UITabBarItems
  • On each view of the UITabBar, set a different images as tabbar
  • Each different image has both the TabBar background in it, as well as all the icons. But the currently active page icon should be highlighted

Here are some examples:

  • background_calendar.png
  • background_clock.png
  • background_location.png
  • background_lightbulb.png

I have four tabs, so this means I need four different backgrounds for my UITabBar. On each view, I first need to remove the current background, and then I just add the background for current screen. In each ViewController I add the following:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
	for(UIView *view in self.tabBarController.tabBar.subviews) {
		if([view isKindOfClass:[UIImageView class]]) {
			[view removeFromSuperview];
		}
	}

	[self.tabBarController.tabBar insertSubview:[[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"background_location.png"]] autorelease] atIndex:0];
}

When you don’t remove the subviews, and just try to insert your background image at index 0, then your image won’t swap. Hence we need to remove the existing subview first, and then later insert our new one. If you now build and run your application, you should see the tabbar, and if you hit each tabbar icon, you will see that the correct one is activated. And all in color!

Update 14 Sept. 2011: I wrote a follow-up blogpost here: http://blog.theanalogguy.be/2011/09/14/custom-colored-uitabbar-icons-an-update/

Custom background for UINavigationBar

When you’re working on an iphone app, more often than not, you’ll be working with the standard SDK elements and then customize those. For a recent project, I had to work with a navigation controller. And of course, the UINavigationBar needed to be customized with a proper image.

Now I had never done this before, and as usual when I don’t know how to do some task, I look in one of my two books. If the answer isn’t there, then Google comes to the rescue. So to customize the background of a UINavigationBar wouldn’t be too much of a problem I thought. And indeed it wasn’t, but I first implemented a wrong solution:

How to do it incorrectly

In the viewWillAppear:(BOOL)animated method of the ViewController, I wrote this:

[self.navigationController.navigationBar insertSubview:[[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"title_bar.png"]] autorelease] atIndex:0];

Basically, it inserts an image with filename “title_bar.png” as a subView into the UINavigationBar. This works fine. In fact, I couldn’t see anything wrong with it. So I went ahead, and added it elsewhere in the code too.

So if this works, what is wrong with it? The behavior is unpredictable. In my title bar, I set the title of the current view, and I added a button on the right hand side. Sometimes the button wouldn’t render, sometimes the title wouldn’t render. Sometimes the behavior was correct only after I went to another view, and then came back to this one. So to keep it short: it is unpredictable, and you don’t want to do it this way.

How to do it correctly

To make this work, you don’t have to write a lot of code. All you need to do is subclass the UINavigationBar class, and implement the drawRect method yourself. This will override the default behavior with what you implement. So each time drawRect is called, we just make sure the “title_bar.png” image is added:

@implementation UINavigationBar (CustomImage)
- (void)drawRect:(CGRect)rect {
	UIImage *image = [UIImage imageNamed: @"title_bar.png"];
	[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
@end

The drawRect method is automatically invoked when the UINavigationBar will be rendered. Each time this happens, the image will now be automatically drawn in the title bar. Beware though, this is for all UINavigationBar’s in your project.