API CHANGE: Allow cached blocks within control and if blocks, as long as that control or if block is contained within an uncached block, not a cached block

git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/branches/2.4@101833 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Hamish Friedlander 2010-03-30 02:36:54 +00:00 committed by Sam Minnee
parent cfe081dd8b
commit 04299df886
2 changed files with 59 additions and 41 deletions

View File

@ -686,33 +686,21 @@ class SSViewer_PartialParser {
/xS'; /xS';
static function process($template, $content) { static function process($template, $content) {
$parser = new SSViewer_PartialParser($template, $content, 0, array(), 'if', 'false'); $parser = new SSViewer_PartialParser($template, $content, 0);
$parser->parse(); $parser->parse();
return $parser->generate(); return $parser->generate();
} }
function __construct($template, $content, $offset, $keyparts, $conditional, $condition) { function __construct($template, $content, $offset) {
$this->template = $template; $this->template = $template;
$this->content = $content; $this->content = $content;
$this->offset = $offset; $this->offset = $offset;
$this->keyparts = $keyparts;
$this->conditional = $conditional;
$this->condition = $condition;
$this->blocks = array(); $this->blocks = array();
} }
function controlcheck($text) { function controlcheck($text) {
$ifs = preg_match_all('/<'.'% +if +/', $text, $matches); // NOP - hook for Cached_PartialParser
$end_ifs = preg_match_all('/<'.'% +end_if +/', $text, $matches);
if ($ifs != $end_ifs) throw new Exception('You can\'t have cached or uncached blocks within condition structures');
$controls = preg_match_all('/<'.'% +control +/', $text, $matches);
$end_controls = preg_match_all('/<'.'% +end_control +/', $text, $matches);
if ($controls != $end_controls) throw new Exception('You can\'t have cached or uncached blocks within control structures');
} }
function parse() { function parse() {
@ -735,12 +723,12 @@ class SSViewer_PartialParser {
if ($tag == 'cached' || $tag == 'cacheblock') { if ($tag == 'cached' || $tag == 'cacheblock') {
list($keyparts, $conditional, $condition) = $this->parseargs(@$matches[2][0]); list($keyparts, $conditional, $condition) = $this->parseargs(@$matches[2][0]);
$parser = new SSViewer_Cached_PartialParser($this->template, $this->content, $endpos, $keyparts, $conditional, $condition);
} }
else { else {
$keyparts = array(); $conditional = 'if'; $condition = 'false'; $parser = new SSViewer_PartialParser($this->template, $this->content, $endpos);
} }
$parser = new SSViewer_PartialParser($this->template, $this->content, $endpos, $keyparts, $conditional, $condition);
$parser->parse(); $parser->parse();
$this->blocks[] = $parser; $this->blocks[] = $parser;
$this->offset = $parser->offset; $this->offset = $parser->offset;
@ -824,13 +812,49 @@ class SSViewer_PartialParser {
return array($parts, $conditional, $condition); return array($parts, $conditional, $condition);
} }
function generate() {
$res = array();
foreach ($this->blocks as $i => $block) {
if ($block instanceof SSViewer_PartialParser)
$res[] = $block->generate();
else {
$res[] = $block;
}
}
return implode('', $res);
}
}
class SSViewer_Cached_PartialParser extends SSViewer_PartialParser {
function __construct($template, $content, $offset, $keyparts, $conditional, $condition) {
$this->keyparts = $keyparts;
$this->conditional = $conditional;
$this->condition = $condition;
parent::__construct($template, $content, $offset);
}
function controlcheck($text) {
$ifs = preg_match_all('/<'.'% +if +/', $text, $matches);
$end_ifs = preg_match_all('/<'.'% +end_if +/', $text, $matches);
if ($ifs != $end_ifs) throw new Exception('You can\'t have cached or uncached blocks within condition structures');
$controls = preg_match_all('/<'.'% +control +/', $text, $matches);
$end_controls = preg_match_all('/<'.'% +end_control +/', $text, $matches);
if ($controls != $end_controls) throw new Exception('You can\'t have cached or uncached blocks within control structures');
}
function key() { function key() {
if (empty($this->keyparts)) return "''"; if (empty($this->keyparts)) return "''";
return 'sha1(' . implode(".'_'.", $this->keyparts) . ')'; return 'sha1(' . implode(".'_'.", $this->keyparts) . ')';
} }
function generate() { function generate() {
$res = array(); $res = array();
$key = $this->key(); $key = $this->key();
@ -855,16 +879,6 @@ class SSViewer_PartialParser {
// of cache blocks, and invalidation of the cache when the template changes // of cache blocks, and invalidation of the cache when the template changes
$partialkey = "'".sha1($this->template . $block)."_'.$key.'_$i'"; $partialkey = "'".sha1($this->template . $block)."_'.$key.'_$i'";
$knownUncached = array(
'if' => array('false', '0'),
'unless' => array('true', '1')
);
// Optimized version if we know condition is false
if ($this->conditional && in_array($this->condition, $knownUncached[$this->conditional])) {
$res[] = $block;
}
else {
// Try to load from cache // Try to load from cache
$res[] = "<?\n".'if ('.$condition.' ($partial = $cache->load('.$partialkey.'))) $val .= $partial;'."\n"; $res[] = "<?\n".'if ('.$condition.' ($partial = $cache->load('.$partialkey.'))) $val .= $partial;'."\n";
@ -876,7 +890,6 @@ class SSViewer_PartialParser {
$res[] = "}\n?>"; $res[] = "}\n?>";
} }
} }
}
return implode('', $res); return implode('', $res);
} }

View File

@ -189,17 +189,22 @@ class SSViewerCacheBlockTest extends SapphireTest {
/** /**
* @expectedException Exception * @expectedException Exception
*/ */
function testErrorMessageForCacheWithinControl() { function testErrorMessageForCachedWithinControlWithinCached() {
$this->_reset(true); $this->_reset(true);
$this->_runtemplate('<% control Foo %><% cached %>$Bar<% end_cached %><% end_control %>'); $this->_runtemplate('<% cached %><% control Foo %><% cached %>$Bar<% end_cached %><% end_control %><% end_cached %>');
}
function testNoErrorMessageForCachedWithinControlWithinUncached() {
$this->_reset(true);
$this->_runtemplate('<% uncached %><% control Foo %><% cached %>$Bar<% end_cached %><% end_control %><% end_uncached %>');
} }
/** /**
* @expectedException Exception * @expectedException Exception
*/ */
function testErrorMessageForCacheWithinIf() { function testErrorMessageForCachedWithinIf() {
$this->_reset(true); $this->_reset(true);
$this->_runtemplate('<% if Foo %><% cached %>$Bar<% end_cached %><% end_if %>'); $this->_runtemplate('<% cached %><% if Foo %><% cached %>$Bar<% end_cached %><% end_if %><% end_cached %>');
} }
/** /**