Skip to content

Fragment Caching Library

Derek Jones edited this page Jul 5, 2012 · 16 revisions

Contibutors:Libraries::Caching

Introduction

Ok, here goes: this is a library to add page-fragment caching capabilities to codigniter. That is: allow you, the programmer to mark a part of a view to be cached independently of other bits of the page. The idea is pretty simple, but I wanted the syntax to be as lean as possible, and to make usage as transparent as possible.

Usage: fragment caching is invoked via start/end markers in the view.

// some un-cached markup & code
// some more un-cached markup & code

<? if($this->cache_fragment->start(1)){ ?>
  // the argument in function 'start' is the cache's expiration time in minutes
  // stuff you wish to cache
<? } $this->cache_fragment->end();?>

// even more un-cached markup & code

The library: Place it in libraries/Cache_fragment.php

<?php
// Fragment caching library for CI
// =============================================================================
// written by nir gavish 2010
// [email protected]
// http://www.webweb.co.il/ (hebrew site)
// =============================================================================
class Cache_fragment{
    private $fragment_path = './cache/fragment/'; // make sure this is a valid dir
    private $fragment_name;
    private $newly_cached = false;
    private $CI;

    function Cache_fragment(){
        $this->CI =& get_instance();
    }
    
    function start($lifespan){
        if ($this->fragment_name!=''){die('Nested fragment cache not supported.');}
        $x = debug_backtrace();

        $this->fragment_name = md5($this->CI->uri->uri_string().'||'.$x[0]['line']);

        // if file does not exist, make preparations to cache and return true, so segment is executed
        if(!file_exists($this->fragment_path . $this->fragment_name)){
            $this->newly_cached = true;
            ob_start();
            return true;
        }else{
            // cache exists, let's see if it is still valid by checking it's age against the $lifespan variable
            $fModify = filemtime($this->fragment_path . $this->fragment_name);
            $fAge = time() - $fModify;
            if ($fAge > ($lifespan * 60)){
                // file is old, let's re-cache
                $this->newly_cached = true;
                ob_start();
                return true;
            }
            // no need to redo
            return false;
        }
    }
    
    function end(){
        if($this->newly_cached==true){
            $new_cache = ob_get_clean();
            
            $fname = $this->fragment_path . $this->fragment_name;
            $fhandle = fopen($fname,"w+");
            $content = $new_cache;
            fwrite($fhandle,$content);
            fclose($fhandle);
        }
        include $this->fragment_path . $this->fragment_name;

        $this->newly_cached = false;
        $this->fragment_name = null;
    }
}
?>

Of course, you can either add 'cache_fragment' to the autoload, or do:

$this->load->library('cache_fragment');

Note: The name of the cache is derived from the full URL + the line number that called the cache, that way, multiple caches may exist on the page, each kept in a separate cache-file, with separate expiration times, this is probably the only semi clever bit in this library.

Note2: Nested fragment caching is not supported, because I'm lazy, if anyone really, absolutely needs it, I'll sit down and add the feature.

Note3: Contact me with anything, really

Clone this wiki locally