Moved handling of smarty.block.* to special compilers, because they aren't real tags. Organized tag-stack handling in compiler, unified nocache handling in compiler.

This commit is contained in:
Simon Wisselink
2023-01-20 17:22:00 +01:00
parent 390f34318d
commit 2fbf67b32e
38 changed files with 430 additions and 457 deletions

View File

@@ -5,6 +5,7 @@
*/ */
namespace Smarty\Compile; namespace Smarty\Compile;
use Smarty\Compiler\Template;
use Smarty\Data; use Smarty\Data;
use Smarty\Exception; use Smarty\Exception;
@@ -49,20 +50,6 @@ abstract class Base implements CompilerInterface {
*/ */
protected $cacheable = true; protected $cacheable = true;
/**
* Mapping array for boolean option value
*
* @var array
*/
private $optionMap = [1 => true, 0 => false, 'true' => true, 'false' => false];
/**
* Mapping array with attributes as key
*
* @var array
*/
protected $mapCache = [];
public function isCacheable(): bool { public function isCacheable(): bool {
return $this->cacheable; return $this->cacheable;
} }
@@ -96,14 +83,12 @@ abstract class Base implements CompilerInterface {
*/ */
protected function getAttributes($compiler, $attributes) { protected function getAttributes($compiler, $attributes) {
$_indexed_attr = []; $_indexed_attr = [];
if (!isset($this->mapCache['option'])) { $options = array_fill_keys($this->option_flags, true);
$this->mapCache['option'] = array_fill_keys($this->option_flags, true);
}
foreach ($attributes as $key => $mixed) { foreach ($attributes as $key => $mixed) {
// shorthand ? // shorthand ?
if (!is_array($mixed)) { if (!is_array($mixed)) {
// option flag ? // options flag ?
if (isset($this->mapCache['option'][trim($mixed, '\'"')])) { if (isset($options[trim($mixed, '\'"')])) {
$_indexed_attr[trim($mixed, '\'"')] = true; $_indexed_attr[trim($mixed, '\'"')] = true;
// shorthand attribute ? // shorthand attribute ?
} elseif (isset($this->shorttag_order[$key])) { } elseif (isset($this->shorttag_order[$key])) {
@@ -115,20 +100,24 @@ abstract class Base implements CompilerInterface {
// named attribute // named attribute
} else { } else {
foreach ($mixed as $k => $v) { foreach ($mixed as $k => $v) {
// option flag? // options flag?
if (isset($this->mapCache['option'][$k])) { if (isset($options[$k])) {
if (is_bool($v)) { if (is_bool($v)) {
$_indexed_attr[$k] = $v; $_indexed_attr[$k] = $v;
} else { } else {
if (is_string($v)) { if (is_string($v)) {
$v = trim($v, '\'" '); $v = trim($v, '\'" ');
} }
if (isset($this->optionMap[$v])) {
$_indexed_attr[$k] = $this->optionMap[$v]; // Mapping array for boolean option value
static $optionMap = [1 => true, 0 => false, 'true' => true, 'false' => false];
if (isset($optionMap[$v])) {
$_indexed_attr[$k] = $optionMap[$v];
} else { } else {
$compiler->trigger_template_error( $compiler->trigger_template_error(
"illegal value '" . var_export($v, true) . "illegal value '" . var_export($v, true) .
"' for option flag '{$k}'", "' for options flag '{$k}'",
null, null,
true true
); );
@@ -149,9 +138,7 @@ abstract class Base implements CompilerInterface {
} }
// check for not allowed attributes // check for not allowed attributes
if ($this->optional_attributes !== ['_any']) { if ($this->optional_attributes !== ['_any']) {
if (!isset($this->mapCache['all'])) { $allowedAttributes = array_fill_keys(
$this->mapCache['all'] =
array_fill_keys(
array_merge( array_merge(
$this->required_attributes, $this->required_attributes,
$this->optional_attributes, $this->optional_attributes,
@@ -159,22 +146,19 @@ abstract class Base implements CompilerInterface {
), ),
true true
); );
}
foreach ($_indexed_attr as $key => $dummy) { foreach ($_indexed_attr as $key => $dummy) {
if (!isset($this->mapCache['all'][$key]) && $key !== 0) { if (!isset($allowedAttributes[$key]) && $key !== 0) {
$compiler->trigger_template_error("unexpected '{$key}' attribute", null, true); $compiler->trigger_template_error("unexpected '{$key}' attribute", null, true);
} }
} }
} }
// default 'false' for all option flags not set // default 'false' for all options flags not set
foreach ($this->option_flags as $flag) { foreach ($this->option_flags as $flag) {
if (!isset($_indexed_attr[$flag])) { if (!isset($_indexed_attr[$flag])) {
$_indexed_attr[$flag] = false; $_indexed_attr[$flag] = false;
} }
} }
if (isset($_indexed_attr['nocache']) && $_indexed_attr['nocache']) {
$compiler->tag_nocache = true;
}
return $_indexed_attr; return $_indexed_attr;
} }
@@ -182,44 +166,25 @@ abstract class Base implements CompilerInterface {
* Push opening tag name on stack * Push opening tag name on stack
* Optionally additional data can be saved on stack * Optionally additional data can be saved on stack
* *
* @param object $compiler compiler object * @param Template $compiler compiler object
* @param string $openTag the opening tag's name * @param string $openTag the opening tag's name
* @param mixed $data optional data saved * @param mixed $data optional data saved
*/ */
protected function openTag($compiler, $openTag, $data = null) { protected function openTag(Template $compiler, $openTag, $data = null) {
array_push($compiler->_tag_stack, [$openTag, $data]); $compiler->openTag($openTag, $data);
} }
/** /**
* Pop closing tag * Pop closing tag
* Raise an error if this stack-top doesn't match with expected opening tags * Raise an error if this stack-top doesn't match with expected opening tags
* *
* @param object $compiler compiler object * @param Template $compiler compiler object
* @param array|string $expectedTag the expected opening tag names * @param array|string $expectedTag the expected opening tag names
* *
* @return mixed any type the opening tag's name or saved data * @return mixed any type the opening tag's name or saved data
*/ */
protected function closeTag($compiler, $expectedTag) { protected function closeTag(Template $compiler, $expectedTag) {
if (count($compiler->_tag_stack) > 0) { return $compiler->closeTag($expectedTag);
// get stacked info
[$_openTag, $_data] = array_pop($compiler->_tag_stack);
// open tag must match with the expected ones
if (in_array($_openTag, (array)$expectedTag)) {
if (is_null($_data)) {
// return opening tag
return $_openTag;
} else {
// return restored data
return $_data;
}
}
// wrong nesting of tags
$compiler->trigger_template_error("unclosed '" . $compiler->getTemplate()->getLeftDelimiter() . "{$_openTag}" .
$compiler->getTemplate()->getRightDelimiter() . "' tag");
return;
}
// wrong nesting of tags
$compiler->trigger_template_error('unexpected closing tag', null, true);
} }
/** /**
@@ -259,11 +224,11 @@ abstract class Base implements CompilerInterface {
* Compiles code for the tag * Compiles code for the tag
* *
* @param array $args array with attributes from parser * @param array $args array with attributes from parser
* @param \Smarty\Compiler\Template $compiler compiler object * @param Template $compiler compiler object
* @param array $parameter array with compilation parameter * @param array $parameter array with compilation parameter
* *
* @return bool|string compiled code or true if no code has been compiled * @return bool|string compiled code or true if no code has been compiled
* @throws \Smarty\CompilerException * @throws \Smarty\CompilerException
*/ */
abstract public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = array(), $tag = null, $function = null); abstract public function compile($args, Template $compiler, $parameter = array(), $tag = null, $function = null);
} }

View File

@@ -18,8 +18,6 @@ use Smarty\Smarty;
/** /**
* Smarty Internal Plugin Compile Block Plugin Class * Smarty Internal Plugin Compile Block Plugin Class
* *
*/ */
class BlockCompiler extends Base { class BlockCompiler extends Base {
@@ -62,6 +60,56 @@ class BlockCompiler extends Base {
return $output; return $output;
} }
/**
* Compiles code for the {$smarty.block.child} property
*
* @param Template $compiler compiler object
*
* @return string compiled code
* @throws CompilerException
*/
public function compileChild(\Smarty\Compiler\Template $compiler) {
if (!isset($compiler->_cache['blockNesting'])) {
$compiler->trigger_template_error(
"{\$smarty.block.child} used outside {block} tags ",
$compiler->getParser()->lex->taglineno
);
}
$compiler->has_code = true;
$compiler->suppressNocacheProcessing = true;
$output = "<?php \n";
$output .= '$_smarty_tpl->getInheritance()->callChild($_smarty_tpl, $this' . ");\n";
$output .= "?>\n";
return $output;
}
/**
* Compiles code for the {$smarty.block.parent} property
*
* @param Template $compiler compiler object
*
* @return string compiled code
* @throws CompilerException
*/
public function compileParent(\Smarty\Compiler\Template $compiler) {
if (!isset($compiler->_cache['blockNesting'])) {
$compiler->trigger_template_error(
"{\$smarty.block.parent} used outside {block} tags ",
$compiler->getParser()->lex->taglineno
);
}
$compiler->has_code = true;
$compiler->suppressNocacheProcessing = true;
$output = "<?php \n";
$output .= '$_smarty_tpl->getInheritance()->callParent($_smarty_tpl, $this' . ");\n";
$output .= "?>\n";
return $output;
}
/** /**
* Returns true if this block is cacheable. * Returns true if this block is cacheable.
* *
@@ -118,6 +166,13 @@ class BlockCompiler extends Base {
$compiler->tag_nocache = true; $compiler->tag_nocache = true;
} }
if ($compiler->tag_nocache) {
// push a {nocache} tag onto the stack to prevent caching of this block
$this->openTag($compiler, 'nocache');
}
$this->openTag($compiler, $tag, [$_params, $compiler->tag_nocache]);
// compile code // compile code
$output = "<?php \$_block_repeat=true; $output = "<?php \$_block_repeat=true;
if (!" . $this->getIsCallableCode($tag, $function) .") {\nthrow new \\Smarty\\Exception('block tag \'{$tag}\' not callable or registered');\n}\n if (!" . $this->getIsCallableCode($tag, $function) .") {\nthrow new \\Smarty\\Exception('block tag \'{$tag}\' not callable or registered');\n}\n
@@ -125,9 +180,7 @@ echo " . $this->getFullCallbackCode($tag, $function) . "({$_params}, null, \$_sm
while (\$_block_repeat) { while (\$_block_repeat) {
ob_start(); ob_start();
?>"; ?>";
$this->openTag($compiler, $tag, [$_params, $compiler->nocache]);
// maybe nocache because of nocache variables or nocache plugin
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
return $output; return $output;
} }
@@ -142,13 +195,11 @@ while (\$_block_repeat) {
* @throws Exception * @throws Exception
*/ */
private function compileClosingTag(Template $compiler, string $tag, array $parameter, ?string $function): string { private function compileClosingTag(Template $compiler, string $tag, array $parameter, ?string $function): string {
// must endblock be nocache?
if ($compiler->nocache) {
$compiler->tag_nocache = true;
}
// closing tag of block plugin, restore nocache // closing tag of block plugin, restore nocache
$base_tag = substr($tag, 0, -5); $base_tag = substr($tag, 0, -5);
[$_params, $compiler->nocache] = $this->closeTag($compiler, $base_tag); [$_params, $nocache_pushed] = $this->closeTag($compiler, $base_tag);
// compile code // compile code
if (!isset($parameter['modifier_list'])) { if (!isset($parameter['modifier_list'])) {
$mod_pre = $mod_post = $mod_content = ''; $mod_pre = $mod_post = $mod_content = '';
@@ -164,6 +215,13 @@ while (\$_block_repeat) {
$callback = $this->getFullCallbackCode($base_tag, $function); $callback = $this->getFullCallbackCode($base_tag, $function);
$output .= "echo {$callback}({$_params}, {$mod_content2}, \$_smarty_tpl, \$_block_repeat);\n"; $output .= "echo {$callback}({$_params}, {$mod_content2}, \$_smarty_tpl, \$_block_repeat);\n";
$output .= "{$mod_post}}\n?>"; $output .= "{$mod_post}}\n?>";
if ($nocache_pushed) {
// pop the pushed virtual nocache tag
$this->closeTag($compiler, 'nocache');
$compiler->tag_nocache = true;
}
return $output; return $output;
} }

View File

@@ -19,6 +19,12 @@ namespace Smarty\Compile\Tag;
*/ */
class Append extends Assign class Append extends Assign
{ {
/**
* @inheritdoc
*/
protected $optional_attributes = ['scope', 'index'];
/** /**
* Compiles code for the {append} tag * Compiles code for the {append} tag
* *
@@ -31,13 +37,10 @@ class Append extends Assign
*/ */
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = array(), $tag = null, $function = null) public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = array(), $tag = null, $function = null)
{ {
// the following must be assigned at runtime because it will be overwritten in parent class
$this->required_attributes = array('var', 'value');
$this->shorttag_order = array('var', 'value');
$this->optional_attributes = array('scope', 'index');
$this->mapCache = array();
// check and get attributes // check and get attributes
$_attr = $this->getAttributes($compiler, $args); $_attr = $this->getAttributes($compiler, $args);
// map to compile assign attributes // map to compile assign attributes
if (isset($_attr[ 'index' ])) { if (isset($_attr[ 'index' ])) {
$_params[ 'smarty_internal_index' ] = '[' . $_attr[ 'index' ] . ']'; $_params[ 'smarty_internal_index' ] = '[' . $_attr[ 'index' ] . ']';

View File

@@ -22,6 +22,21 @@ use Smarty\Smarty;
*/ */
class Assign extends Base class Assign extends Base
{ {
/**
* @inheritdoc
*/
protected $required_attributes = ['var', 'value'];
/**
* @inheritdoc
*/
protected $optional_attributes = ['scope'];
/**
* @inheritdoc
*/
protected $shorttag_order = ['var', 'value'];
/** /**
* Attribute definition: Overwrites base class. * Attribute definition: Overwrites base class.
* *
@@ -42,21 +57,17 @@ class Assign extends Base
*/ */
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = array(), $tag = null, $function = null) public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = array(), $tag = null, $function = null)
{ {
// the following must be assigned at runtime because it will be overwritten in Append
$this->required_attributes = array('var', 'value');
$this->shorttag_order = array('var', 'value');
$this->optional_attributes = array('scope');
$this->mapCache = array();
$_nocache = false; $_nocache = false;
// check and get attributes // check and get attributes
$_attr = $this->getAttributes($compiler, $args); $_attr = $this->getAttributes($compiler, $args);
// nocache ?
if ($_var = $compiler->getId($_attr[ 'var' ])) { if ($_var = $compiler->getId($_attr[ 'var' ])) {
$_var = "'{$_var}'"; $_var = "'{$_var}'";
} else { } else {
$_var = $_attr[ 'var' ]; $_var = $_attr[ 'var' ];
} }
if ($compiler->tag_nocache || $compiler->nocache) { if ($compiler->tag_nocache || $compiler->isNocacheActive()) {
$_nocache = true; $_nocache = true;
// create nocache var to make it know for further compiling // create nocache var to make it know for further compiling
$compiler->setNocacheInVariable($_attr[ 'var' ]); $compiler->setNocacheInVariable($_attr[ 'var' ]);

View File

@@ -74,20 +74,17 @@ class Block extends Inheritance {
$_attr = $this->getAttributes($compiler, $args); $_attr = $this->getAttributes($compiler, $args);
++$compiler->_cache['blockNesting']; ++$compiler->_cache['blockNesting'];
$_className = 'Block_' . preg_replace('![^\w]+!', '_', uniqid(mt_rand(), true)); $_className = 'Block_' . preg_replace('![^\w]+!', '_', uniqid(mt_rand(), true));
$compiler->_cache['blockName'][$compiler->_cache['blockNesting']] = $_attr['name'];
$compiler->_cache['blockClass'][$compiler->_cache['blockNesting']] = $_className;
$compiler->_cache['blockParams'][$compiler->_cache['blockNesting']] = [];
$compiler->_cache['blockParams'][1]['subBlocks'][trim($_attr['name'], '"\'')][] = $_className;
$this->openTag( $this->openTag(
$compiler, $compiler,
'block', 'block',
[ [
$_attr, $compiler->nocache, $compiler->getParser()->current_buffer, $_attr, $compiler->tag_nocache, $compiler->getParser()->current_buffer,
$compiler->getTemplate()->getCompiled()->getNocacheCode(), $compiler->getTemplate()->getCompiled()->getNocacheCode(), $_className
$compiler->getTemplate()->caching,
] ]
); );
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
// @TODO what is this for?
$compiler->getParser()->current_buffer = new Template(); $compiler->getParser()->current_buffer = new Template();
$compiler->getTemplate()->getCompiled()->setNocacheCode(false); $compiler->getTemplate()->getCompiled()->setNocacheCode(false);
$compiler->suppressNocacheProcessing = true; $compiler->suppressNocacheProcessing = true;

View File

@@ -1,26 +0,0 @@
<?php
/**
* This file is part of Smarty.
*
* (c) 2015 Uwe Tews
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Smarty\Compile\Tag;
/**
* Smarty Internal Plugin Compile Block Child Class
*
* @author Uwe Tews <uwe.tews@googlemail.com>
*/
class BlockChild extends Child {
/**
* Tag name
*
* @var string
*/
protected $tag = 'block_child';
}

View File

@@ -20,19 +20,11 @@ class BlockClose extends Inheritance {
*/ */
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = array(), $tag = null, $function = null) public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = array(), $tag = null, $function = null)
{ {
[$_attr, $_nocache, $_buffer, $_has_nocache_code, $_caching] = $this->closeTag($compiler, ['block']); [$_attr, $_nocache, $_buffer, $_has_nocache_code, $_className] = $this->closeTag($compiler, ['block']);
// init block parameter
$_block = $compiler->_cache['blockParams'][$compiler->_cache['blockNesting']];
unset($compiler->_cache['blockParams'][$compiler->_cache['blockNesting']]);
$_name = $_attr['name']; $_name = $_attr['name'];
$_assign = isset($_attr['assign']) ? $_attr['assign'] : null; $_assign = $_attr['assign'] ?? null;
unset($_attr['assign'], $_attr['name']);
foreach ($_attr as $name => $stat) {
if ((is_bool($stat) && $stat !== false) || (!is_bool($stat) && $stat !== 'false')) {
$_block[$name] = 'true';
}
}
$_className = $compiler->_cache['blockClass'][$compiler->_cache['blockNesting']];
// get compiled block code // get compiled block code
$_functionCode = $compiler->getParser()->current_buffer; $_functionCode = $compiler->getParser()->current_buffer;
// setup buffer for template function code // setup buffer for template function code
@@ -41,9 +33,6 @@ class BlockClose extends Inheritance {
$output .= $compiler->cStyleComment(" {block {$_name}} ") . "\n"; $output .= $compiler->cStyleComment(" {block {$_name}} ") . "\n";
$output .= "class {$_className} extends \\Smarty\\Runtime\\Block\n"; $output .= "class {$_className} extends \\Smarty\\Runtime\\Block\n";
$output .= "{\n"; $output .= "{\n";
foreach ($_block as $property => $value) {
$output .= "public \${$property} = " . var_export($value, true) . ";\n";
}
$output .= "public function callBlock(\\Smarty\\Template \$_smarty_tpl) {\n"; $output .= "public function callBlock(\\Smarty\\Template \$_smarty_tpl) {\n";
if ($compiler->getTemplate()->getCompiled()->getNocacheCode()) { if ($compiler->getTemplate()->getCompiled()->getNocacheCode()) {
$output .= "\$_smarty_tpl->getCached()->hashes['{$compiler->getTemplate()->getCompiled()->nocache_hash}'] = true;\n"; $output .= "\$_smarty_tpl->getCached()->hashes['{$compiler->getTemplate()->getCompiled()->nocache_hash}'] = true;\n";
@@ -76,11 +65,13 @@ class BlockClose extends Inheritance {
) )
); );
$compiler->blockOrFunctionCode .= $compiler->getParser()->current_buffer->to_smarty_php($compiler->getParser()); $compiler->blockOrFunctionCode .= $compiler->getParser()->current_buffer->to_smarty_php($compiler->getParser());
$compiler->getParser()->current_buffer = new Template(); $compiler->getParser()->current_buffer = new Template();
// restore old status // restore old status
$compiler->getTemplate()->getCompiled()->setNocacheCode($_has_nocache_code); $compiler->getTemplate()->getCompiled()->setNocacheCode($_has_nocache_code);
$compiler->tag_nocache = $compiler->nocache; $compiler->tag_nocache = $_nocache;
$compiler->nocache = $_nocache;
$compiler->getParser()->current_buffer = $_buffer; $compiler->getParser()->current_buffer = $_buffer;
$output = "<?php \n"; $output = "<?php \n";
if ($compiler->_cache['blockNesting'] === 1) { if ($compiler->_cache['blockNesting'] === 1) {

View File

@@ -1,33 +0,0 @@
<?php
/**
* This file is part of Smarty.
*
* (c) 2015 Uwe Tews
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Smarty\Compile\Tag;
/**
* Smarty Internal Plugin Compile Block Parent Class
*
* @author Uwe Tews <uwe.tews@googlemail.com>
*/
class BlockParent extends Child {
/**
* Tag name
*
* @var string
*/
protected $tag = 'block_parent';
/**
* Block type
*
* @var string
*/
protected $blockType = 'Parent';
}

View File

@@ -93,17 +93,20 @@ class BreakTag extends Base {
$levels = 1; $levels = 1;
} }
$level_count = $levels; $level_count = $levels;
$stack_count = count($compiler->_tag_stack) - 1;
$tagStack = $compiler->getTagStack();
$stack_count = count($tagStack) - 1;
$foreachLevels = 0; $foreachLevels = 0;
$lastTag = ''; $lastTag = '';
while ($level_count > 0 && $stack_count >= 0) { while ($level_count > 0 && $stack_count >= 0) {
if (isset($_is_loopy[$compiler->_tag_stack[$stack_count][0]])) { if (isset($_is_loopy[$tagStack[$stack_count][0]])) {
$lastTag = $compiler->_tag_stack[$stack_count][0]; $lastTag = $tagStack[$stack_count][0];
if ($level_count === 0) { if ($level_count === 0) {
break; break;
} }
$level_count--; $level_count--;
if ($compiler->_tag_stack[$stack_count][0] === 'foreach') { if ($tagStack[$stack_count][0] === 'foreach') {
$foreachLevels++; $foreachLevels++;
} }
} }

View File

@@ -59,7 +59,7 @@ class Call extends Base {
$_name = $_attr['name']; $_name = $_attr['name'];
unset($_attr['name'], $_attr['assign'], $_attr['nocache']); unset($_attr['name'], $_attr['assign'], $_attr['nocache']);
// set flag (compiled code of {function} must be included in cache file // set flag (compiled code of {function} must be included in cache file
if (!$compiler->getTemplate()->caching || $compiler->nocache || $compiler->tag_nocache) { if (!$compiler->getTemplate()->caching || $compiler->isNocacheActive() || $compiler->tag_nocache) {
$_nocache = 'true'; $_nocache = 'true';
} else { } else {
$_nocache = 'false'; $_nocache = 'false';

View File

@@ -55,13 +55,17 @@ class Capture extends Base {
*/ */
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) { public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
// check and get attributes // check and get attributes
$_attr = $this->getAttributes($compiler, $args, $parameter, 'capture'); $_attr = $this->getAttributes($compiler, $args);
$buffer = $_attr['name'] ?? "'default'"; $buffer = $_attr['name'] ?? "'default'";
$assign = $_attr['assign'] ?? 'null'; $assign = $_attr['assign'] ?? 'null';
$append = $_attr['append'] ?? 'null'; $append = $_attr['append'] ?? 'null';
$compiler->_cache['capture_stack'][] = [$compiler->nocache];
// maybe nocache because of nocache variables $compiler->_cache['capture_stack'][] = $compiler->tag_nocache;
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache; if ($compiler->tag_nocache) {
// push a virtual {nocache} tag onto the stack.
$compiler->openTag('nocache');
}
$_output = "<?php \$_smarty_tpl->getSmarty()->getRuntime('Capture')->open(\$_smarty_tpl, $buffer, $assign, $append);?>"; $_output = "<?php \$_smarty_tpl->getSmarty()->getRuntime('Capture')->open(\$_smarty_tpl, $buffer, $assign, $append);?>";
return $_output; return $_output;
} }

View File

@@ -30,13 +30,13 @@ class CaptureClose extends Base {
* @return string compiled code * @return string compiled code
*/ */
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) { public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
// check and get attributes
$_attr = $this->getAttributes($compiler, $args, $parameter, '/capture'); if (array_pop($compiler->_cache['capture_stack'])) {
// must endblock be nocache? // pop the virtual {nocache} tag from the stack.
if ($compiler->nocache) { $compiler->closeTag('nocache');
$compiler->tag_nocache = true; $compiler->tag_nocache = true;
} }
[$compiler->nocache] = array_pop($compiler->_cache['capture_stack']);
return "<?php \$_smarty_tpl->getSmarty()->getRuntime('Capture')->close(\$_smarty_tpl);?>"; return "<?php \$_smarty_tpl->getSmarty()->getRuntime('Capture')->close(\$_smarty_tpl);?>";
} }
} }

View File

@@ -1,82 +0,0 @@
<?php
/**
* This file is part of Smarty.
*
* (c) 2015 Uwe Tews
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Smarty\Compile\Tag;
use Smarty\Compile\Base;
/**
* Smarty Internal Plugin Compile Child Class
*
* @author Uwe Tews <uwe.tews@googlemail.com>
*/
class Child extends Base {
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see BasePlugin
*/
protected $optional_attributes = ['assign'];
/**
* Tag name
*
* @var string
*/
protected $tag = 'child';
/**
* Block type
*
* @var string
*/
protected $blockType = 'Child';
/**
* Compiles code for the {child} tag
*
* @param array $args array with attributes from parser
* @param \Smarty\Compiler\Template $compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return string compiled code
* @throws \Smarty\CompilerException
*/
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
$tag = isset($parameter[0]) ? "'{$parameter[0]}'" : "'{{$this->tag}}'";
if (!isset($compiler->_cache['blockNesting'])) {
$compiler->trigger_template_error(
"{$tag} used outside {block} tags ",
$compiler->getParser()->lex->taglineno
);
}
$compiler->has_code = true;
$compiler->suppressNocacheProcessing = true;
if ($this->blockType === 'Child') {
$compiler->_cache['blockParams'][$compiler->_cache['blockNesting']]['callsChild'] = 'true';
}
$_assign = $_attr['assign'] ?? null;
$output = "<?php \n";
if (isset($_assign)) {
$output .= "ob_start();\n";
}
$output .= '$_smarty_tpl->getInheritance()->call' . $this->blockType . '($_smarty_tpl, $this' .
($this->blockType === 'Child' ? '' : ", {$tag}") . ");\n";
if (isset($_assign)) {
$output .= "\$_smarty_tpl->assign({$_assign}, ob_get_clean());\n";
}
$output .= "?>\n";
return $output;
}
}

View File

@@ -23,9 +23,9 @@ class ElseIfTag extends Base {
* @throws \Smarty\CompilerException * @throws \Smarty\CompilerException
*/ */
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) { public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
// check and get attributes
$_attr = $this->getAttributes($compiler, $args); [$nesting, $nocache_pushed] = $this->closeTag($compiler, ['if', 'elseif']);
[$nesting, $compiler->tag_nocache] = $this->closeTag($compiler, ['if', 'elseif']);
if (!isset($parameter['if condition'])) { if (!isset($parameter['if condition'])) {
$compiler->trigger_template_error('missing elseif condition', null, true); $compiler->trigger_template_error('missing elseif condition', null, true);
} }
@@ -38,7 +38,7 @@ class ElseIfTag extends Base {
} else { } else {
$var = $parameter['if condition']['var']; $var = $parameter['if condition']['var'];
} }
if ($compiler->nocache) { if ($compiler->isNocacheActive()) {
// create nocache var to make it know for further compiling // create nocache var to make it know for further compiling
$compiler->setNocacheInVariable($var); $compiler->setNocacheInVariable($var);
} }
@@ -68,12 +68,12 @@ class ElseIfTag extends Base {
$_output = $compiler->appendCode("<?php } else {\n?>", $assignCode); $_output = $compiler->appendCode("<?php } else {\n?>", $assignCode);
return $compiler->appendCode($_output, "<?php if ({$prefixVar}) {?>"); return $compiler->appendCode($_output, "<?php if ({$prefixVar}) {?>");
} else { } else {
$this->openTag($compiler, 'elseif', [$nesting, $compiler->tag_nocache]); $this->openTag($compiler, 'elseif', [$nesting, $nocache_pushed]);
return "<?php } elseif ({$parameter['if condition']}) {?>"; return "<?php } elseif ({$parameter['if condition']}) {?>";
} }
} else { } else {
$_output = $compiler->appendCode("<?php } else {\n?>", $prefixCode); $_output = $compiler->appendCode("<?php } else {\n?>", $prefixCode);
$this->openTag($compiler, 'elseif', [$nesting + 1, $compiler->tag_nocache]); $this->openTag($compiler, 'elseif', [$nesting + 1, $nocache_pushed]);
if ($condition_by_assign) { if ($condition_by_assign) {
$_output = $compiler->appendCode($_output, $assignCode); $_output = $compiler->appendCode($_output, $assignCode);
return $compiler->appendCode($_output, "<?php if ({$prefixVar}) {?>"); return $compiler->appendCode($_output, "<?php if ({$prefixVar}) {?>");

View File

@@ -31,18 +31,20 @@ class ForClose extends Base {
*/ */
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) { public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
$compiler->loopNesting--; $compiler->loopNesting--;
// check and get attributes
$this->getAttributes($compiler, $args); [$openTag, $nocache_pushed] = $this->closeTag($compiler, ['for', 'forelse']);
// must endblock be nocache?
if ($compiler->nocache) {
$compiler->tag_nocache = true;
}
[$openTag, $compiler->nocache] = $this->closeTag($compiler, ['for', 'forelse']);
$output = "<?php }\n"; $output = "<?php }\n";
if ($openTag !== 'forelse') { if ($openTag !== 'forelse') {
$output .= "}\n"; $output .= "}\n";
} }
$output .= "?>"; $output .= "?>";
if ($nocache_pushed) {
// pop the pushed virtual nocache tag
$this->closeTag('nocache');
$compiler->tag_nocache = true;
}
return $output; return $output;
} }
} }

View File

@@ -22,10 +22,8 @@ class ForElse extends Base {
* @return string compiled code * @return string compiled code
*/ */
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) { public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
// check and get attributes [$tagName, $nocache_pushed] = $this->closeTag($compiler, ['for']);
$this->getAttributes($compiler, $args); $this->openTag($compiler, 'forelse', ['forelse', $nocache_pushed]);
[$openTag, $nocache] = $this->closeTag($compiler, ['for']);
$this->openTag($compiler, 'forelse', ['forelse', $nocache]);
return "<?php }} else { ?>"; return "<?php }} else { ?>";
} }
} }

View File

@@ -37,7 +37,7 @@ class ForTag extends Base {
$this->required_attributes = ['start', 'ifexp', 'var', 'step']; $this->required_attributes = ['start', 'ifexp', 'var', 'step'];
$this->optional_attributes = []; $this->optional_attributes = [];
} }
$this->mapCache = [];
// check and get attributes // check and get attributes
$_attr = $this->getAttributes($compiler, $args); $_attr = $this->getAttributes($compiler, $args);
$output = "<?php\n"; $output = "<?php\n";
@@ -87,10 +87,14 @@ class ForTag extends Base {
$output .= "\$_smarty_tpl->tpl_vars[$var]->last = \$_smarty_tpl->tpl_vars[$var]->iteration === \$_smarty_tpl->tpl_vars[$var]->total;"; $output .= "\$_smarty_tpl->tpl_vars[$var]->last = \$_smarty_tpl->tpl_vars[$var]->iteration === \$_smarty_tpl->tpl_vars[$var]->total;";
} }
$output .= '?>'; $output .= '?>';
$this->openTag($compiler, 'for', ['for', $compiler->nocache]);
// maybe nocache because of nocache variables if ($compiler->tag_nocache) {
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache; // push a {nocache} tag onto the stack to prevent caching of this for loop
// return compiled code $this->openTag('nocache');
}
$this->openTag($compiler, 'for', ['for', $compiler->tag_nocache]);
return $output; return $output;
} }
} }

View File

@@ -31,13 +31,15 @@ class ForeachClose extends Base {
*/ */
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) { public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
$compiler->loopNesting--; $compiler->loopNesting--;
// must endblock be nocache?
if ($compiler->nocache) { [$openTag, $nocache_pushed, $local, $itemVar, $restore] = $this->closeTag($compiler, ['foreach', 'foreachelse']);
if ($nocache_pushed) {
// pop the pushed virtual nocache tag
$this->closeTag('nocache');
$compiler->tag_nocache = true; $compiler->tag_nocache = true;
} }
[
$openTag, $compiler->nocache, $local, $itemVar, $restore,
] = $this->closeTag($compiler, ['foreach', 'foreachelse']);
$output = "<?php\n"; $output = "<?php\n";
if ($restore === 2) { if ($restore === 2) {
$output .= "{$itemVar} = {$local}saved;\n"; $output .= "{$itemVar} = {$local}saved;\n";

View File

@@ -21,10 +21,9 @@ class ForeachElse extends Base {
* @return string compiled code * @return string compiled code
*/ */
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) { public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
// check and get attributes
$this->getAttributes($compiler, $args); [$openTag, $nocache_pushed, $local, $itemVar, $restore] = $this->closeTag($compiler, ['foreach']);
[$openTag, $nocache, $local, $itemVar, $restore] = $this->closeTag($compiler, ['foreach']); $this->openTag($compiler, 'foreachelse', ['foreachelse', $nocache_pushed, $local, $itemVar, 0]);
$this->openTag($compiler, 'foreachelse', ['foreachelse', $nocache, $local, $itemVar, 0]);
$output = "<?php\n"; $output = "<?php\n";
if ($restore === 2) { if ($restore === 2) {
$output .= "{$itemVar} = {$local}saved;\n"; $output .= "{$itemVar} = {$local}saved;\n";

View File

@@ -181,14 +181,19 @@ class ForeachTag extends ForeachSection {
$foreachVar = "\$_smarty_tpl->tpl_vars['__smarty_foreach_{$attributes['name']}']"; $foreachVar = "\$_smarty_tpl->tpl_vars['__smarty_foreach_{$attributes['name']}']";
} }
$needTotal = isset($itemAttr['total']); $needTotal = isset($itemAttr['total']);
if ($compiler->tag_nocache) {
// push a {nocache} tag onto the stack to prevent caching of this block
$this->openTag('nocache');
}
// Register tag // Register tag
$this->openTag( $this->openTag(
$compiler, $compiler,
'foreach', 'foreach',
['foreach', $compiler->nocache, $local, $itemVar, empty($itemAttr) ? 1 : 2] ['foreach', $compiler->tag_nocache, $local, $itemVar, empty($itemAttr) ? 1 : 2]
); );
// maybe nocache because of nocache variables
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
// generate output code // generate output code
$output = "<?php\n"; $output = "<?php\n";
$output .= "\$_from = \$_smarty_tpl->getSmarty()->getRuntime('Foreach')->init(\$_smarty_tpl, $from, " . $output .= "\$_from = \$_smarty_tpl->getSmarty()->getRuntime('Foreach')->init(\$_smarty_tpl, $from, " .

View File

@@ -29,11 +29,15 @@ class IfClose extends Base {
* @return string compiled code * @return string compiled code
*/ */
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) { public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
// must endblock be nocache?
if ($compiler->nocache) { [$nesting, $nocache_pushed] = $this->closeTag($compiler, ['if', 'else', 'elseif']);
if ($nocache_pushed) {
// pop the pushed virtual nocache tag
$this->closeTag('nocache');
$compiler->tag_nocache = true; $compiler->tag_nocache = true;
} }
[$nesting, $compiler->nocache] = $this->closeTag($compiler, ['if', 'else', 'elseif']);
$tmp = ''; $tmp = '';
for ($i = 0; $i < $nesting; $i++) { for ($i = 0; $i < $nesting; $i++) {
$tmp .= '}'; $tmp .= '}';

View File

@@ -23,11 +23,14 @@ class IfTag extends Base {
* @throws \Smarty\CompilerException * @throws \Smarty\CompilerException
*/ */
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) { public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
// check and get attributes
$_attr = $this->getAttributes($compiler, $args); if ($compiler->tag_nocache) {
$this->openTag($compiler, 'if', [1, $compiler->nocache]); // push a {nocache} tag onto the stack to prevent caching of this block
// must whole block be nocache ? $this->openTag('nocache');
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache; }
$this->openTag($compiler, 'if', [1, $compiler->tag_nocache]);
if (!isset($parameter['if condition'])) { if (!isset($parameter['if condition'])) {
$compiler->trigger_template_error('missing if condition', null, true); $compiler->trigger_template_error('missing if condition', null, true);
} }
@@ -37,7 +40,7 @@ class IfTag extends Base {
} else { } else {
$var = $parameter['if condition']['var']; $var = $parameter['if condition']['var'];
} }
if ($compiler->nocache) { if ($compiler->isNocacheActive()) {
// create nocache var to make it know for further compiling // create nocache var to make it know for further compiling
$compiler->setNocacheInVariable($var); $compiler->setNocacheInVariable($var);
} }

View File

@@ -111,11 +111,13 @@ class IncludeTag extends Base {
// assume caching is off // assume caching is off
$_caching = Smarty::CACHING_OFF; $_caching = Smarty::CACHING_OFF;
$call_nocache = $compiler->tag_nocache || $compiler->nocache;
// caching was on and {include} is not in nocache mode // caching was on and {include} is not in nocache mode
if ($compiler->getTemplate()->caching && !$compiler->nocache && !$compiler->tag_nocache) { // @TODO see if we can do without this
if ($compiler->getTemplate()->caching && !$compiler->isNocacheActive()) {
$_caching = \Smarty\Template::CACHING_NOCACHE_CODE; $_caching = \Smarty\Template::CACHING_NOCACHE_CODE;
} }
// flag if included template code should be merged into caller // flag if included template code should be merged into caller
$merge_compiled_includes = ($compiler->getSmarty()->merge_compiled_includes || $_attr['inline'] === true) && $merge_compiled_includes = ($compiler->getSmarty()->merge_compiled_includes || $_attr['inline'] === true) &&
!$compiler->getTemplate()->getSource()->handler->recompiled; !$compiler->getTemplate()->getSource()->handler->recompiled;
@@ -125,12 +127,15 @@ class IncludeTag extends Base {
$merge_compiled_includes = false; $merge_compiled_includes = false;
} }
} }
/* /*
* if the {include} tag provides individual parameter for caching or compile_id * if the {include} tag provides individual parameter for caching or compile_id
* the subtemplate must not be included into the common cache file and is treated like * the subtemplate must not be included into the common cache file and is treated like
* a call in nocache mode. * a call in nocache mode.
* *
*/ */
$call_nocache = $compiler->isNocacheActive();
if ($_attr['nocache'] !== true && $_attr['caching']) { if ($_attr['nocache'] !== true && $_attr['caching']) {
$_caching = $_new_caching = (int)$_attr['caching']; $_caching = $_new_caching = (int)$_attr['caching'];
$call_nocache = true; $call_nocache = true;
@@ -161,7 +166,7 @@ class IncludeTag extends Base {
// output will be stored in a smarty variable instead of being displayed // output will be stored in a smarty variable instead of being displayed
if ($_assign = $compiler->getId($_attr['assign'])) { if ($_assign = $compiler->getId($_attr['assign'])) {
$_assign = "'{$_assign}'"; $_assign = "'{$_assign}'";
if ($compiler->tag_nocache || $compiler->nocache || $call_nocache) { if ($call_nocache) {
// create nocache var to make it know for further compiling // create nocache var to make it know for further compiling
$compiler->setNocacheInVariable($_attr['assign']); $compiler->setNocacheInVariable($_attr['assign']);
} }
@@ -281,7 +286,7 @@ class IncludeTag extends Base {
$compiled_code = "<?php\n\n"; $compiled_code = "<?php\n\n";
$compiled_code .= $compiler->cStyleComment(" Start inline template \"{$sourceInfo}\" =============================") . "\n"; $compiled_code .= $compiler->cStyleComment(" Start inline template \"{$sourceInfo}\" =============================") . "\n";
$compiled_code .= "function {$tpl->getCompiled()->unifunc} (\\Smarty\\Template \$_smarty_tpl) {\n"; $compiled_code .= "function {$tpl->getCompiled()->unifunc} (\\Smarty\\Template \$_smarty_tpl) {\n";
$compiled_code .= "?>\n" . $tpl->getCompiler()->compileTemplateSource($tpl, null, $compiler->getParentCompiler()); $compiled_code .= "?>\n" . $tpl->getCompiler()->compileTemplateSource($tpl, $compiler->getParentCompiler());
$compiled_code .= "<?php\n"; $compiled_code .= "<?php\n";
$compiled_code .= "}\n?>\n"; $compiled_code .= "}\n?>\n";
$compiled_code .= $tpl->getSmarty()->runPostFilters($tpl->getCompiler()->blockOrFunctionCode, $tpl); $compiled_code .= $tpl->getSmarty()->runPostFilters($tpl->getCompiler()->blockOrFunctionCode, $tpl);

View File

@@ -29,10 +29,7 @@ class Nocache extends Base {
* @return bool * @return bool
*/ */
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) { public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
$this->getAttributes($compiler, $args); $this->openTag($compiler, 'nocache');
$this->openTag($compiler, 'nocache', [$compiler->nocache]);
// enter nocache mode
$compiler->nocache = true;
// this tag does not return compiled code // this tag does not return compiled code
$compiler->has_code = false; $compiler->has_code = false;
return true; return true;

View File

@@ -30,9 +30,7 @@ class NocacheClose extends Base {
* @return bool * @return bool
*/ */
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) { public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
$_attr = $this->getAttributes($compiler, $args); $this->closeTag($compiler, ['nocache']);
// leave nocache mode
[$compiler->nocache] = $this->closeTag($compiler, ['nocache']);
// this tag does not return compiled code // this tag does not return compiled code
$compiler->has_code = false; $compiler->has_code = false;
return true; return true;

View File

@@ -1,33 +0,0 @@
<?php
/**
* This file is part of Smarty.
*
* (c) 2015 Uwe Tews
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Smarty\Compile\Tag;
/**
* Smarty Internal Plugin Compile Parent Class
*
* @author Uwe Tews <uwe.tews@googlemail.com>
*/
class ParentTag extends Child {
/**
* Tag name
*
* @var string
*/
protected $tag = 'parent';
/**
* Block type
*
* @var string
*/
protected $blockType = 'Parent';
}

View File

@@ -95,9 +95,14 @@ class Section extends ForeachSection {
} }
$local = "\$__section_{$attributes['name']}_" . $this->counter++ . '_'; $local = "\$__section_{$attributes['name']}_" . $this->counter++ . '_';
$sectionVar = "\$_smarty_tpl->tpl_vars['__smarty_section_{$attributes['name']}']"; $sectionVar = "\$_smarty_tpl->tpl_vars['__smarty_section_{$attributes['name']}']";
$this->openTag($compiler, 'section', ['section', $compiler->nocache, $local, $sectionVar]);
// maybe nocache because of nocache variables if ($compiler->tag_nocache) {
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache; // push a {nocache} tag onto the stack to prevent caching of this block
$this->openTag('nocache');
}
$this->openTag($compiler, 'section', ['section', $compiler->tag_nocache]);
$initLocal = []; $initLocal = [];
$initNamedProperty = []; $initNamedProperty = [];
$initFor = []; $initFor = [];

View File

@@ -14,9 +14,6 @@ use Smarty\Compile\Base;
/** /**
* Smarty Internal Plugin Compile Sectionclose Class * Smarty Internal Plugin Compile Sectionclose Class
*
*/ */
class SectionClose extends Base { class SectionClose extends Base {
@@ -30,12 +27,14 @@ class SectionClose extends Base {
*/ */
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) { public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
$compiler->loopNesting--; $compiler->loopNesting--;
// must endblock be nocache?
if ($compiler->nocache) { [$openTag, $nocache_pushed] = $this->closeTag($compiler, ['section', 'sectionelse']);
$compiler->tag_nocache = true;
if ($nocache_pushed) {
// pop the pushed virtual nocache tag
$this->closeTag('nocache');
} }
[$openTag, $compiler->nocache, $local, $sectionVar] =
$this->closeTag($compiler, ['section', 'sectionelse']);
$output = "<?php\n"; $output = "<?php\n";
if ($openTag === 'sectionelse') { if ($openTag === 'sectionelse') {
$output .= "}\n"; $output .= "}\n";

View File

@@ -21,10 +21,8 @@ class SectionElse extends Base {
* @return string compiled code * @return string compiled code
*/ */
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) { public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
// check and get attributes [$openTag, $nocache_pushed] = $this->closeTag($compiler, ['section']);
$this->getAttributes($compiler, $args); $this->openTag($compiler, 'sectionelse', ['sectionelse', $nocache_pushed]);
[$openTag, $nocache, $local, $sectionVar] = $this->closeTag($compiler, ['section']);
$this->openTag($compiler, 'sectionelse', ['sectionelse', $nocache, $local, $sectionVar]);
return "<?php }} else {\n ?>"; return "<?php }} else {\n ?>";
} }
} }

View File

@@ -30,11 +30,15 @@ class WhileClose extends Base {
*/ */
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) { public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
$compiler->loopNesting--; $compiler->loopNesting--;
// must endblock be nocache?
if ($compiler->nocache) { $nocache_pushed = $this->closeTag($compiler, ['while']);
if ($nocache_pushed) {
// pop the pushed virtual nocache tag
$this->closeTag('nocache');
$compiler->tag_nocache = true; $compiler->tag_nocache = true;
} }
$compiler->nocache = $this->closeTag($compiler, ['while']);
return "<?php }?>\n"; return "<?php }?>\n";
} }
} }

View File

@@ -24,16 +24,20 @@ class WhileTag extends Base {
*/ */
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) { public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
$compiler->loopNesting++; $compiler->loopNesting++;
// check and get attributes
$_attr = $this->getAttributes($compiler, $args); if ($compiler->tag_nocache) {
$this->openTag($compiler, 'while', $compiler->nocache); // push a {nocache} tag onto the stack to prevent caching of this block
$this->openTag('nocache');
}
$this->openTag($compiler, 'while', $compiler->tag_nocache);
if (!array_key_exists('if condition', $parameter)) { if (!array_key_exists('if condition', $parameter)) {
$compiler->trigger_template_error('missing while condition', null, true); $compiler->trigger_template_error('missing while condition', null, true);
} }
// maybe nocache because of nocache variables
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
if (is_array($parameter['if condition'])) { if (is_array($parameter['if condition'])) {
if ($compiler->nocache) { if ($compiler->isNocacheActive()) {
// create nocache var to make it know for further compiling // create nocache var to make it know for further compiling
if (is_array($parameter['if condition']['var'])) { if (is_array($parameter['if condition']['var'])) {
$var = $parameter['if condition']['var']['var']; $var = $parameter['if condition']['var']['var'];

View File

@@ -17,6 +17,7 @@ use Smarty\Compile\ModifierCompiler;
use Smarty\Compile\ObjectMethodBlockCompiler; use Smarty\Compile\ObjectMethodBlockCompiler;
use Smarty\Compile\ObjectMethodCallCompiler; use Smarty\Compile\ObjectMethodCallCompiler;
use Smarty\Compile\FunctionCallCompiler; use Smarty\Compile\FunctionCallCompiler;
use Smarty\Compile\PrintExpressionCompiler;
use Smarty\Lexer\TemplateLexer; use Smarty\Lexer\TemplateLexer;
use Smarty\Parser\TemplateParser; use Smarty\Parser\TemplateParser;
use Smarty\Smarty; use Smarty\Smarty;
@@ -76,14 +77,14 @@ class Template extends BaseCompiler {
* *
* @var array * @var array
*/ */
public $_tag_stack = []; private $_tag_stack = [];
/** /**
* tag stack count * tag stack count
* *
* @var array * @var array
*/ */
public $_tag_stack_count = []; private $_tag_stack_count = [];
/** /**
* current template * current template
@@ -308,6 +309,17 @@ class Template extends BaseCompiler {
* @var ModifierCompiler * @var ModifierCompiler
*/ */
private $modifierCompiler; private $modifierCompiler;
/**
* @var PrintExpressionCompiler
*/
private $printExpressionCompiler;
/**
* Depth of nested {nocache}{/nocache} blocks. If outside, this is 0. If inside, this is 1 or higher (if nested).
* @var int
*/
private $noCacheStackDepth = 0;
/** /**
* Initialize compiler * Initialize compiler
@@ -332,53 +344,38 @@ class Template extends BaseCompiler {
$this->defaultHandlerBlockCompiler = new DefaultHandlerBlockCompiler(); $this->defaultHandlerBlockCompiler = new DefaultHandlerBlockCompiler();
$this->objectMethodBlockCompiler = new ObjectMethodBlockCompiler(); $this->objectMethodBlockCompiler = new ObjectMethodBlockCompiler();
$this->objectMethodCallCompiler = new ObjectMethodCallCompiler(); $this->objectMethodCallCompiler = new ObjectMethodCallCompiler();
$this->printExpressionCompiler = new PrintExpressionCompiler();
} }
/** /**
* Method to compile a Smarty template * Method to compile a Smarty template
* *
* @param Smarty\Template $template template object to compile * @param \Smarty\Template $template template object to compile
* @param null $nocache true is shall be compiled in nocache mode
* @param null|Template $parent_compiler
* *
* @return bool true if compiling succeeded, false if it failed * @return bool true if compiling succeeded, false if it failed
* @throws Exception * @throws Exception
*/ */
public function compileTemplate( public function compileTemplate(\Smarty\Template $template) {
\Smarty\Template $template, return $template->createCodeFrame(
$nocache = null, $this->compileTemplateSource($template),
\Smarty\Compiler\Template $parent_compiler = null
) {
// get code frame of compiled template
$_compiled_code = $template->createCodeFrame(
$this->compileTemplateSource(
$template,
$nocache,
$parent_compiler
),
$this->smarty->runPostFilters($this->blockOrFunctionCode, $this->template) . $this->smarty->runPostFilters($this->blockOrFunctionCode, $this->template) .
join('', $this->mergedSubTemplatesCode), join('', $this->mergedSubTemplatesCode),
false, false,
$this $this
); );
return $_compiled_code;
} }
/** /**
* Compile template source and run optional post filter * Compile template source and run optional post filter
* *
* @param \Smarty\Template $template * @param \Smarty\Template $template
* @param null|bool $nocache flag if template must be compiled in nocache mode * @param Template|null $parent_compiler
* @param \Smarty\Compiler\Template $parent_compiler
* *
* @return string * @return string
* @throws \Exception * @throws CompilerException
* @throws Exception
*/ */
public function compileTemplateSource( public function compileTemplateSource(\Smarty\Template $template, \Smarty\Compiler\Template $parent_compiler = null) {
\Smarty\Template $template,
$nocache = null,
\Smarty\Compiler\Template $parent_compiler = null
) {
try { try {
// save template object in compiler class // save template object in compiler class
$this->template = $template; $this->template = $template;
@@ -386,18 +383,20 @@ class Template extends BaseCompiler {
$this->smarty->getDebug()->start_compile($this->template); $this->smarty->getDebug()->start_compile($this->template);
} }
$this->parent_compiler = $parent_compiler ? $parent_compiler : $this; $this->parent_compiler = $parent_compiler ? $parent_compiler : $this;
$nocache = isset($nocache) ? $nocache : false;
if (empty($template->getCompiled()->nocache_hash)) { if (empty($template->getCompiled()->nocache_hash)) {
$template->getCompiled()->nocache_hash = $this->nocache_hash; $template->getCompiled()->nocache_hash = $this->nocache_hash;
} else { } else {
$this->nocache_hash = $template->getCompiled()->nocache_hash; $this->nocache_hash = $template->getCompiled()->nocache_hash;
} }
$this->caching = $template->caching; $this->caching = $template->caching;
// flag for nocache sections // flag for nocache sections
$this->nocache = $nocache; $this->nocache = false;
$this->tag_nocache = false; $this->tag_nocache = false;
// reset has nocache code flag // reset has nocache code flag
$this->template->getCompiled()->setNocacheCode(false); $this->template->getCompiled()->setNocacheCode(false);
$this->has_variable_string = false; $this->has_variable_string = false;
$this->prefix_code = []; $this->prefix_code = [];
// add file dependency // add file dependency
@@ -715,8 +714,7 @@ class Template extends BaseCompiler {
if (!empty($content) if (!empty($content)
&& !($this->template->getSource()->handler->recompiled) && !($this->template->getSource()->handler->recompiled)
&& $this->caching && $this->caching
&& !$this->suppressNocacheProcessing && $this->isNocacheActive()
&& ($this->nocache || $this->tag_nocache)
) { ) {
$this->template->getCompiled()->setNocacheCode(true); $this->template->getCompiled()->setNocacheCode(true);
$_output = addcslashes($content, '\'\\'); $_output = addcslashes($content, '\'\\');
@@ -1075,21 +1073,14 @@ class Template extends BaseCompiler {
return '/*' . str_replace('*/', '* /', $string) . '*/'; return '/*' . str_replace('*/', '* /', $string) . '*/';
} }
private function argsContainNocache(array $args): bool { public function compileChildBlock() {
foreach ($args as $arg) { $this->has_code = true;
if (!is_array($arg)) { return $this->blockCompiler->compileChild($this);
if ($arg === "'nocache'" || $arg === 'nocache') {
return true;
} }
} else {
foreach ($arg as $k => $v) { public function compileParentBlock() {
if (($k === "'nocache'" || $k === 'nocache') && (trim($v, "'\" ") === 'true')) { $this->has_code = true;
return true; return $this->blockCompiler->compileParent($this);
}
}
}
}
return false;
} }
/** /**
@@ -1108,17 +1099,16 @@ class Template extends BaseCompiler {
// assume that tag does compile into code, but creates no HTML output // assume that tag does compile into code, but creates no HTML output
$this->has_code = true; $this->has_code = true;
// check nocache option flag $this->handleNocacheFlag($args);
if ($this->argsContainNocache($args)) {
$this->tag_nocache = true;
}
// compile built-in tags // compile built-in tags
if ($tagCompiler = $this->getTagCompiler($tag)) { if ($tagCompiler = $this->getTagCompiler($tag)) {
if (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this)) { if (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this)) {
$this->tag_nocache = !$tagCompiler->isCacheable(); $this->tag_nocache = !$tagCompiler->isCacheable();
$_output = $tagCompiler->compile($args, $this, $parameter); $_output = $tagCompiler->compile($args, $this, $parameter);
return $this->has_code ? $_output : null; if ($_output !== false) {
return $this->has_code && $_output !== true ? $_output : null;
}
} }
} }
@@ -1190,6 +1180,21 @@ class Template extends BaseCompiler {
$this->trigger_template_error("unknown tag '{$tag}'", null, true); $this->trigger_template_error("unknown tag '{$tag}'", null, true);
} }
/**
* Sets $this->tag_nocache if attributes contain the 'nocache' flag.
*
* @param array $attributes
*
* @return void
*/
private function handleNocacheFlag(array $attributes) {
foreach ($attributes as $value) {
if (is_string($value) && trim($value, '\'" ') == 'nocache') {
$this->tag_nocache = true;
}
}
}
private function getBaseTag($tag) { private function getBaseTag($tag) {
if (strlen($tag) < 6 || substr($tag, -5) !== 'close') { if (strlen($tag) < 6 || substr($tag, -5) !== 'close') {
return $tag; return $tag;
@@ -1198,6 +1203,24 @@ class Template extends BaseCompiler {
} }
} }
/**
* Compiles the output of a variable or expression.
*
* @param $value
* @param $attributes
* @param $modifiers
*
* @return string
* @throws Exception
*/
public function compilePrintExpression($value, $attributes = [], $modifiers = null) {
$this->handleNocacheFlag($attributes);
return $this->printExpressionCompiler->compile($attributes, $this, [
'value'=> $value,
'modifierlist' => $modifiers,
]);
}
/** /**
* method to compile a Smarty template * method to compile a Smarty template
* *
@@ -1256,7 +1279,7 @@ class Template extends BaseCompiler {
mb_internal_encoding($mbEncoding); mb_internal_encoding($mbEncoding);
} }
// check for unclosed tags // check for unclosed tags
if (count($this->_tag_stack) > 0) { if ($this->getTagStackCount() > 0) {
// get stacked info // get stacked info
[$openTag, $_data] = array_pop($this->_tag_stack); [$openTag, $_data] = array_pop($this->_tag_stack);
$this->trigger_template_error( $this->trigger_template_error(
@@ -1405,4 +1428,72 @@ class Template extends BaseCompiler {
$this->parent_compiler = $parent_compiler; $this->parent_compiler = $parent_compiler;
} }
/**
* Push opening tag name on stack
* Optionally additional data can be saved on stack
*
* @param string $openTag the opening tag's name
* @param mixed $data optional data saved
*/
public function openTag($openTag, $data = null) {
$this->_tag_stack[] = [$openTag, $data];
if ($openTag == 'nocache') {
$this->noCacheStackDepth++;
}
}
/**
* Pop closing tag
* Raise an error if this stack-top doesn't match with expected opening tags
*
* @param array|string $expectedTag the expected opening tag names
*
* @return mixed any type the opening tag's name or saved data
* @throws CompilerException
*/
public function closeTag($expectedTag) {
if ($this->getTagStackCount() > 0) {
// get stacked info
[$_openTag, $_data] = array_pop($this->_tag_stack);
// open tag must match with the expected ones
if (in_array($_openTag, (array)$expectedTag)) {
if ($_openTag == 'nocache') {
$this->noCacheStackDepth--;
}
if (is_null($_data)) {
// return opening tag
return $_openTag;
} else {
// return restored data
return $_data;
}
}
// wrong nesting of tags
$this->trigger_template_error("unclosed '" . $this->getTemplate()->getLeftDelimiter() . "{$_openTag}" .
$this->getTemplate()->getRightDelimiter() . "' tag");
return;
}
// wrong nesting of tags
$this->trigger_template_error('unexpected closing tag', null, true);
}
/**
* Returns true if we are in a {nocache}...{/nocache} block, but false if inside {block} tag inside a {nocache} block...
* @return bool
*/
public function isNocacheActive(): bool {
return !$this->suppressNocacheProcessing && ($this->noCacheStackDepth > 0 || $this->tag_nocache);
}
/**
* Returns the full tag stack, used in the compiler for {break}
* @return array
*/
public function getTagStack(): array {
return $this->_tag_stack;
}
} }

View File

@@ -13,9 +13,6 @@ class CoreExtension extends Base {
case 'call': return new \Smarty\Compile\Tag\Call(); case 'call': return new \Smarty\Compile\Tag\Call();
case 'capture': return new \Smarty\Compile\Tag\Capture(); case 'capture': return new \Smarty\Compile\Tag\Capture();
case 'captureclose': return new \Smarty\Compile\Tag\CaptureClose(); case 'captureclose': return new \Smarty\Compile\Tag\CaptureClose();
case 'child': return new \Smarty\Compile\Tag\Child();
case 'block_child': return new \Smarty\Compile\Tag\BlockChild();
case 'block_parent': return new \Smarty\Compile\Tag\BlockParent();
case 'config_load': return new \Smarty\Compile\Tag\ConfigLoad(); case 'config_load': return new \Smarty\Compile\Tag\ConfigLoad();
case 'continue': return new \Smarty\Compile\Tag\ContinueTag(); case 'continue': return new \Smarty\Compile\Tag\ContinueTag();
case 'debug': return new \Smarty\Compile\Tag\Debug(); case 'debug': return new \Smarty\Compile\Tag\Debug();
@@ -38,7 +35,6 @@ class CoreExtension extends Base {
case 'rdelim': return new \Smarty\Compile\Tag\Rdelim(); case 'rdelim': return new \Smarty\Compile\Tag\Rdelim();
case 'nocache': return new \Smarty\Compile\Tag\Nocache(); case 'nocache': return new \Smarty\Compile\Tag\Nocache();
case 'nocacheclose': return new \Smarty\Compile\Tag\NocacheClose(); case 'nocacheclose': return new \Smarty\Compile\Tag\NocacheClose();
case 'parent': return new \Smarty\Compile\Tag\ParentTag();
case 'section': return new \Smarty\Compile\Tag\Section(); case 'section': return new \Smarty\Compile\Tag\Section();
case 'sectionelse': return new \Smarty\Compile\Tag\SectionElse(); case 'sectionelse': return new \Smarty\Compile\Tag\SectionElse();
case 'sectionclose': return new \Smarty\Compile\Tag\SectionClose(); case 'sectionclose': return new \Smarty\Compile\Tag\SectionClose();

View File

@@ -28,7 +28,7 @@ class Dq extends Base
{ {
$this->subtrees[] = $subtree; $this->subtrees[] = $subtree;
if ($subtree instanceof Tag) { if ($subtree instanceof Tag) {
$parser->block_nesting_level = count($parser->compiler->_tag_stack); $parser->block_nesting_level = $parser->compiler->getTagStackCount();
} }
} }
@@ -64,7 +64,7 @@ class Dq extends Base
$this->subtrees[] = $subtree; $this->subtrees[] = $subtree;
} }
if ($subtree instanceof Tag) { if ($subtree instanceof Tag) {
$parser->block_nesting_level = count($parser->compiler->_tag_stack); $parser->block_nesting_level = $parser->compiler->getTagStackCount();
} }
} }

View File

@@ -64,7 +64,7 @@ class Tag extends Base
$var = $parser->compiler->getNewPrefixVariable(); $var = $parser->compiler->getNewPrefixVariable();
$tmp = $parser->compiler->appendCode('<?php ob_start();?>', $this->data); $tmp = $parser->compiler->appendCode('<?php ob_start();?>', $this->data);
$tmp = $parser->compiler->appendCode($tmp, "<?php {$var}=ob_get_clean();?>"); $tmp = $parser->compiler->appendCode($tmp, "<?php {$var}=ob_get_clean();?>");
$parser->compiler->prefix_code[] = sprintf('%s', $tmp); $parser->compiler->appendPrefixCode((string) $tmp);
return $var; return $var;
} }
} }

View File

@@ -162,8 +162,8 @@ class TemplateParser
{ {
$this->lex = $lex; $this->lex = $lex;
$this->compiler = $compiler; $this->compiler = $compiler;
$this->template = $this->compiler->template; $this->template = $this->compiler->getTemplate();
$this->smarty = $this->template->smarty; $this->smarty = $this->template->getSmarty();
$this->security = $this->smarty->security_policy ?? false; $this->security = $this->smarty->security_policy ?? false;
$this->current_buffer = $this->root_buffer = new TemplateParseTree(); $this->current_buffer = $this->root_buffer = new TemplateParseTree();
} }
@@ -207,7 +207,7 @@ class TemplateParser
} }
$this->compiler->prefix_code = array(); $this->compiler->prefix_code = array();
$tmp .= $code; $tmp .= $code;
return new Tag($this, $this->compiler->processNocacheCode($tmp, true)); return new Tag($this, $this->compiler->processNocacheCode($tmp));
} }
} }
@@ -294,7 +294,7 @@ template ::= template smartytag(B). {
$this->current_buffer->append_subtree($this, $this->mergePrefixCode(B)); $this->current_buffer->append_subtree($this, $this->mergePrefixCode(B));
} }
$this->compiler->has_variable_string = false; $this->compiler->has_variable_string = false;
$this->block_nesting_level = count($this->compiler->_tag_stack); $this->block_nesting_level = $this->compiler->getTagStackCount();
} }
@@ -303,11 +303,12 @@ template ::= .
smartytag(A) ::= SIMPELOUTPUT(B). { smartytag(A) ::= SIMPELOUTPUT(B). {
$var = trim(substr(B, $this->compiler->getLdelLength(), -$this->compiler->getRdelLength()), ' $'); $var = trim(substr(B, $this->compiler->getLdelLength(), -$this->compiler->getRdelLength()), ' $');
$attributes = [];
if (preg_match('/^(.*)(\s+nocache)$/', $var, $match)) { if (preg_match('/^(.*)(\s+nocache)$/', $var, $match)) {
A = (new \Smarty\Compile\PrintExpressionCompiler())->compile(array('nocache'),$this->compiler,array('value'=>$this->compiler->compileVariable('\''.$match[1].'\''))); $attributes[] = 'nocache';
} else { $var = $match[1];
A = (new \Smarty\Compile\PrintExpressionCompiler())->compile(array(),$this->compiler,array('value'=>$this->compiler->compileVariable('\''.$var.'\'')));
} }
A = $this->compiler->compilePrintExpression($this->compiler->compileVariable('\''.$var.'\''), $attributes);
} }
// simple tag like {name} // simple tag like {name}
@@ -321,7 +322,7 @@ smartytag(A)::= SIMPLETAG(B). {
if ($this->security) { if ($this->security) {
$this->security->isTrustedConstant($tag, $this->compiler); $this->security->isTrustedConstant($tag, $this->compiler);
} }
A = (new \Smarty\Compile\PrintExpressionCompiler())->compile(array(),$this->compiler,array('value'=>$tag)); A = $this->compiler->compilePrintExpression($tag);
} else { } else {
if (preg_match('/^(.*)(\s+nocache)$/', $tag, $match)) { if (preg_match('/^(.*)(\s+nocache)$/', $tag, $match)) {
A = $this->compiler->compileTag($match[1],array('\'nocache\'')); A = $this->compiler->compileTag($match[1],array('\'nocache\''));
@@ -336,10 +337,10 @@ smartytag(A) ::= SMARTYBLOCKCHILDPARENT(i). {
$j = strrpos(i,'.'); $j = strrpos(i,'.');
if (i[$j+1] == 'c') { if (i[$j+1] == 'c') {
// {$smarty.block.child} // {$smarty.block.child}
A = $this->compiler->compileTag('child',array(),array(i)); A = $this->compiler->compileChildBlock();
} else { } else {
// {$smarty.block.parent} // {$smarty.block.parent}
A = $this->compiler->compileTag('parent',array(),array(i)); A = $this->compiler->compileParentBlock();
} }
} }
@@ -352,7 +353,7 @@ smartytag(A) ::= LDEL tagbody(B) RDEL. {
} }
// output with optional attributes // output with optional attributes
tagbody(A) ::= outattr(B). { tagbody(A) ::= outattr(B). {
A = (new \Smarty\Compile\PrintExpressionCompiler())->compile(B[1],$this->compiler,array('value'=>B[0])); A = $this->compiler->compilePrintExpression(B[0], B[1]);
} }
// //
@@ -392,7 +393,7 @@ tag(res) ::= LDEL ID(i) attributes(a). {
if ($this->security) { if ($this->security) {
$this->security->isTrustedConstant(i, $this->compiler); $this->security->isTrustedConstant(i, $this->compiler);
} }
res = (new \Smarty\Compile\PrintExpressionCompiler())->compile(a,$this->compiler,array('value'=>i)); res = $this->compiler->compilePrintExpression(i, a);
} else { } else {
res = $this->compiler->compileTag(i,a); res = $this->compiler->compileTag(i,a);
} }
@@ -402,7 +403,7 @@ tag(res) ::= LDEL ID(i). {
if ($this->security) { if ($this->security) {
$this->security->isTrustedConstant(i, $this->compiler); $this->security->isTrustedConstant(i, $this->compiler);
} }
res = (new \Smarty\Compile\PrintExpressionCompiler())->compile(array(),$this->compiler,array('value'=>i)); res = $this->compiler->compilePrintExpression(i);
} else { } else {
res = $this->compiler->compileTag(i,array()); res = $this->compiler->compileTag(i,array());
} }
@@ -415,7 +416,7 @@ tag(res) ::= LDEL ID(i) modifierlist(l)attributes(a). {
if ($this->security) { if ($this->security) {
$this->security->isTrustedConstant(i, $this->compiler); $this->security->isTrustedConstant(i, $this->compiler);
} }
res = (new \Smarty\Compile\PrintExpressionCompiler())->compile(a,$this->compiler,array('value'=>i, 'modifierlist'=>l)); res = $this->compiler->compilePrintExpression(i, a, l);
} else { } else {
res = $this->compiler->compileTag(i,a, array('modifierlist'=>l)); res = $this->compiler->compileTag(i,a, array('modifierlist'=>l));
} }

View File

@@ -222,11 +222,11 @@ class InheritanceRuntime {
* @return null|string block content * @return null|string block content
* @throws Exception * @throws Exception
*/ */
public function callParent(Template $tpl, \Smarty\Runtime\Block $block, $tag) { public function callParent(Template $tpl, \Smarty\Runtime\Block $block) {
if (isset($block->parent)) { if (isset($block->parent)) {
$this->callBlock($block->parent, $tpl); $this->callBlock($block->parent, $tpl);
} else { } else {
throw new Exception("inheritance: illegal '{$tag}' used in child template '" . throw new Exception("inheritance: illegal '{\$smarty.block.parent}' used in child template '" .
"{$tpl->getInheritance()->sources[$block->tplIndex]->filepath}' block '{$block->name}'"); "{$tpl->getInheritance()->sources[$block->tplIndex]->filepath}' block '{$block->name}'");
} }
} }

View File

@@ -1343,7 +1343,7 @@ class CompileBlockExtendsTest extends PHPUnit_Smarty
"blockNocache - {$file}"); "blockNocache - {$file}");
} }
/* /*
* Data provider für TestBlockNocache * Data provider for TestBlockNocache
*/ */
public function dataTestBlockNocache() public function dataTestBlockNocache()
{ {