Caching of included sub templates (Smarty version 2.6.9)

Nick Payne <[email protected]> Fri, 04 May 2007 16:15:15 +0100
Newsgroups gmane.comp.php.smarty.devel
Message-ID <[email protected]>
--------------090308010305020907040808
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

Hey list,

Due to the way we use smarty in our PHP framework we needed a way to 
only cache certain templates included within other top level templates. 
For example, home.tpl includes within it menu-top.tpl - a dynamically 
generated menu which requires a large number of MySQL queries to 
generate the navigational menu for a website. Whilst we don't want most 
of the content on the home page to ever be cached, it's of use to cache 
the menu for short periods of time (as low as 60 seconds) as on high 
traffic sites it greatly reduces the number of database queries needed - 
we can live with a 1 or 2 minute stale menu for the amount of queries it 
saves us.
   
We haven't used smarty's caching until now and couldn't see a way of 
achieving this, and after a bit of experimenting (and to be honest, 
trial and error) came up with the following solution. The only function 
which has been changed is _smarty_include($params) in Smarty.class.php. 
Two things:
   
1) It might be a bit of a hack, but it seems to work - no doubt there's 
a better way of doing it.
2) We might be re-inventing the wheel & missing out on existing smarty 
caching abilities that can do exactly this for us already. If so, please 
enlighten us :)
   
   
    Example usage:
   
    --home.tpl
   
    <div id="menu">
        {include file="menu-top.tpl" __cache__=60} {* cache the menu for 
1 minute *}
    </div>
    <div id="pagecontent">
        ... get dynamic page content (never want cached)...
    </div>
   
   

    Code:
   
    --Smarty.class.php
   
    function _smarty_include($params)
    {
        static $_cache_info = array(); // needed for cache stack
 
        if ($this->debugging) {
            $_params = array();
            require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
            $debug_start_time = smarty_core_get_microtime($_params, $this);
            $this->_smarty_debug_info[] = array('type'      => 'template',
                                                  'filename'  => 
$params['smarty_include_tpl_file'],
                                                  'depth'     => 
++$this->_inclusion_depth);
            $included_tpls_idx = count($this->_smarty_debug_info) - 1;
        }
       
        // check for special '__cache__' variable
        $cache = $params['smarty_include_vars']['__cache__'];
        unset($params['smarty_include_vars']['__cache__']);
       
        //If caching check for cached version, and return if found
        if($cache != "") {
          /* save cache lifetime */
          $_cache_lifetime = $this->cache_lifetime;
         
          /* set to $cache */
          $this->cache_lifetime = $cache;
         
          // the following section mimics normal smarty caching behaviour...
         
          $resource_name = $params['smarty_include_tpl_file'];
         
          // save old cache_info, initialize cache_info
          array_push($_cache_info, $this->_cache_info);
          $this->_cache_info = array();
          $_params = array(
              'tpl_file' => $resource_name,
              'cache_id' => '',
              'compile_id' => '',
              'results' => "",
          );
         
          require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php');
          if (smarty_core_read_cache_file($_params, $this)) {
              $_smarty_results = $_params['results'];
              if (!empty($this->_cache_info['insert_tags'])) {
                  $_params = array('plugins' => 
$this->_cache_info['insert_tags']);
                  require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
                  smarty_core_load_plugins($_params, $this);
                  $_params = array('results' => $_smarty_results);
                  require_once(SMARTY_CORE_DIR . 
'core.process_cached_inserts.php');
                  $_smarty_results = 
smarty_core_process_cached_inserts($_params, $this);
              }
              if (!empty($this->_cache_info['cache_serials'])) {
                  $_params = array('results' => $_smarty_results);
                  require_once(SMARTY_CORE_DIR . 
'core.process_compiled_include.php');
                  $_smarty_results = 
smarty_core_process_compiled_include($_params, $this);
              }
              echo $_smarty_results;
              return true;
           }
          
          //ASSERT: NO CACHE AVAILABLE
          $this->_cache_info['template'][$resource_name] = true;
        }
       
        // normal behaviour - either no __cache__ variable passed,
        // or no cached template available

        $this->_tpl_vars = array_merge($this->_tpl_vars, 
$params['smarty_include_vars']);

        // config vars are treated as local, so push a copy of the
        // current ones onto the front of the stack
        array_unshift($this->_config, $this->_config[0]);

        $_smarty_compile_path = 
$this->_get_compile_path($params['smarty_include_tpl_file']);


        if ($this->_is_compiled($params['smarty_include_tpl_file'], 
$_smarty_compile_path)
            || 
$this->_compile_resource($params['smarty_include_tpl_file'], 
$_smarty_compile_path))
        {
            // if caching, we need to isolate included tpl output and 
then put that in cache
          if($cache != "") {
            /* save output buffer for later */
            $ob_pre = ob_get_contents();
            ob_end_clean();
            ob_start();
          }
           include($_smarty_compile_path);
          if($cache != "") {
            /* save output buffer (included tpl) into cache */
            $_params["results"] = ob_get_contents();
            ob_end_clean();
            ob_start();
            /* restore original output buffer */
            echo $ob_pre;
          }
          
        }
       
        if($cache != "") {
 
          /* write cache file */
          require_once(SMARTY_CORE_DIR . 'core.write_cache_file.php');
          smarty_core_write_cache_file($_params, $this);
          require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php');
          $_smarty_results = 
smarty_core_process_cached_inserts($_params, $this);
         
          // restore initial cache_info
          $this->_cache_info = array_pop($_cache_info);
          $this->cache_lifetime = $_cache_lifetime;
         
          //actually output data this run
          echo $_smarty_results;
          return true;
        }
       
        // pop the local vars off the front of the stack
        array_shift($this->_config);

        $this->_inclusion_depth--;

        if ($this->debugging) {
            // capture time for debugging info
            $_params = array();
            require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
            $this->_smarty_debug_info[$included_tpls_idx]['exec_time'] = 
smarty_core_get_microtime($_params, $this) - $debug_start_time;
        }

        if ($this->caching) {
            
$this->_cache_info['template'][$params['smarty_include_tpl_file']] = true;
        }
    }
   
   
Apologies for the length of the code snippet - needed the whole function 
to illustrate the changes made (a diff of the original and modified file 
is attached).
   
Any suggestions or comments would be greatly appreciated.
   
    Nick

-- 
Nick Payne
Developer
 
SBsquared Limited
The Old Forge
Hoults Estate
Walker Road
Newcastle upon Tyne
NE6 1AB
 
T: +44(0)845 330 7201
F: +44(0)870 460 4937
 
W: www.sbsquared.com


--------------090308010305020907040808
Content-Type: text/x-patch;
 name="smarty.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="smarty.diff"

1838a1839,1841
>     
>         static $_cache_info = array();
>   
1847a1851,1899
>         
>         $cache = $params['smarty_include_vars']['cache'];
>         unset($params['smarty_include_vars']['cache']);
>         
>         //If caching check for cache, and return if found
>         if($cache != "") {
>           /* save cache lifetime */
>           $_cache_lifetime = $this->cache_lifetime;
>           
>           /* set to $cache */
>           $this->cache_lifetime = $cache;
>           
>           $resource_name = $params['smarty_include_tpl_file'];
>           
>           // save old cache_info, initialize cache_info
>           array_push($_cache_info, $this->_cache_info);
>           $this->_cache_info = array();
>           $_params = array(
>               'tpl_file' => $resource_name,
>               'cache_id' => '',
>               'compile_id' => '',
>               'results' => "",
>           );
>           
>           require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php');
>           if (smarty_core_read_cache_file($_params, $this)) {
>               $_smarty_results = $_params['results'];
>               if (!empty($this->_cache_info['insert_tags'])) {
>                   $_params = array('plugins' => $this->_cache_info['insert_tags']);
>                   require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
>                   smarty_core_load_plugins($_params, $this);
>                   $_params = array('results' => $_smarty_results);
>                   require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php');
>                   $_smarty_results = smarty_core_process_cached_inserts($_params, $this);
>               }
>               if (!empty($this->_cache_info['cache_serials'])) {
>                   $_params = array('results' => $_smarty_results);
>                   require_once(SMARTY_CORE_DIR . 'core.process_compiled_include.php');
>                   $_smarty_results = smarty_core_process_compiled_include($_params, $this);
>               }
>               echo $_smarty_results;
>               return true;
>            }
>            
>           //ASSERT NO CACHE
>           $this->_cache_info['template'][$resource_name] = true;
>         }
>         
>         //Normal Behaviour
1861,1863c1913,1948
<             include($_smarty_compile_path);
<         }
< 
---
>           if($cache != "") {
>             /* save output buffer for later */
>             $ob_pre = ob_get_contents();
>             ob_end_clean();
>             ob_start();
>           }
>            include($_smarty_compile_path);
>           if($cache != "") {
>             /* save output buffer into cache */
>             $_params["results"] = ob_get_contents();
>             ob_end_clean();
>             ob_start();
>             /* restore original output buffer */
>             echo $ob_pre;
>           }
>            
>         }
>         
>         
>         if($cache != "") {
>  
>           /* write cache file */
>           require_once(SMARTY_CORE_DIR . 'core.write_cache_file.php');
>           smarty_core_write_cache_file($_params, $this);
>           require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php');
>           $_smarty_results = smarty_core_process_cached_inserts($_params, $this);
>           
>           // restore initial cache_info
>           $this->_cache_info = array_pop($_cache_info);
>           $this->cache_lifetime = $_cache_lifetime;
>           
>           //actually output data this run
>           echo $_smarty_results;
>           return true;
>         } 
>         


--------------090308010305020907040808
Content-Type: text/plain; charset=us-ascii

-- 
Smarty Development Mailing List (http://smarty.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
--------------090308010305020907040808--