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;
use Smarty\Compiler\Template;
use Smarty\Data;
use Smarty\Exception;
@@ -49,20 +50,6 @@ abstract class Base implements CompilerInterface {
*/
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 {
return $this->cacheable;
}
@@ -96,14 +83,12 @@ abstract class Base implements CompilerInterface {
*/
protected function getAttributes($compiler, $attributes) {
$_indexed_attr = [];
if (!isset($this->mapCache['option'])) {
$this->mapCache['option'] = array_fill_keys($this->option_flags, true);
}
$options = array_fill_keys($this->option_flags, true);
foreach ($attributes as $key => $mixed) {
// shorthand ?
if (!is_array($mixed)) {
// option flag ?
if (isset($this->mapCache['option'][trim($mixed, '\'"')])) {
// options flag ?
if (isset($options[trim($mixed, '\'"')])) {
$_indexed_attr[trim($mixed, '\'"')] = true;
// shorthand attribute ?
} elseif (isset($this->shorttag_order[$key])) {
@@ -115,20 +100,24 @@ abstract class Base implements CompilerInterface {
// named attribute
} else {
foreach ($mixed as $k => $v) {
// option flag?
if (isset($this->mapCache['option'][$k])) {
// options flag?
if (isset($options[$k])) {
if (is_bool($v)) {
$_indexed_attr[$k] = $v;
} else {
if (is_string($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 {
$compiler->trigger_template_error(
"illegal value '" . var_export($v, true) .
"' for option flag '{$k}'",
"' for options flag '{$k}'",
null,
true
);
@@ -149,9 +138,7 @@ abstract class Base implements CompilerInterface {
}
// check for not allowed attributes
if ($this->optional_attributes !== ['_any']) {
if (!isset($this->mapCache['all'])) {
$this->mapCache['all'] =
array_fill_keys(
$allowedAttributes = array_fill_keys(
array_merge(
$this->required_attributes,
$this->optional_attributes,
@@ -159,22 +146,19 @@ abstract class Base implements CompilerInterface {
),
true
);
}
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);
}
}
}
// default 'false' for all option flags not set
// default 'false' for all options flags not set
foreach ($this->option_flags as $flag) {
if (!isset($_indexed_attr[$flag])) {
$_indexed_attr[$flag] = false;
}
}
if (isset($_indexed_attr['nocache']) && $_indexed_attr['nocache']) {
$compiler->tag_nocache = true;
}
return $_indexed_attr;
}
@@ -182,44 +166,25 @@ abstract class Base implements CompilerInterface {
* Push opening tag name 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 mixed $data optional data saved
*/
protected function openTag($compiler, $openTag, $data = null) {
array_push($compiler->_tag_stack, [$openTag, $data]);
protected function openTag(Template $compiler, $openTag, $data = null) {
$compiler->openTag($openTag, $data);
}
/**
* Pop closing tag
* 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
*
* @return mixed any type the opening tag's name or saved data
*/
protected function closeTag($compiler, $expectedTag) {
if (count($compiler->_tag_stack) > 0) {
// 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);
protected function closeTag(Template $compiler, $expectedTag) {
return $compiler->closeTag($expectedTag);
}
/**
@@ -259,11 +224,11 @@ abstract class Base implements CompilerInterface {
* Compiles code for the tag
*
* @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
*
* @return bool|string compiled code or true if no code has been compiled
* @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
*
*/
class BlockCompiler extends Base {
@@ -62,6 +60,56 @@ class BlockCompiler extends Base {
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.
*
@@ -118,6 +166,13 @@ class BlockCompiler extends Base {
$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
$output = "<?php \$_block_repeat=true;
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) {
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;
}
@@ -142,13 +195,11 @@ while (\$_block_repeat) {
* @throws Exception
*/
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
$base_tag = substr($tag, 0, -5);
[$_params, $compiler->nocache] = $this->closeTag($compiler, $base_tag);
[$_params, $nocache_pushed] = $this->closeTag($compiler, $base_tag);
// compile code
if (!isset($parameter['modifier_list'])) {
$mod_pre = $mod_post = $mod_content = '';
@@ -164,6 +215,13 @@ while (\$_block_repeat) {
$callback = $this->getFullCallbackCode($base_tag, $function);
$output .= "echo {$callback}({$_params}, {$mod_content2}, \$_smarty_tpl, \$_block_repeat);\n";
$output .= "{$mod_post}}\n?>";
if ($nocache_pushed) {
// pop the pushed virtual nocache tag
$this->closeTag($compiler, 'nocache');
$compiler->tag_nocache = true;
}
return $output;
}

View File

@@ -19,6 +19,12 @@ namespace Smarty\Compile\Tag;
*/
class Append extends Assign
{
/**
* @inheritdoc
*/
protected $optional_attributes = ['scope', 'index'];
/**
* 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)
{
// 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
$_attr = $this->getAttributes($compiler, $args);
// map to compile assign attributes
if (isset($_attr[ 'index' ])) {
$_params[ 'smarty_internal_index' ] = '[' . $_attr[ 'index' ] . ']';

View File

@@ -22,6 +22,21 @@ use Smarty\Smarty;
*/
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.
*
@@ -42,21 +57,17 @@ class Assign extends Base
*/
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;
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
// nocache ?
if ($_var = $compiler->getId($_attr[ 'var' ])) {
$_var = "'{$_var}'";
} else {
$_var = $_attr[ 'var' ];
}
if ($compiler->tag_nocache || $compiler->nocache) {
if ($compiler->tag_nocache || $compiler->isNocacheActive()) {
$_nocache = true;
// create nocache var to make it know for further compiling
$compiler->setNocacheInVariable($_attr[ 'var' ]);

View File

@@ -74,20 +74,17 @@ class Block extends Inheritance {
$_attr = $this->getAttributes($compiler, $args);
++$compiler->_cache['blockNesting'];
$_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(
$compiler,
'block',
[
$_attr, $compiler->nocache, $compiler->getParser()->current_buffer,
$compiler->getTemplate()->getCompiled()->getNocacheCode(),
$compiler->getTemplate()->caching,
$_attr, $compiler->tag_nocache, $compiler->getParser()->current_buffer,
$compiler->getTemplate()->getCompiled()->getNocacheCode(), $_className
]
);
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
// @TODO what is this for?
$compiler->getParser()->current_buffer = new Template();
$compiler->getTemplate()->getCompiled()->setNocacheCode(false);
$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)
{
[$_attr, $_nocache, $_buffer, $_has_nocache_code, $_caching] = $this->closeTag($compiler, ['block']);
// init block parameter
$_block = $compiler->_cache['blockParams'][$compiler->_cache['blockNesting']];
unset($compiler->_cache['blockParams'][$compiler->_cache['blockNesting']]);
[$_attr, $_nocache, $_buffer, $_has_nocache_code, $_className] = $this->closeTag($compiler, ['block']);
$_name = $_attr['name'];
$_assign = isset($_attr['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']];
$_assign = $_attr['assign'] ?? null;
// get compiled block code
$_functionCode = $compiler->getParser()->current_buffer;
// setup buffer for template function code
@@ -41,9 +33,6 @@ class BlockClose extends Inheritance {
$output .= $compiler->cStyleComment(" {block {$_name}} ") . "\n";
$output .= "class {$_className} extends \\Smarty\\Runtime\\Block\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";
if ($compiler->getTemplate()->getCompiled()->getNocacheCode()) {
$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->getParser()->current_buffer = new Template();
// restore old status
$compiler->getTemplate()->getCompiled()->setNocacheCode($_has_nocache_code);
$compiler->tag_nocache = $compiler->nocache;
$compiler->nocache = $_nocache;
$compiler->tag_nocache = $_nocache;
$compiler->getParser()->current_buffer = $_buffer;
$output = "<?php \n";
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;
}
$level_count = $levels;
$stack_count = count($compiler->_tag_stack) - 1;
$tagStack = $compiler->getTagStack();
$stack_count = count($tagStack) - 1;
$foreachLevels = 0;
$lastTag = '';
while ($level_count > 0 && $stack_count >= 0) {
if (isset($_is_loopy[$compiler->_tag_stack[$stack_count][0]])) {
$lastTag = $compiler->_tag_stack[$stack_count][0];
if (isset($_is_loopy[$tagStack[$stack_count][0]])) {
$lastTag = $tagStack[$stack_count][0];
if ($level_count === 0) {
break;
}
$level_count--;
if ($compiler->_tag_stack[$stack_count][0] === 'foreach') {
if ($tagStack[$stack_count][0] === 'foreach') {
$foreachLevels++;
}
}

View File

@@ -59,7 +59,7 @@ class Call extends Base {
$_name = $_attr['name'];
unset($_attr['name'], $_attr['assign'], $_attr['nocache']);
// 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';
} else {
$_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) {
// check and get attributes
$_attr = $this->getAttributes($compiler, $args, $parameter, 'capture');
$_attr = $this->getAttributes($compiler, $args);
$buffer = $_attr['name'] ?? "'default'";
$assign = $_attr['assign'] ?? 'null';
$append = $_attr['append'] ?? 'null';
$compiler->_cache['capture_stack'][] = [$compiler->nocache];
// maybe nocache because of nocache variables
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
$compiler->_cache['capture_stack'][] = $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);?>";
return $_output;
}

View File

@@ -30,13 +30,13 @@ class CaptureClose extends Base {
* @return string compiled code
*/
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
// check and get attributes
$_attr = $this->getAttributes($compiler, $args, $parameter, '/capture');
// must endblock be nocache?
if ($compiler->nocache) {
if (array_pop($compiler->_cache['capture_stack'])) {
// pop the virtual {nocache} tag from the stack.
$compiler->closeTag('nocache');
$compiler->tag_nocache = true;
}
[$compiler->nocache] = array_pop($compiler->_cache['capture_stack']);
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
*/
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
[$nesting, $compiler->tag_nocache] = $this->closeTag($compiler, ['if', 'elseif']);
[$nesting, $nocache_pushed] = $this->closeTag($compiler, ['if', 'elseif']);
if (!isset($parameter['if condition'])) {
$compiler->trigger_template_error('missing elseif condition', null, true);
}
@@ -38,7 +38,7 @@ class ElseIfTag extends Base {
} else {
$var = $parameter['if condition']['var'];
}
if ($compiler->nocache) {
if ($compiler->isNocacheActive()) {
// create nocache var to make it know for further compiling
$compiler->setNocacheInVariable($var);
}
@@ -68,12 +68,12 @@ class ElseIfTag extends Base {
$_output = $compiler->appendCode("<?php } else {\n?>", $assignCode);
return $compiler->appendCode($_output, "<?php if ({$prefixVar}) {?>");
} else {
$this->openTag($compiler, 'elseif', [$nesting, $compiler->tag_nocache]);
$this->openTag($compiler, 'elseif', [$nesting, $nocache_pushed]);
return "<?php } elseif ({$parameter['if condition']}) {?>";
}
} else {
$_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) {
$_output = $compiler->appendCode($_output, $assignCode);
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) {
$compiler->loopNesting--;
// check and get attributes
$this->getAttributes($compiler, $args);
// must endblock be nocache?
if ($compiler->nocache) {
$compiler->tag_nocache = true;
}
[$openTag, $compiler->nocache] = $this->closeTag($compiler, ['for', 'forelse']);
[$openTag, $nocache_pushed] = $this->closeTag($compiler, ['for', 'forelse']);
$output = "<?php }\n";
if ($openTag !== 'forelse') {
$output .= "}\n";
}
$output .= "?>";
if ($nocache_pushed) {
// pop the pushed virtual nocache tag
$this->closeTag('nocache');
$compiler->tag_nocache = true;
}
return $output;
}
}

View File

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

View File

@@ -37,7 +37,7 @@ class ForTag extends Base {
$this->required_attributes = ['start', 'ifexp', 'var', 'step'];
$this->optional_attributes = [];
}
$this->mapCache = [];
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
$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 .= '?>';
$this->openTag($compiler, 'for', ['for', $compiler->nocache]);
// maybe nocache because of nocache variables
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
// return compiled code
if ($compiler->tag_nocache) {
// push a {nocache} tag onto the stack to prevent caching of this for loop
$this->openTag('nocache');
}
$this->openTag($compiler, 'for', ['for', $compiler->tag_nocache]);
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) {
$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;
}
[
$openTag, $compiler->nocache, $local, $itemVar, $restore,
] = $this->closeTag($compiler, ['foreach', 'foreachelse']);
$output = "<?php\n";
if ($restore === 2) {
$output .= "{$itemVar} = {$local}saved;\n";

View File

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

View File

@@ -181,14 +181,19 @@ class ForeachTag extends ForeachSection {
$foreachVar = "\$_smarty_tpl->tpl_vars['__smarty_foreach_{$attributes['name']}']";
}
$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
$this->openTag(
$compiler,
'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
$output = "<?php\n";
$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
*/
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;
}
[$nesting, $compiler->nocache] = $this->closeTag($compiler, ['if', 'else', 'elseif']);
$tmp = '';
for ($i = 0; $i < $nesting; $i++) {
$tmp .= '}';

View File

@@ -23,11 +23,14 @@ class IfTag extends Base {
* @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);
$this->openTag($compiler, 'if', [1, $compiler->nocache]);
// must whole block be nocache ?
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
if ($compiler->tag_nocache) {
// push a {nocache} tag onto the stack to prevent caching of this block
$this->openTag('nocache');
}
$this->openTag($compiler, 'if', [1, $compiler->tag_nocache]);
if (!isset($parameter['if condition'])) {
$compiler->trigger_template_error('missing if condition', null, true);
}
@@ -37,7 +40,7 @@ class IfTag extends Base {
} else {
$var = $parameter['if condition']['var'];
}
if ($compiler->nocache) {
if ($compiler->isNocacheActive()) {
// create nocache var to make it know for further compiling
$compiler->setNocacheInVariable($var);
}

View File

@@ -111,11 +111,13 @@ class IncludeTag extends Base {
// assume caching is off
$_caching = Smarty::CACHING_OFF;
$call_nocache = $compiler->tag_nocache || $compiler->nocache;
// 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;
}
// flag if included template code should be merged into caller
$merge_compiled_includes = ($compiler->getSmarty()->merge_compiled_includes || $_attr['inline'] === true) &&
!$compiler->getTemplate()->getSource()->handler->recompiled;
@@ -125,12 +127,15 @@ class IncludeTag extends Base {
$merge_compiled_includes = false;
}
}
/*
* 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
* a call in nocache mode.
*
*/
$call_nocache = $compiler->isNocacheActive();
if ($_attr['nocache'] !== true && $_attr['caching']) {
$_caching = $_new_caching = (int)$_attr['caching'];
$call_nocache = true;
@@ -161,7 +166,7 @@ class IncludeTag extends Base {
// output will be stored in a smarty variable instead of being displayed
if ($_assign = $compiler->getId($_attr['assign'])) {
$_assign = "'{$_assign}'";
if ($compiler->tag_nocache || $compiler->nocache || $call_nocache) {
if ($call_nocache) {
// create nocache var to make it know for further compiling
$compiler->setNocacheInVariable($_attr['assign']);
}
@@ -281,7 +286,7 @@ class IncludeTag extends Base {
$compiled_code = "<?php\n\n";
$compiled_code .= $compiler->cStyleComment(" Start inline template \"{$sourceInfo}\" =============================") . "\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 .= "}\n?>\n";
$compiled_code .= $tpl->getSmarty()->runPostFilters($tpl->getCompiler()->blockOrFunctionCode, $tpl);

View File

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

View File

@@ -30,9 +30,7 @@ class NocacheClose extends Base {
* @return bool
*/
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
$_attr = $this->getAttributes($compiler, $args);
// leave nocache mode
[$compiler->nocache] = $this->closeTag($compiler, ['nocache']);
$this->closeTag($compiler, ['nocache']);
// this tag does not return compiled code
$compiler->has_code = false;
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++ . '_';
$sectionVar = "\$_smarty_tpl->tpl_vars['__smarty_section_{$attributes['name']}']";
$this->openTag($compiler, 'section', ['section', $compiler->nocache, $local, $sectionVar]);
// maybe nocache because of nocache variables
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
if ($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 = [];
$initNamedProperty = [];
$initFor = [];

View File

@@ -14,9 +14,6 @@ use Smarty\Compile\Base;
/**
* Smarty Internal Plugin Compile Sectionclose Class
*
*/
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) {
$compiler->loopNesting--;
// must endblock be nocache?
if ($compiler->nocache) {
$compiler->tag_nocache = true;
[$openTag, $nocache_pushed] = $this->closeTag($compiler, ['section', 'sectionelse']);
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";
if ($openTag === 'sectionelse') {
$output .= "}\n";

View File

@@ -21,10 +21,8 @@ class SectionElse extends Base {
* @return string compiled code
*/
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
// check and get attributes
$this->getAttributes($compiler, $args);
[$openTag, $nocache, $local, $sectionVar] = $this->closeTag($compiler, ['section']);
$this->openTag($compiler, 'sectionelse', ['sectionelse', $nocache, $local, $sectionVar]);
[$openTag, $nocache_pushed] = $this->closeTag($compiler, ['section']);
$this->openTag($compiler, 'sectionelse', ['sectionelse', $nocache_pushed]);
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) {
$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->nocache = $this->closeTag($compiler, ['while']);
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) {
$compiler->loopNesting++;
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
$this->openTag($compiler, 'while', $compiler->nocache);
if ($compiler->tag_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)) {
$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 ($compiler->nocache) {
if ($compiler->isNocacheActive()) {
// create nocache var to make it know for further compiling
if (is_array($parameter['if condition']['var'])) {
$var = $parameter['if condition']['var']['var'];

View File

@@ -17,6 +17,7 @@ use Smarty\Compile\ModifierCompiler;
use Smarty\Compile\ObjectMethodBlockCompiler;
use Smarty\Compile\ObjectMethodCallCompiler;
use Smarty\Compile\FunctionCallCompiler;
use Smarty\Compile\PrintExpressionCompiler;
use Smarty\Lexer\TemplateLexer;
use Smarty\Parser\TemplateParser;
use Smarty\Smarty;
@@ -76,14 +77,14 @@ class Template extends BaseCompiler {
*
* @var array
*/
public $_tag_stack = [];
private $_tag_stack = [];
/**
* tag stack count
*
* @var array
*/
public $_tag_stack_count = [];
private $_tag_stack_count = [];
/**
* current template
@@ -308,6 +309,17 @@ class Template extends BaseCompiler {
* @var 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
@@ -332,53 +344,38 @@ class Template extends BaseCompiler {
$this->defaultHandlerBlockCompiler = new DefaultHandlerBlockCompiler();
$this->objectMethodBlockCompiler = new ObjectMethodBlockCompiler();
$this->objectMethodCallCompiler = new ObjectMethodCallCompiler();
$this->printExpressionCompiler = new PrintExpressionCompiler();
}
/**
* Method to compile a Smarty template
*
* @param Smarty\Template $template template object to compile
* @param null $nocache true is shall be compiled in nocache mode
* @param null|Template $parent_compiler
* @param \Smarty\Template $template template object to compile
*
* @return bool true if compiling succeeded, false if it failed
* @throws Exception
*/
public function compileTemplate(
\Smarty\Template $template,
$nocache = null,
\Smarty\Compiler\Template $parent_compiler = null
) {
// get code frame of compiled template
$_compiled_code = $template->createCodeFrame(
$this->compileTemplateSource(
$template,
$nocache,
$parent_compiler
),
public function compileTemplate(\Smarty\Template $template) {
return $template->createCodeFrame(
$this->compileTemplateSource($template),
$this->smarty->runPostFilters($this->blockOrFunctionCode, $this->template) .
join('', $this->mergedSubTemplatesCode),
false,
$this
);
return $_compiled_code;
}
/**
* Compile template source and run optional post filter
*
* @param \Smarty\Template $template
* @param null|bool $nocache flag if template must be compiled in nocache mode
* @param \Smarty\Compiler\Template $parent_compiler
* @param Template|null $parent_compiler
*
* @return string
* @throws \Exception
* @throws CompilerException
* @throws Exception
*/
public function compileTemplateSource(
\Smarty\Template $template,
$nocache = null,
\Smarty\Compiler\Template $parent_compiler = null
) {
public function compileTemplateSource(\Smarty\Template $template, \Smarty\Compiler\Template $parent_compiler = null) {
try {
// save template object in compiler class
$this->template = $template;
@@ -386,18 +383,20 @@ class Template extends BaseCompiler {
$this->smarty->getDebug()->start_compile($this->template);
}
$this->parent_compiler = $parent_compiler ? $parent_compiler : $this;
$nocache = isset($nocache) ? $nocache : false;
if (empty($template->getCompiled()->nocache_hash)) {
$template->getCompiled()->nocache_hash = $this->nocache_hash;
} else {
$this->nocache_hash = $template->getCompiled()->nocache_hash;
}
$this->caching = $template->caching;
// flag for nocache sections
$this->nocache = $nocache;
$this->nocache = false;
$this->tag_nocache = false;
// reset has nocache code flag
$this->template->getCompiled()->setNocacheCode(false);
$this->has_variable_string = false;
$this->prefix_code = [];
// add file dependency
@@ -715,8 +714,7 @@ class Template extends BaseCompiler {
if (!empty($content)
&& !($this->template->getSource()->handler->recompiled)
&& $this->caching
&& !$this->suppressNocacheProcessing
&& ($this->nocache || $this->tag_nocache)
&& $this->isNocacheActive()
) {
$this->template->getCompiled()->setNocacheCode(true);
$_output = addcslashes($content, '\'\\');
@@ -1075,21 +1073,14 @@ class Template extends BaseCompiler {
return '/*' . str_replace('*/', '* /', $string) . '*/';
}
private function argsContainNocache(array $args): bool {
foreach ($args as $arg) {
if (!is_array($arg)) {
if ($arg === "'nocache'" || $arg === 'nocache') {
return true;
public function compileChildBlock() {
$this->has_code = true;
return $this->blockCompiler->compileChild($this);
}
} else {
foreach ($arg as $k => $v) {
if (($k === "'nocache'" || $k === 'nocache') && (trim($v, "'\" ") === 'true')) {
return true;
}
}
}
}
return false;
public function compileParentBlock() {
$this->has_code = true;
return $this->blockCompiler->compileParent($this);
}
/**
@@ -1108,17 +1099,16 @@ class Template extends BaseCompiler {
// assume that tag does compile into code, but creates no HTML output
$this->has_code = true;
// check nocache option flag
if ($this->argsContainNocache($args)) {
$this->tag_nocache = true;
}
$this->handleNocacheFlag($args);
// compile built-in tags
if ($tagCompiler = $this->getTagCompiler($tag)) {
if (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this)) {
$this->tag_nocache = !$tagCompiler->isCacheable();
$_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);
}
/**
* 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) {
if (strlen($tag) < 6 || substr($tag, -5) !== 'close') {
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
*
@@ -1256,7 +1279,7 @@ class Template extends BaseCompiler {
mb_internal_encoding($mbEncoding);
}
// check for unclosed tags
if (count($this->_tag_stack) > 0) {
if ($this->getTagStackCount() > 0) {
// get stacked info
[$openTag, $_data] = array_pop($this->_tag_stack);
$this->trigger_template_error(
@@ -1405,4 +1428,72 @@ class Template extends BaseCompiler {
$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 'capture': return new \Smarty\Compile\Tag\Capture();
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 'continue': return new \Smarty\Compile\Tag\ContinueTag();
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 'nocache': return new \Smarty\Compile\Tag\Nocache();
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 'sectionelse': return new \Smarty\Compile\Tag\SectionElse();
case 'sectionclose': return new \Smarty\Compile\Tag\SectionClose();

View File

@@ -28,7 +28,7 @@ class Dq extends Base
{
$this->subtrees[] = $subtree;
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;
}
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();
$tmp = $parser->compiler->appendCode('<?php ob_start();?>', $this->data);
$tmp = $parser->compiler->appendCode($tmp, "<?php {$var}=ob_get_clean();?>");
$parser->compiler->prefix_code[] = sprintf('%s', $tmp);
$parser->compiler->appendPrefixCode((string) $tmp);
return $var;
}
}

View File

@@ -162,8 +162,8 @@ class TemplateParser
{
$this->lex = $lex;
$this->compiler = $compiler;
$this->template = $this->compiler->template;
$this->smarty = $this->template->smarty;
$this->template = $this->compiler->getTemplate();
$this->smarty = $this->template->getSmarty();
$this->security = $this->smarty->security_policy ?? false;
$this->current_buffer = $this->root_buffer = new TemplateParseTree();
}
@@ -207,7 +207,7 @@ class TemplateParser
}
$this->compiler->prefix_code = array();
$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->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). {
$var = trim(substr(B, $this->compiler->getLdelLength(), -$this->compiler->getRdelLength()), ' $');
$attributes = [];
if (preg_match('/^(.*)(\s+nocache)$/', $var, $match)) {
A = (new \Smarty\Compile\PrintExpressionCompiler())->compile(array('nocache'),$this->compiler,array('value'=>$this->compiler->compileVariable('\''.$match[1].'\'')));
} else {
A = (new \Smarty\Compile\PrintExpressionCompiler())->compile(array(),$this->compiler,array('value'=>$this->compiler->compileVariable('\''.$var.'\'')));
$attributes[] = 'nocache';
$var = $match[1];
}
A = $this->compiler->compilePrintExpression($this->compiler->compileVariable('\''.$var.'\''), $attributes);
}
// simple tag like {name}
@@ -321,7 +322,7 @@ smartytag(A)::= SIMPLETAG(B). {
if ($this->security) {
$this->security->isTrustedConstant($tag, $this->compiler);
}
A = (new \Smarty\Compile\PrintExpressionCompiler())->compile(array(),$this->compiler,array('value'=>$tag));
A = $this->compiler->compilePrintExpression($tag);
} else {
if (preg_match('/^(.*)(\s+nocache)$/', $tag, $match)) {
A = $this->compiler->compileTag($match[1],array('\'nocache\''));
@@ -336,10 +337,10 @@ smartytag(A) ::= SMARTYBLOCKCHILDPARENT(i). {
$j = strrpos(i,'.');
if (i[$j+1] == 'c') {
// {$smarty.block.child}
A = $this->compiler->compileTag('child',array(),array(i));
A = $this->compiler->compileChildBlock();
} else {
// {$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
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) {
$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 {
res = $this->compiler->compileTag(i,a);
}
@@ -402,7 +403,7 @@ tag(res) ::= LDEL ID(i). {
if ($this->security) {
$this->security->isTrustedConstant(i, $this->compiler);
}
res = (new \Smarty\Compile\PrintExpressionCompiler())->compile(array(),$this->compiler,array('value'=>i));
res = $this->compiler->compilePrintExpression(i);
} else {
res = $this->compiler->compileTag(i,array());
}
@@ -415,7 +416,7 @@ tag(res) ::= LDEL ID(i) modifierlist(l)attributes(a). {
if ($this->security) {
$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 {
res = $this->compiler->compileTag(i,a, array('modifierlist'=>l));
}

View File

@@ -222,11 +222,11 @@ class InheritanceRuntime {
* @return null|string block content
* @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)) {
$this->callBlock($block->parent, $tpl);
} 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}'");
}
}

View File

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