Speeding up Requests with Reverse Routing Caching

Category CakePHP
This issue has been discussed by Tim and Matt in recent days and people got some performance changes.
From this I created an improved version of the AppHelper from Matt. My version is based on criteria cache.
For example, you can cache all back-end urls separated from the front-end urls using the criteria ‘prefix’.
Also, different from Matt version, it will use a separated cache config ‘_app_urls_’.
Below the code:
Update¹: I’ve updated the code to cache full urls properly. Thanks to Orcar for this catch.
<?php

class AppHelper extends Helper {
	public $_cache = array();
	public $_key = '';
	public $_criteria = array('prefix');
	public $_extras = array();
	public $_paramFields = array('controller', 'plugin', 'action', 'prefix');

	public function beforeRender() {
		if (is_a($this, 'HtmlHelper')) {
			$keys = array_intersect_key($this->params, array_combine($this->_criteria, $this->_criteria));
			$this->_key = 'url_map_' . implode('_', $keys);

			$this->_cache = Cache::read($this->_key, '_app_urls_');
			$this->_extras = array_intersect_key($this->params, array_combine($this->_paramFields, $this->_paramFields));
		}
	}

	public function afterLayout() {
		if (is_a($this, 'HtmlHelper')) {
			Cache::write($this->_key, $this->_cache, '_app_urls_');
		}
	}

	public function url($url = null, $full = false) {
		$keyUrl = $url;
		if (is_array($keyUrl)) {
			$keyUrl += $this->_extras;
			$keyUrl['full'] = $full;
		}

		$key = md5(serialize($keyUrl));
		if (!empty($this->_cache[$key])) {
			return $this->_cache[$key];
		}

		$url = parent::url($url, $full);
		$this->_cache[$key] = $url;

		return $url;
	}
}
Comments5 Comments

5 Responses

  1. [...] a continuation off a couple of posts mentioned in the last digest, Renan Gonçalves posted a modified version of my code. If only one of us had commit access and could sneak this into the core [...]

  2. Hi!

    In what way, more exactly, is this code improved?

    Also line 33 looks funky here: “if (!emptyempty($this->_cache[$key])) {” but it only seems to be the highlighting, plain mode looks fine. Strange.

    • Hey Oscar!

      Good catch with the double empty, its really a highlighting problem. I’m going to create a ticket for it. Thank’s.

      The code as improved in two ways:
      1 – You can define a separated cache settings for this. Its named “_app_urls_”. Its mean that you can use FileEngineCache for model caches and so on and use APC for this particular cache. (Take a look on this article Cache duration and configuration tips)
      2 – Putting more keys on $this->_criteria you can separate the caches. I’m using $this->_criteria = array(‘prefix’) its mean that will be created two caches: Front-end cache and Back-end (admin) cache.

      Thank you for your reply!

      • Hi!

        Still haven’t figured put how/where to pass the prefix to your code, but it doesn’t matter that much for me. However, I ran into another more serious problem. When passing true to the “full” parameter in the URL function, of doesn’t take that into account when getting the info from the cache, so it returns the URL without the base address apended. At least I think that’s what happens (I’m using it for sending emails). Suggestions?

        • Hey Oscar!

          The criteria is hard-coded, so you to put beforeRender() something like this:
          $this->_criteria = array(‘controller’);
          This example will create one cache entry for every controller you have.

          I just updated the code and the post to allow the use o $full = true, thank you for this catch.

          See ya!

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>