Part of the EllisLab Network
   
1 of 3
1
Poll
Do you think this is a good idea?
Yes 42
No 4
Total Votes: 46
You must be a logged-in member to vote
Sparks : Caching Template system
Posted: 14 July 2007 04:52 PM   [ Ignore ]  
Grad Student
Rank
Total Posts:  33
Joined  07-14-2007

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:

<p><?php echo("This block is cacheable"); ?></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 <?php ?> blocks.  I.e. it becomes:

<p>This block is cacheable</p>
<
p><?php echo("This block is NOT cacheable"); ?></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!

Profile
 
 
Posted: 16 July 2007 06:41 AM   [ Ignore ]   [ # 1 ]  
Grad Student
Rank
Total Posts:  33
Joined  07-14-2007

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):

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)

<html>
<
body>

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

</body>
</
html


Usage (content file)

<h4>Content fileTodays headline<?$headline ?></h4>

Username <$?= $username ?$> <br/>
Cache file generated at<?$generate_time ?>this page generated at: <$?= $view_time ?$> 
Profile
 
 
Posted: 16 July 2007 08:28 AM   [ Ignore ]   [ # 2 ]  
Grad Student
Avatar
Rank
Total Posts:  54
Joined  12-07-2006

Nice, nice work. Thanks for sharing.

Profile
 
 
Posted: 23 July 2007 06:55 AM   [ Ignore ]   [ # 3 ]  
Grad Student
Rank
Total Posts:  55
Joined  06-05-2006

This seems like a great idea! Thanks alot for sharing it!

Profile
 
 
Posted: 25 July 2007 11:28 AM   [ Ignore ]   [ # 4 ]  
Grad Student
Rank
Total Posts:  58
Joined  10-24-2006

interesting library, do you have any api docs for using it, other than the wiki page?

Profile
 
 
Posted: 25 July 2007 12:04 PM   [ Ignore ]   [ # 5 ]  
Grad Student
Rank
Total Posts:  33
Joined  07-14-2007
jbowman - 25 July 2007 03:28 PM

interesting library, do you have any api docs for using it, other than the wiki page?

Working on it!

Profile
 
 
Posted: 25 July 2007 12:12 PM   [ Ignore ]   [ # 6 ]  
Grad Student
Rank
Total Posts:  58
Joined  10-24-2006

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!

Profile
 
 
Posted: 25 July 2007 12:17 PM   [ Ignore ]   [ # 7 ]  
Grad Student
Rank
Total Posts:  33
Joined  07-14-2007

You might also like to check out another Al James (tm) production: http://codeigniter.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…

Profile
 
 
Posted: 26 July 2007 08:45 AM   [ Ignore ]   [ # 8 ]  
Grad Student
Rank
Total Posts:  58
Joined  10-24-2006

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

$lang['template_email''Email';
$lang['template_password''Password';
$lang['template_register''Register now!'

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

<div id="site_header_login">
            <
form method="post" action="/user/login"><$?=$lang['template_email'];?>: <input type="text" /> <$?=$lang['template_password'];?>: <input type="password" /> <input type="submit" value="Login" /></form>
            <
a href="/user/register"><$?=$lang['template_register'];?></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.

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

        
extract($this->dataEXTR_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;
        
    
Profile
 
 
Posted: 26 July 2007 10:02 AM   [ Ignore ]   [ # 9 ]  
Lab Technician
Avatar
RankRankRankRank
Total Posts:  1092
Joined  08-06-2006

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.

 Signature 

peeker email (imap/pop) | site_migrate | OOCalendar | PhotoBox2 | word_limiter

Profile
 
 
Posted: 26 July 2007 10:07 AM   [ Ignore ]   [ # 10 ]  
Grad Student
Rank
Total Posts:  33
Joined  07-14-2007

@sophistry

You can make it work in php4 by making one call per method:

Instead of:

$this->sparks->store()->display(); 

You would use:

$this->sparks->store();
$this->sparks->display(); 

Longer but it should work!

Profile
 
 
   
1 of 3
1