4.2. Output caching

In many websites some data do not change so often in order to read them every time from the database or some other source. They are not even worth assigning to the template engine then. To improve the performance, we can use the output caching feature. When it is enabled, OPT captures the output generated by the parser and stores it on the HDD. Next time, instead of generating the result once more, it simply reads it from the directory.

OPT supports the expiry date cache. This means that if the cache file is too old, it is regenerated in order to make the website up-to-date. There is, however, some delay, but if we specify short enough peroids, the guests will not notice anything.

The output caching feature is enabled by specifying the directory, where OPT will store the cached template versions. We set it in the cache directive. Then we use optClass::cacheStatus() method to enable or disable the caching for the exact templates:

Example 4.4. Caching issues

// This is our cache directory.
$tpl -> cache = './cache/';
// cache file1.tpl for 120 seconds
$tpl -> cacheStatus(true, 120);
$tpl -> parse('file1.tpl');
$tpl -> cacheStatus(false);

// cache three files for 30 seconds
$tpl -> cacheStatus(true, 120);
$tpl -> parse('file1.tpl');
$tpl -> parse('file2.tpl');
$tpl -> parse('file3.tpl');
$tpl -> cacheStatus(false);
// This file will not be cached
$tpl -> parse('file4.tpl');

The next, very useful method, is optClass::isCached(). It allows to check, whether the template has a valid cache file, and we do not have to read the data from the database etc. Note that this method reads everything it needs from the cache file and you do not have to call cacheStatus() before you want to use it. This is a sample code:

Example 4.5. Reading the data in cached scripts

<?php
	define('OPT_DIR', '../lib/');
	require(OPT_DIR.'opt.class.php');
	
	try
	{ 
		$tpl = new optClass;
		$tpl -> root = 'templates/';
		$tpl -> compile = 'templates_c/';
		$tpl -> cache = 'cache/';
		$tpl -> httpHeaders(OPT_HTML);
	
		if(!$tpl -> isCached('example10.tpl'))
		{
			// We load the data only if we regenerate the cache
			require('db_connect.php'); 
			$r = mysql_query('SELECT id, name, description
				FROM products ORDER BY id');
			$list = array();
			while($row = mysql_fetch_assoc($r)) 
			{ 
				// add the next item 
				$list[] = array( 
					'id' => $row['id'], 
					'name' => $row['name'],
					'description' => $row['description']
				);
			}
			$tpl -> assign('products', $list);
			mysql_close();
		}
		// cache the template result for 30 seconds
		$tpl -> cacheStatus(true, 30);
		$tpl -> parse('example10.tpl');
		$tpl -> cacheStatus(false);
	}
	catch(optException $exception)
	{ 
		optErrorHandler($exception); 
	}
?>

Even in the cached templates, there is unsually a need to some content stay dynamic. The dynamic content can be enclosed in the {dynamic}...{/dynamic} tags:

Example 4.6. Dynamic content in cached templates

{dynamic}
<p>Dynamic date: {$current_date}</p>
{/dynamic}
<p>Static (cached) date: {$current_date}</p>

If we cache this template, we notice that the first date changes every time we refresh the page (it is dynamic). The second date changes rarely, only if the cache file is regenerated and OPT has an ability to put here the new value (see Example 9 in the sources).

Let's say we have a template that is used to show an article. We call it article_read.tpl. We cache it, but there is the problem. The user sees only article A, even if he wants to see article B. Why? Of course, OPT cached the first article and thinks it should be shown in all the situations. But there is a solution. Using optClass::cacheUnique() method you may set additional identifier to the cached content.

Example 4.7. Unique cache ID

if(!$tpl -> isCached('article_read.tpl', $_GET['article_id']))
{
	$stmt = $opd -> prepare('SELECT * FROM articles WHERE id=:id');
	$stmt -> bindValue(':id', $_GET['article_id'], PDO::PARAM_INT);
	$stmt -> execute();
	$tpl -> assignGroup($stmt -> fetch());
}
$tpl -> cacheStatus(true, 300);
$tpl -> cacheUnique($_GET['article_id']);
$tpl -> parse('article_read.tpl');
$tpl -> cacheStatus(false);

As we see, the ID must be specified also in the isCached() method. Note that after calling the parse() method, the ID is cleared automatically, so we do not have to worry about the fact that the next template will be also cached with it by mistake.