• 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Sparks : Caching Template system

#1
[eluser]Al James[/eluser]
Update Version 1.1 is here

Hi there,

For my project I require a caching system, however caching in CI is a all or nothing affair, i.e. I can either cache the entire page or nothing at all.

In real life, this is not sutible. For my site (and I should imagine most sites that are not entirely static) elements on the pages an be divided into those that are cacheable and those that are not (must be generated for each page view).

For example: On all my pages, the message "You are logged in as XXX" is displayed in the top corner of the screen. Obviously, this must be generated for each page view. The rest of the page is (often) cacheable.

Out of the box, CI would not be able to help as it can only cache the entire page or nothing at all.

In order to solve this, I have developed a caching template system that allows you to divide the php blocks into those that can be cached and those that cannot. I have called it 'SPARKS' and this is a request for comments. If people like the idea, I will post the code in the wiki.

Basically, you create view files with the following syntax:

Code:
<p>&lt;?php echo("This block is cacheable"); ?&gt;</p>
<p><$?php echo("This block is NOT cacheable"); ?$></p>

Thus, we simply use <$?php ?$> tags for non-cacheable php blocks.

On the first view, the above template gets eval'ed and stored in a cache file. The <$php $> blocks get re-written as &lt;?php ?&gt; blocks. I.e. it becomes:

Code:
<p>This block is cacheable</p>
<p>&lt;?php echo("This block is NOT cacheable"); ?&gt;</p>

So that when this cache file is included, it will execute the non-cacheable php blocks.

Roughly, the pseudo-code for the controller would look like:

1) Load libraries and helpers for non-cacheable content
2) Calculate non-cacheable content
3) Check for a current cached version of the template. If it exists, display it and return.
4) Load libraries and helpers for cacheable content.
5) Calculate cacheable content.
6) Render page to cache.
7) Display page.

Thus is a cached version of the page exists, the controller function returns at step 3 and does not complete steps 4-7.

What do people think of this approach? Its got me out of a sticky situation.

If people think the concept is a good one, I will post the code!

#2
[eluser]Al James[/eluser]
Hi there...

Here is the 'Sparks.php' library.

As well as two-stage caching, this library also solves the view within a view problem commonly experienced with 'templated' webpages. You set a 'template' view file and also a 'content' view file (the template one is optional though). In your template you use the helper 'sparks_content()' as a placemarker where the content file should be inserted. You can also include views within views using the 'sparks_include($view_file)' helper.

Usage (Controller):

Code:
class Test extends Controller {
    
    function index()
    {
        $this->load->library('Sparks');
        //$this->import->library('com.purplesagelabs.template.Sparks');
        
        //     Set template and content files. Set time to live to 5 seconds.
        
        $this->sparks->template('template.php')->content('content.php')->ttl(5);
        
        //    Calculate data for non-cacheable content
        
        $this->sparks->set('username', 'Al James'); //Would be get username from session or whatever
        $this->sparks->set('view_time', time());
        
        // Check for cached version of page, if its there display it and return
        
        if ($this->sparks->is_cached()) return $this->sparks->display();
        
        //Otherwise, generate cacheable content
        
        $this->sparks->set('headline', 'Welcome to Sparks!');
        $this->sparks->set('generate_time', time());
        
        // Store and display the page
        
        $this->sparks->store()->display();
        
    }
}

Usage (template file)

Code:
&lt;html&gt;
&lt;body&gt;

    <h1>Template header!</h1>
    
    &lt;?php sparks_content(); ?&gt;

&lt;/body&gt;
&lt;/html&gt;


Usage (content file)

Code:
<h4>Content file. Todays headline: &lt;?= $headline ?&gt;</h4>

Username <$?= $username ?$> <br/>
Cache file generated at: &lt;?= $generate_time ?&gt;, this page generated at: <$?= $view_time ?$>

#3
[eluser]txomin[/eluser]
Nice, nice work. Thanks for sharing.

#4
[eluser]Sarre[/eluser]
This seems like a great idea! Thanks alot for sharing it!

#5
[eluser]jbowman[/eluser]
interesting library, do you have any api docs for using it, other than the wiki page?

#6
[eluser]Al James[/eluser]
[quote author="jbowman" date="1185395285"]interesting library, do you have any api docs for using it, other than the wiki page?[/quote]

Working on it!

#7
[eluser]jbowman[/eluser]
ok great Smile I'm still in heavy design mode for my site, but am testing sparks out right now to see if it fits well with my design ideas. First initial implementation went very well.

For anyone else keeping tabs on this project, I'd like to note that the caching variables work within the templates, as well as the content. All variables declared with set work from the template on down. I'm presuming they work within the includes for parts as well, though as of yet I don't have a test case to prove it. This has given me the incentive to start working on my basic layout and getting my css/javascript setup.

Thanks Al!

#8
[eluser]Al James[/eluser]
You might also like to check out another Al James ™ production: http://ellislab.com/forums/viewthread/56798/

A page library for working with js/css files and meta info. It also allows you to pass data straight from PHP into the javascript layer if you want (great for AJAX style pages)....

I will probably bundle all my libraries into one package (they all complement each other) with decent documentation...

#9
[eluser]jbowman[/eluser]
I made a modification to Sparks for handling language setting.

I changed the changed the display and store functions to loop through the currently loaded language and create a $lang array.

So now if you have an application/lanaguage/english/template_lang.php that has this inside
Code:
$lang['template_email'] = 'Email';
$lang['template_password'] = 'Password';
$lang['template_register'] = 'Register now!';

You can have a block of your template/view look like

Code:
<div id="site_header_login">
            &lt;form method="post" action="/user/login"&gt;<$?=$lang['template_email'];?&gt;: &lt;input type="text" /&gt; <$?=$lang['template_password'];?&gt;: &lt;input type="password" /&gt; &lt;input type="submit" value="Login" /&gt;&lt;/form&gt;
            <a href="/user/register"><$?=$lang['template_register'];?&gt;</a>
        </div>

Note: I'm using the Sparks syntax to not cache my language strings, since they're dynamic depending on the user viewing the site.

Here's my updated functions.

Code:
/**
     *  Display the current cache file
     *  
     *  @access public
     *  @return object  A pointer to $this for chaining
     */
    function display()
    {
        
        $CI =& get_instance();

        extract($this->data, EXTR_SKIP); //EXTR_SKIP to avoid overwriting the $CI variable
        
       foreach ($CI->lang->language as $key => $val)
       {
                $lang[$key] = $val;
       }

        
        include($this->_cache_file_name());
        
        return $this;
        
    }

    /**
     *  Save this page to the cache
     *  
     *  @access public
     *  @return object  A pointer to $this for chaining
     */
    function store()
    {
                                
        $file = ($this->template_file == null) ? $this->content_file : $this->template_file;                
                                
        $__path = APPPATH.'views/'.$file;
        
        extract($this->data);
        
        $CI =& get_instance();

       foreach ($CI->lang->language as $key => $val)
       {
               $lang[$key] = $val;
       }

        
        ob_start();
        
        require($__path);
        
        $buffer = ob_get_contents();
        @ob_end_clean();
        
        $this->_write_to_cache($buffer);
        
        return $this;
        
    }

#10
[eluser]sophistry[/eluser]
A quick look at this makes me think it is implemented for PHP5 only - method chaining does not work in PHP4 AFAIK.

Would it be a huge production to make it available for PHP4? I don't know what alternate architecture would be needed to replicate the method chaining. Extra methods? Or just different usage of the library?

Thanks for sharing! This looks really nice and I'll take it out for a drive shortly.


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2021 MyBB Group.