CakePHP: Cache views by domain – a cache helper

By default CakePHP caches views using just the path, for example, app/tmp/cache/views/posts.php for /posts or app/tmp/cache/views/posts_view.php for /posts/view but what to do if you want to cache a view which loads from more than one domain and that view has data which is domain specific. For example, there are sub-domains for application users like http://user1.mydomain.com/posts, http://user2.mydomain.com/posts etc. and you want to display posts added by those specific users. This guide will tell you how to hack CakePHP to do this.

You may already know that CakePHP uses Cache helper to cache views and __writeFile() method in that helper class is responsible for building name of a cache file. You can write your own cache helper which will extend built-in cache helper (I preferred this way instead of making changes in CakePHP core) like 'class MyHelper extends CacheHelper' and override __writeFile() method by doing copy/paste core code in that method.

Now change the filename building code from

PHP:
  1. $cache = strtolower(Inflector::slug($path));

to

PHP:
  1. $cache = r('www.', '', env('HTTP_HOST')) . '_' . strtolower(Inflector::slug($path));

so that the domain name will be prefixed to cache filename.

Now let's move forward to make changes in Dispatcher as it outputs cached views. For this, extend Dispatcher class, 'class MyDispatcher extends Dispatcher', and override cached() method by doing same copy/paste thing as mentioned above.

Again change the filename building code from

PHP:
  1. $path = strtolower(Inflector::slug($path));

to

PHP:
  1. $path = r('www.', '', env('HTTP_HOST')) . '_' . strtolower(Inflector::slug($path));

so that the domain name will be prefixed to cache filename.

And now the last change is in app/webroot/index.php, at the end of file, change code from

PHP:
  1. $Dispatcher = new Dispatcher();

to

PHP:
  1. require_once('my_dispatcher.php');
  2. $Dispatcher = new MyDispatcher();

assuming 'my_dispatcher.php' is in searchable path, I used 'app' directory to store my dispatcher.

That's it folks!!!

P.S. You can use your own customizations like date('Ymd') to prefix cache view files, to cache them by days.

About Amit Badkas

Amit Badkas is Zend certified PHP5 and Zend Framework engineer, and has been working in SANIsoft for past 9 years, his present designation is 'Technical Manager'

4 Responses to CakePHP: Cache views by domain – a cache helper

  1. burak June 24, 2010 at 6:32 pm #

    Nice article. I'm trying to extend the CacheHelper as you've suggested but it seems the extended helper doesn't get called? Maybe there is something to change in the view class? Any suggestions?

    • Amit Badkas June 25, 2010 at 8:25 am #

      Thanks for appreciation. As I already mentioned that you need to extend built-in cache helper like 'class MyHelper extends CacheHelper', you need to use 'My' instead of 'Cache' for controller's class variable $helpers array.

  2. burak June 25, 2010 at 9:04 pm #

    I did extend the cache helper as "MyCacheHelper" and I included "MyCache" instead of "Cache" in the helpers array but couldn't get it to run. Isn't this the same as using "MyHelper"?

    I copied the CacheHelper class into my app and modified it. This isn't good but I needed a fast solution and it didn't work by extending it.

  3. Kalt May 6, 2011 at 6:26 pm #

    Very useful, thanks !

    @burak : it is not mentionned here but you need to import the core CacheHelper before the class declaration :
    App::import('Helper', 'Cache');

    I also added a __construct method to MyCacheHelper to register the Helper in the View :

    function __construct() {
    parent::__construct();
    $View = ClassRegistry::getObject('view');
    $View->loaded['cache'] = $this;
    }

Leave a Reply