tags:

views:

461

answers:

1

The Smarty FAQ suggests one way to handle cacheable fragments, but it needs each page controller to do tons of work up-front, instead of encapsulating things properly.

We want to get to a stage where we can do something like:

<div id="header">
  {our_categories}
  {our_subcategories category=$current_category}
</div>

The output of the our_ prefixed functions should be completely cacheable, only relying on the named parameters (if any.) If we referred to {our_categories} in more than one template, they should all refer to the same cached content.

(it's probably worth mentioning that we tried using {insert name="..."} and coding up our own functions, but the results weren't cacheable, and we ended up hand-cranking the HTML retunred, rather than benefiting from Smarty's template processing.)

Our first crack at this uses a custom function smarty_function_our_categories, but the caching's going horribly wrong. Here's what our function looks like:

function smarty_function_our_categories($params, &$smarty) {
  $smarty->caching = 2;
  $smarty->cache_lifetime = 3600; # 1 hour
  if (!$smarty->is_cached(...)) {
    // ... do db access to fetch data for template...
    $smarty->assign(....);
  }
  return $smarty->fetch(...);
}

The problem is: calling $smarty->fetch() within a function confuses smarty, making it lose track of which templates have insert-tags, and which don't. The end result is that Smarty forgets to replace certain markers when serving up cached content (markers it puts there to say: "replace this with the results of some non-caching {insert ...} call.) In our case, this manifests itself with our site showing a couple of md5 checksums and a php-serialized memento where our main menu should be - that's not good.

We assume we've made a mistake in how we're building our components, so the question finally becomes:

How do you safely create a caching component using Smarty to render itself?

A: 

You should not change caching parameters from inside Smarty function. Wheither or not the result of the plugin output is cacheable is defined when you register plugin.

http://www.smarty.net/manual/en/caching.cacheable.php

To create uncachable content inside cachable template just use {dynamic} blocks like this:

//Registering dynamic non-caching block with Smarty
$template->register_block('dynamic', 'smarty_block_dynamic', false); 
function smarty_block_dynamic($param, $content, &$smarty) { 
    return $content; 
}
FractalizeR
This has three downsides we want to avoid: (1) pre-registering block implementations instead of auto-loading, (2) template needs to open and close each block, (3) block implementation builds HTML manually instead of rendering using smarty.We're looking to see if and how we can work around each issue and would love some suggestions.
searlea
(1) you can place your dynamic block function into smarty directory and it will load it on demand. (2) I didn't understand (3) Didn't get either. What is the problem of it?
FractalizeR