Caching of included sub templates (Smarty version 2.6.9)

From: Date: Fri, 04 May 2007 15:15:15 +0000
Subject: Caching of included sub templates (Smarty version 2.6.9)
Groups: php.smarty.dev 
Request: Send a blank email to php-smarty-dev+get-3005@lists.php.net to get a copy of this message
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

« previous php.smarty.dev (#3005) next »