Fragments are a quick and simple way to cache HTML or other output. Fragments are not useful for caching objects or raw database results, in which case you should use a more robust caching method, which can be achieved with the Cache module. Fragments use Kohana::cache() and will be placed in the cache directory (application/cache
by default).
You should use Fragment (or any caching solution) when reading the cache is faster than reprocessing the result. Reading and parsing a remote file, parsing a complicated template, calculating something, etc.
Fragments are typically used in view files.
Fragments are used by calling Fragment::load() in an if
statement at the beginning of what you want cached, and Fragment::save() at the end. They use output buffering to capture the output between the two function calls.
You can specify the lifetime (in seconds) of the Fragment using the second parameter of Fragment::load(). The default lifetime is 30 seconds. You can use the Date helper to make more readable times.
Fragments will store a different cache for each language (using I18n) if you pass true
as the third parameter to Fragment::load();
You can force the deletion of a Fragment using Fragment::delete(), or specify a lifetime of 0.
// Cache for 5 minutes, and cache each language
if (!Fragment::load('foobar', Date::MINUTE * 5, true)) {
// Anything that is echo'ed here will be saved
Fragment::save();
}
In this example we will calculate pi to 1000 places, and cache the result using a fragment. The first time you run this it will probably take a few seconds, but subsequent loads will be much faster, until the fragment lifetime runs out.
if (!Fragment::load('pi1000', Date::HOUR * 4)) {
// Change function nesting limit
ini_set('xdebug.max_nesting_level', 1000);
// Source: http://mgccl.com/2007/01/22/php-calculate-pi-revisited
function bcfact($n)
{
return ($n == 0 || $n == 1) ? 1 : bcmul($n, bcfact($n - 1));
}
function bcpi($precision)
{
$num = 0;
$k = 0;
bcscale($precision + 3);
$limit = ($precision + 3) / 14;
while ($k < $limit) {
$num = bcadd($num, bcdiv(bcmul(bcadd('13591409', bcmul('545140134', $k)), bcmul(bcpow(-1, $k), bcfact(6 * $k))), bcmul(bcmul(bcpow('640320', 3 * $k + 1), bcsqrt('640320')), bcmul(bcfact(3 * $k), bcpow(bcfact($k), 3)))));
++$k;
}
return bcdiv(1, (bcmul(12, ($num))), $precision);
}
echo bcpi(1000);
Fragment::save();
}
echo View::factory('profiler/stats');
?>
In this example we will use the Feed class to retrieve and parse an RSS feed of recent edits to http://en.wikipedia.org, then use Fragment to cache the results.
$feed = "http://en.wikipedia.org/w/index.php?title=Special:RecentChanges&feed=rss";
$limit = 50;
// Displayed feeds are cached for 30 seconds (default)
if (!Fragment::load('rss:' . $feed)):
// Parse the feed
$items = Feed::parse($feed, $limit);
foreach ($items as $item):
// Convert $item to object
$item = (object) $item;
echo HTML::anchor($item->link, $item->title);
?>
<blockquote>
<p>author: <?php echo $item->creator ?></p>
<p>date: <?php echo $item->pubDate ?></p>
</blockquote>
<?php
endforeach;
Fragment::save();
endif;
echo View::factory('profiler/stats');
You can nest fragments with different lifetimes to provide more specific control. For example, let's say your page has lots of dynamic content so we want to cache it with a lifetime of five minutes, but one of the pieces takes much longer to generate, and only changes every hour anyways. No reason to generate it every 5 minutes, so we will use a nested fragment.
If a nested fragment has a shorter lifetime than the parent, it will only get processed when the parent has expired.
// Cache homepage for five minutes
if (!Fragment::load('homepage', Date::MINUTE * 5)):
echo "<p>Home page stuff</p>";
// Pretend like we are actually doing something :)
sleep(2);
// Cache this every hour since it doesn't change as often
if (!Fragment::load('homepage-subfragment', Date::HOUR)):
echo "<p>Home page special thingy</p>";
// Pretend like this takes a long time
sleep(5);
Fragment::save();
endif;
echo "<p>More home page stuff</p>";
Fragment::save();
endif;
echo View::factory('profiler/stats');