- update/bugfix scope attribute handling reworked. Read the newfeatures.txt file

This commit is contained in:
uwetews
2016-02-09 23:27:07 +01:00
parent 37e6d26b23
commit 2f62b99173
20 changed files with 371 additions and 401 deletions

View File

@@ -4,6 +4,58 @@ This file contains a brief description of new features which have been added to
Smarty 3.1.30 Smarty 3.1.30
Scope Attributes
================
The scope handling has been updated to cover all cases of variable assignments in templates.
A new option flag 'bubble_up' is introduced.
The tags {assign}, {append} direct assignments like {$foo = ...}, {$foo[...]= ...} support
the following optional scope attributes:
scope=parent - the variable will be assigned in the current template and if the template
was included by {include} the calling template
scope=tpl_root - the variable will be assigned in the current template and if the template
was included by {include} the outermost root template
scope=smarty - the variable will be assigned in the current template and the Smarty object
scope=global - the variable will be assigned in the current template and as Smarty object
global variable
scope=root - the variable will be assigned in the current template and if a data object was
used for variable definitions in the data object or in the Smarty object otherwise
scope=local - this scope has only a meaning if the tag is called within a template {function}.
The variable will be assigned in the local scope of the template function and the
template which did call the template function.
The scope attribute can be combined with the new option flag 'bubble_up' like
{$foo = 'bar' scope=global bubble_up}
In addition to the assignments according to the scope attributes tpl_root, smarty, global, root the varibale
will also be assigned in all templates in the call chain from template root to the current template,
including all local template function scopes of nested template function calls.
In combination with scope local it does update the nested template function scopes.
Example:
$smarty->display('main.tpl');
main.tpl:
{include 'sub.tpl'}
sub.tpl:
{$foo = 'bar' scope=global bubble_up}
Will assign the variable 'foo' with value 'bar' as Smarty global variable, in 'sub.tpl' and in
'main.tpl' because the 'bubble_up' option.
The {config_load} tag supports all of the above except the global scope.
The scope attribute and bubble_up option flag can be used also with the {include} tag.
Supported scope are parent, tpl_root, smarty, global and root.
A scope used together with the {include} tag will cause that with some exceptions any variable
assignment within that sub-template will update/assign the variable in other scopes according
to the above rules. It does include also variables assigned by plugins, tags supporting the assign=foo
attribute and direct assignments in {if} and {while} like {if $foo=$bar}.
Excluded are the key and value variables of {foreach}, {for} loop variables , variables passed by attributes
in {include} and direct increments/decrements like {$foo++}, {$foo--}
Caching Caching
======= =======
Caching does now observe the template_dir setting and will create separate cache files if required Caching does now observe the template_dir setting and will create separate cache files if required

View File

@@ -2,6 +2,7 @@
09.02.2016 09.02.2016
- move some code from parser into compiler - move some code from parser into compiler
- reformat all code for unique style - reformat all code for unique style
- update/bugfix scope attribute handling reworked. Read the newfeatures.txt file
05.02.2016 05.02.2016
- improvement internal compiler changes - improvement internal compiler changes

View File

@@ -121,12 +121,12 @@ class Smarty extends Smarty_Internal_TemplateBase
/** /**
* smarty version * smarty version
*/ */
const SMARTY_VERSION = '3.1.30-dev/30'; const SMARTY_VERSION = '3.1.30-dev/31';
/** /**
* define variable scopes * define variable scopes
*/ */
const SCOPE_LOCAL = 0; const SCOPE_LOCAL = 1;
const SCOPE_PARENT = 2; const SCOPE_PARENT = 2;
@@ -134,6 +134,8 @@ class Smarty extends Smarty_Internal_TemplateBase
const SCOPE_ROOT = 8; const SCOPE_ROOT = 8;
const SCOPE_SMARTY = 16;
const SCOPE_GLOBAL = 32; const SCOPE_GLOBAL = 32;
const SCOPE_BUBBLE_UP = 64; const SCOPE_BUBBLE_UP = 64;

View File

@@ -16,13 +16,22 @@
*/ */
class Smarty_Internal_Compile_Assign extends Smarty_Internal_CompileBase class Smarty_Internal_Compile_Assign extends Smarty_Internal_CompileBase
{ {
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $option_flags = array('nocache', 'bubble_up');
/** /**
* Valid scope names * Valid scope names
* *
* @var array * @var array
*/ */
public $valid_scopes = array('local' => true, 'parent' => true, 'root' => true, 'global' => true, public $valid_scopes = array('local' => Smarty::SCOPE_LOCAL, 'parent' => Smarty::SCOPE_PARENT,
'tpl_root' => true); 'root' => Smarty::SCOPE_ROOT, 'global' => Smarty::SCOPE_GLOBAL,
'tpl_root' => Smarty::SCOPE_TPL_ROOT, 'smarty' => Smarty::SCOPE_SMARTY);
/** /**
* Compiles code for the {assign} tag * Compiles code for the {assign} tag
@@ -39,60 +48,41 @@ class Smarty_Internal_Compile_Assign extends Smarty_Internal_CompileBase
// the following must be assigned at runtime because it will be overwritten in Smarty_Internal_Compile_Append // the following must be assigned at runtime because it will be overwritten in Smarty_Internal_Compile_Append
$this->required_attributes = array('var', 'value'); $this->required_attributes = array('var', 'value');
$this->shorttag_order = array('var', 'value'); $this->shorttag_order = array('var', 'value');
$this->optional_attributes = array('scope', 'bubble_up'); $this->optional_attributes = array('scope');
$_nocache = 'null'; $_nocache = false;
// check and get attributes // check and get attributes
$_attr = $this->getAttributes($compiler, $args); $_attr = $this->getAttributes($compiler, $args);
// nocache ? // nocache ?
if ($_var = $compiler->getId($_attr[ 'var' ])) {
$_var = "'{$_var}'";
} else {
$_var = $_attr[ 'var' ];
}
if ($compiler->tag_nocache || $compiler->nocache) { if ($compiler->tag_nocache || $compiler->nocache) {
$_nocache = 'true'; $_nocache = true;
// create nocache var to make it know for further compiling // create nocache var to make it know for further compiling
if (isset($compiler->template->tpl_vars[ trim($_attr[ 'var' ], "'") ])) { $compiler->setNocacheInVariable($_attr[ 'var' ]);
$compiler->template->tpl_vars[ trim($_attr[ 'var' ], "'") ]->nocache = true;
} else {
$compiler->template->tpl_vars[ trim($_attr[ 'var' ], "'") ] = new Smarty_Variable(null, true);
}
} }
// scope setup // scope setup
$_scope = Smarty::SCOPE_LOCAL; $_scope = $compiler->convertScope($_attr, $this->valid_scopes);
if (isset($_attr[ 'scope' ])) { // optional parameter
$_attr[ 'scope' ] = trim($_attr[ 'scope' ], "'\""); $_params = "";
if (!isset($this->valid_scopes[ $_attr[ 'scope' ] ])) { if ($_nocache || $_scope) {
$compiler->trigger_template_error("illegal value '{$_attr['scope']}' for \"scope\" attribute", null, $_params .= ' ,' . var_export($_nocache, true);
true); }
} if ($_scope) {
if ($_attr[ 'scope' ] != 'local') { $_params .= ' ,' . $_scope;
if ($_attr[ 'scope' ] == 'parent') {
$_scope = Smarty::SCOPE_PARENT;
} elseif ($_attr[ 'scope' ] == 'root') {
$_scope = Smarty::SCOPE_ROOT;
} elseif ($_attr[ 'scope' ] == 'global') {
$_scope = Smarty::SCOPE_GLOBAL;
} elseif ($_attr[ 'scope' ] == 'tpl_root') {
$_scope = Smarty::SCOPE_TPL_ROOT;
}
$_scope += (isset($_attr[ 'bubble_up' ]) && $_attr[ 'bubble_up' ] == 'false') ? 0 :
Smarty::SCOPE_BUBBLE_UP;
}
} }
if (isset($parameter[ 'smarty_internal_index' ])) { if (isset($parameter[ 'smarty_internal_index' ])) {
$output = "<?php \$_smarty_tpl->_createLocalArrayVariable({$_attr['var']}, {$_nocache});\n";
$output .= "\$_smarty_tpl->tpl_vars[{$_attr['var']}]->value{$parameter['smarty_internal_index']} = {$_attr['value']};\n";
if ($_scope != Smarty::SCOPE_LOCAL) {
$output .= "\$_smarty_tpl->ext->_updateScope->updateScope(\$_smarty_tpl, {$_attr['var']}, {$_scope});\n";
} else {
$output .= "if (\$_smarty_tpl->scope & Smarty::SCOPE_BUBBLE_UP) {\n";
$output .= "\$_smarty_tpl->ext->_updateScope->updateScope(\$_smarty_tpl, {$_attr['var']});\n}\n";
}
$output .= '?>';
} else {
if ($compiler->template->smarty instanceof SmartyBC) {
$_smartyBC = 'true';
} else {
$_smartyBC = 'false';
}
$output = $output =
"<?php \$_smarty_tpl->_assignInScope({$_attr['var']}, {$_attr['value']}, {$_nocache}, {$_scope}, {$_smartyBC});\n?>"; "<?php \$_tmp_array = isset(\$_smarty_tpl->tpl_vars[{$_var}]) ? \$_smarty_tpl->tpl_vars[{$_var}]->value : array();\n";
$output .= "if (!is_array(\$_tmp_array) || \$_tmp_array instanceof ArrayAccess) {\n";
$output .= "settype(\$_tmp_array, 'array');\n";
$output .= "}\n";
$output .= "\$_tmp_array{$parameter['smarty_internal_index']} = {$_attr['value']};\n";
$output .= "\$_smarty_tpl->_assignInScope({$_var}, \$_tmp_array{$_params});\n?>";
} else {
$output = "<?php \$_smarty_tpl->_assignInScope({$_var}, {$_attr['value']}{$_params});\n?>";
} }
return $output; return $output;
} }

View File

@@ -212,7 +212,7 @@ class Smarty_Internal_Compile_Blockclose extends Smarty_Internal_Compile_Shared_
$compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode); $compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode);
$output = "<?php\n"; $output = "<?php\n";
if (isset($_assign)) { if (isset($_assign)) {
$output .= "\$_smarty_tpl->tpl_vars[{$_assign}] = new Smarty_Variable(ob_get_clean());\n"; $output .= "\$_smarty_tpl->assign({$_assign}, ob_get_clean());\n";
} }
//$output .= "/*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\n"; //$output .= "/*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\n";
$output .= "\$_smarty_tpl->ext->_inheritance->blockNesting--;\n"; $output .= "\$_smarty_tpl->ext->_inheritance->blockNesting--;\n";

View File

@@ -38,14 +38,24 @@ class Smarty_Internal_Compile_Config_Load extends Smarty_Internal_CompileBase
* @var array * @var array
* @see Smarty_Internal_CompileBase * @see Smarty_Internal_CompileBase
*/ */
public $optional_attributes = array('section', 'scope', 'bubble_up'); public $optional_attributes = array('section', 'scope');
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $option_flags = array('nocache', 'bubble_up');
/** /**
* Valid scope names * Valid scope names
* *
* @var array * @var array
*/ */
public $valid_scopes = array('local' => true, 'parent' => true, 'root' => true, 'tpl_root' => true); public $valid_scopes = array('local' => Smarty::SCOPE_LOCAL, 'parent' => Smarty::SCOPE_PARENT,
'root' => Smarty::SCOPE_ROOT, 'tpl_root' => Smarty::SCOPE_TPL_ROOT,
'smarty' => Smarty::SCOPE_SMARTY);
/** /**
* Compiles code for the {config_load} tag * Compiles code for the {config_load} tag
@@ -72,25 +82,8 @@ class Smarty_Internal_Compile_Config_Load extends Smarty_Internal_CompileBase
} else { } else {
$section = 'null'; $section = 'null';
} }
$_scope = Smarty::SCOPE_LOCAL; // scope setup
if (isset($_attr[ 'scope' ])) { $_scope = $compiler->convertScope($_attr, $this->valid_scopes);
$_attr[ 'scope' ] = trim($_attr[ 'scope' ], "'\"");
if (!isset($this->valid_scopes[ $_attr[ 'scope' ] ])) {
$compiler->trigger_template_error("illegal value '{$_attr['scope']}' for \"scope\" attribute", null,
true);
}
if ($_attr[ 'scope' ] != 'local') {
if ($_attr[ 'scope' ] == 'parent') {
$_scope = Smarty::SCOPE_PARENT;
} elseif ($_attr[ 'scope' ] == 'root') {
$_scope = Smarty::SCOPE_ROOT;
} elseif ($_attr[ 'scope' ] == 'tpl_root') {
$_scope = Smarty::SCOPE_TPL_ROOT;
}
$_scope += (isset($_attr[ 'bubble_up' ]) && $_attr[ 'bubble_up' ] == 'false') ? 0 :
Smarty::SCOPE_BUBBLE_UP;
}
}
// create config object // create config object
$_output = $_output =

View File

@@ -148,23 +148,20 @@ class Smarty_Internal_Compile_Functionclose extends Smarty_Internal_CompileBase
$output .= "ob_start();\n"; $output .= "ob_start();\n";
$output .= "\$_smarty_tpl->compiled->has_nocache_code = true;\n"; $output .= "\$_smarty_tpl->compiled->has_nocache_code = true;\n";
$output .= $_paramsCode; $output .= $_paramsCode;
$output .= "\$_smarty_tpl->_cache['saved_tpl_vars'][] = \$_smarty_tpl->tpl_vars;\n";
$output .= "foreach (\$params as \$key => \$value) {\n\$_smarty_tpl->tpl_vars[\$key] = new Smarty_Variable(\$value);\n}"; $output .= "foreach (\$params as \$key => \$value) {\n\$_smarty_tpl->tpl_vars[\$key] = new Smarty_Variable(\$value);\n}";
$output .= "\$params = var_export(\$params, true);\n"; $output .= "\$params = var_export(\$params, true);\n";
$output .= "echo \"/*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/<?php "; $output .= "echo \"/*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/<?php ";
$output .= "\\\$saved_tpl_vars = \\\$_smarty_tpl->tpl_vars;\nforeach (\$params as \\\$key => \\\$value) {\n\\\$_smarty_tpl->tpl_vars[\\\$key] = new Smarty_Variable(\\\$value);\n}\n?>"; $output .= "\\\$_smarty_tpl->smarty->ext->_tplFunction->saveTemplateVariables(\\\$_smarty_tpl, '{$_name}');\nforeach (\$params as \\\$key => \\\$value) {\n\\\$_smarty_tpl->tpl_vars[\\\$key] = new Smarty_Variable(\\\$value);\n}\n?>";
$output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\n\";?>"; $output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\n\";?>";
$compiler->parser->current_buffer->append_subtree($compiler->parser, $compiler->parser->current_buffer->append_subtree($compiler->parser,
new Smarty_Internal_ParseTree_Tag($compiler->parser, new Smarty_Internal_ParseTree_Tag($compiler->parser,
$output)); $output));
$compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode); $compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode);
$output = "<?php echo \"/*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/<?php "; $output = "<?php echo \"/*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/<?php ";
$output .= "foreach (Smarty::\\\$global_tpl_vars as \\\$key => \\\$value){\n"; $output .= "\\\$_smarty_tpl->smarty->ext->_tplFunction->restoreTemplateVariables(\\\$_smarty_tpl, '{$_name}');?>\n";
$output .= "if (!isset(\\\$_smarty_tpl->tpl_vars[\\\$key]) || \\\$_smarty_tpl->tpl_vars[\\\$key] === \\\$value) \\\$saved_tpl_vars[\\\$key] = \\\$value;\n}\n";
$output .= "\\\$_smarty_tpl->tpl_vars = \\\$saved_tpl_vars;?>\n";
$output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\";\n?>"; $output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\";\n?>";
$output .= "<?php echo str_replace('{$compiler->template->compiled->nocache_hash}', \$_smarty_tpl->compiled->nocache_hash, ob_get_clean());\n"; $output .= "<?php echo str_replace('{$compiler->template->compiled->nocache_hash}', \$_smarty_tpl->compiled->nocache_hash, ob_get_clean());\n";
$output .= "\$_smarty_tpl->tpl_vars = array_pop(\$_smarty_tpl->_cache['saved_tpl_vars']);\n}\n}\n"; $output .= "}\n}\n";
$output .= "/*/ {$_funcName}_nocache */\n\n"; $output .= "/*/ {$_funcName}_nocache */\n\n";
$output .= "?>\n"; $output .= "?>\n";
$compiler->parser->current_buffer->append_subtree($compiler->parser, $compiler->parser->current_buffer->append_subtree($compiler->parser,
@@ -181,16 +178,13 @@ class Smarty_Internal_Compile_Functionclose extends Smarty_Internal_CompileBase
$output .= "/* {$_funcName} */\n"; $output .= "/* {$_funcName} */\n";
$output .= "if (!function_exists('{$_funcName}')) {\n"; $output .= "if (!function_exists('{$_funcName}')) {\n";
$output .= "function {$_funcName}(\$_smarty_tpl,\$params) {\n"; $output .= "function {$_funcName}(\$_smarty_tpl,\$params) {\n";
$output .= "\$saved_tpl_vars = \$_smarty_tpl->tpl_vars;\n";
$output .= $_paramsCode; $output .= $_paramsCode;
$output .= "foreach (\$params as \$key => \$value) {\n\$_smarty_tpl->tpl_vars[\$key] = new Smarty_Variable(\$value);\n}?>"; $output .= "foreach (\$params as \$key => \$value) {\n\$_smarty_tpl->tpl_vars[\$key] = new Smarty_Variable(\$value);\n}?>";
$compiler->parser->current_buffer->append_subtree($compiler->parser, $compiler->parser->current_buffer->append_subtree($compiler->parser,
new Smarty_Internal_ParseTree_Tag($compiler->parser, new Smarty_Internal_ParseTree_Tag($compiler->parser,
$output)); $output));
$compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode); $compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode);
$output = "<?php foreach (Smarty::\$global_tpl_vars as \$key => \$value){\n"; $output = "<?php\n}}\n";
$output .= "if (!isset(\$_smarty_tpl->tpl_vars[\$key]) || \$_smarty_tpl->tpl_vars[\$key] === \$value) \$saved_tpl_vars[\$key] = \$value;\n}\n";
$output .= "\$_smarty_tpl->tpl_vars = \$saved_tpl_vars;\n}\n}\n";
$output .= "/*/ {$_funcName} */\n\n"; $output .= "/*/ {$_funcName} */\n\n";
$output .= "?>\n"; $output .= "?>\n";
$compiler->parser->current_buffer->append_subtree($compiler->parser, $compiler->parser->current_buffer->append_subtree($compiler->parser,

View File

@@ -40,38 +40,26 @@ class Smarty_Internal_Compile_If extends Smarty_Internal_CompileBase
if (is_array($parameter[ 'if condition' ])) { if (is_array($parameter[ 'if condition' ])) {
if ($compiler->nocache) { if ($compiler->nocache) {
$_nocache = ',true';
// 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 = trim($parameter[ 'if condition' ][ 'var' ][ 'var' ], "'"); $var = $parameter[ 'if condition' ][ 'var' ][ 'var' ];
} else { } else {
$var = trim($parameter[ 'if condition' ][ 'var' ], "'"); $var = $parameter[ 'if condition' ][ 'var' ];
} }
if (isset($compiler->template->tpl_vars[ $var ])) { $compiler->setNocacheInVariable($var);
$compiler->template->tpl_vars[ $var ]->nocache = true;
} else {
$compiler->template->tpl_vars[ $var ] = new Smarty_Variable(null, true);
}
} else {
$_nocache = '';
} }
$assignCompiler = new Smarty_Internal_Compile_Assign();
$assignAttr = array();
$assignAttr[][ 'value' ] = $parameter[ 'if condition' ][ 'value' ];
if (is_array($parameter[ 'if condition' ][ 'var' ])) { if (is_array($parameter[ 'if condition' ][ 'var' ])) {
$_output = $assignAttr[][ 'var' ] = $parameter[ 'if condition' ][ 'var' ][ 'var' ];
"<?php if (!isset(\$_smarty_tpl->tpl_vars[" . $parameter[ 'if condition' ][ 'var' ][ 'var' ] . $_output = $assignCompiler->compile($assignAttr, $compiler,
"]) || !is_array(\$_smarty_tpl->tpl_vars[" . $parameter[ 'if condition' ][ 'var' ][ 'var' ] . array('smarty_internal_index' => $parameter[ 'if condition' ][ 'var' ][ 'smarty_internal_index' ]));
"]->value)) \$_smarty_tpl->_createLocalArrayVariable(" .
$parameter[ 'if condition' ][ 'var' ][ 'var' ] . "$_nocache);\n";
$_output .= "if (\$_smarty_tpl->tpl_vars[" . $parameter[ 'if condition' ][ 'var' ][ 'var' ] .
"]->value" . $parameter[ 'if condition' ][ 'var' ][ 'smarty_internal_index' ] . " = " .
$parameter[ 'if condition' ][ 'value' ] . ") {?>";
} else { } else {
$_output = "<?php if (!isset(\$_smarty_tpl->tpl_vars[" . $parameter[ 'if condition' ][ 'var' ] . $assignAttr[][ 'var' ] = $parameter[ 'if condition' ][ 'var' ];
"])) \$_smarty_tpl->tpl_vars[" . $parameter[ 'if condition' ][ 'var' ] . $_output = $assignCompiler->compile($assignAttr, $compiler, array());
"] = new Smarty_Variable(null{$_nocache});";
$_output .= "if (\$_smarty_tpl->tpl_vars[" . $parameter[ 'if condition' ][ 'var' ] . "]->value = " .
$parameter[ 'if condition' ][ 'value' ] . ") {?>";
} }
$_output .= "<?php if (" . $parameter[ 'if condition' ][ 'value' ] . ") {?>";
return $_output; return $_output;
} else { } else {
return "<?php if ({$parameter['if condition']}) {?>"; return "<?php if ({$parameter['if condition']}) {?>";
@@ -134,89 +122,53 @@ class Smarty_Internal_Compile_Elseif extends Smarty_Internal_CompileBase
$compiler->trigger_template_error("missing elseif condition", null, true); $compiler->trigger_template_error("missing elseif condition", null, true);
} }
$assignCode = '';
if (is_array($parameter[ 'if condition' ])) { if (is_array($parameter[ 'if condition' ])) {
$condition_by_assign = true; $condition_by_assign = true;
if ($compiler->nocache) { if ($compiler->nocache) {
$_nocache = ',true';
// 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 = trim($parameter[ 'if condition' ][ 'var' ][ 'var' ], "'"); $var = $parameter[ 'if condition' ][ 'var' ][ 'var' ];
} else { } else {
$var = trim($parameter[ 'if condition' ][ 'var' ], "'"); $var = $parameter[ 'if condition' ][ 'var' ];
}
if (isset($compiler->template->tpl_vars[ $var ])) {
$compiler->template->tpl_vars[ $var ]->nocache = true;
} else {
$compiler->template->tpl_vars[ $var ] = new Smarty_Variable(null, true);
} }
$compiler->setNocacheInVariable($var);
}
$assignCompiler = new Smarty_Internal_Compile_Assign();
$assignAttr = array();
$assignAttr[][ 'value' ] = $parameter[ 'if condition' ][ 'value' ];
if (is_array($parameter[ 'if condition' ][ 'var' ])) {
$assignAttr[][ 'var' ] = $parameter[ 'if condition' ][ 'var' ][ 'var' ];
$assignCode = $assignCompiler->compile($assignAttr, $compiler,
array('smarty_internal_index' => $parameter[ 'if condition' ][ 'var' ][ 'smarty_internal_index' ]));
} else { } else {
$_nocache = ''; $assignAttr[][ 'var' ] = $parameter[ 'if condition' ][ 'var' ];
$assignCode = $assignCompiler->compile($assignAttr, $compiler, array());
} }
} else { } else {
$condition_by_assign = false; $condition_by_assign = false;
} }
if (empty($compiler->prefix_code)) { $prefixCode = $compiler->getPrefixCode();
if (empty($prefixCode)) {
if ($condition_by_assign) { if ($condition_by_assign) {
$this->openTag($compiler, 'elseif', array($nesting + 1, $compiler->tag_nocache)); $this->openTag($compiler, 'elseif', array($nesting + 1, $compiler->tag_nocache));
if (is_array($parameter[ 'if condition' ][ 'var' ])) { $_output = $compiler->appendCode("<?php } else {\n?>", $assignCode);
$_output = "<?php } else { if (!isset(\$_smarty_tpl->tpl_vars[" . return $compiler->appendCode($_output,
$parameter[ 'if condition' ][ 'var' ][ 'var' ] . "<?php if (" . $parameter[ 'if condition' ][ 'value' ] . ") {\n?>");
"]) || !is_array(\$_smarty_tpl->tpl_vars[" .
$parameter[ 'if condition' ][ 'var' ][ 'var' ] .
"]->value)) \$_smarty_tpl->_createLocalArrayVariable(" .
$parameter[ 'if condition' ][ 'var' ][ 'var' ] . "$_nocache);\n";
$_output .= "if (\$_smarty_tpl->tpl_vars[" . $parameter[ 'if condition' ][ 'var' ][ 'var' ] .
"]->value" . $parameter[ 'if condition' ][ 'var' ][ 'smarty_internal_index' ] . " = " .
$parameter[ 'if condition' ][ 'value' ] . ") {?>";
} else {
$_output =
"<?php } else { if (!isset(\$_smarty_tpl->tpl_vars[" . $parameter[ 'if condition' ][ 'var' ] .
"])) \$_smarty_tpl->tpl_vars[" . $parameter[ 'if condition' ][ 'var' ] .
"] = new Smarty_Variable(null{$_nocache});";
$_output .= "if (\$_smarty_tpl->tpl_vars[" . $parameter[ 'if condition' ][ 'var' ] . "]->value = " .
$parameter[ 'if condition' ][ 'value' ] . ") {?>";
}
return $_output;
} else { } else {
$this->openTag($compiler, 'elseif', array($nesting, $compiler->tag_nocache)); $this->openTag($compiler, 'elseif', array($nesting, $compiler->tag_nocache));
return "<?php } elseif ({$parameter['if condition']}) {?>"; return "<?php } elseif ({$parameter['if condition']}) {?>";
} }
} else { } else {
$tmp = ''; $_output = $compiler->appendCode("<?php } else {\n?>", $prefixCode);
foreach ($compiler->prefix_code as $code) {
$tmp = $compiler->appendCode($tmp, $code);
}
$compiler->prefix_code = array();
$tmp = $compiler->appendCode("<?php } else {?>", $tmp);
$this->openTag($compiler, 'elseif', array($nesting + 1, $compiler->tag_nocache)); $this->openTag($compiler, 'elseif', array($nesting + 1, $compiler->tag_nocache));
if ($condition_by_assign) { if ($condition_by_assign) {
if (is_array($parameter[ 'if condition' ][ 'var' ])) { $_output = $compiler->appendCode($_output, $assignCode);
$_output = $compiler->appendCode($tmp, "<?php if (!isset(\$_smarty_tpl->tpl_vars[" . return $compiler->appendCode($_output,
$parameter[ 'if condition' ][ 'var' ][ 'var' ] . "<?php if (" . $parameter[ 'if condition' ][ 'value' ] . ") {\n?>");
"]) || !is_array(\$_smarty_tpl->tpl_vars[" .
$parameter[ 'if condition' ][ 'var' ][ 'var' ] .
"]->value)) \$_smarty_tpl->_createLocalArrayVariable(" .
$parameter[ 'if condition' ][ 'var' ][ 'var' ] .
"$_nocache);\n");
$_output .= "if (\$_smarty_tpl->tpl_vars[" . $parameter[ 'if condition' ][ 'var' ][ 'var' ] .
"]->value" . $parameter[ 'if condition' ][ 'var' ][ 'smarty_internal_index' ] . " = " .
$parameter[ 'if condition' ][ 'value' ] . ") {?>";
} else {
$_output = $compiler->appendCode($tmp, "<?php if (!isset(\$_smarty_tpl->tpl_vars[" .
$parameter[ 'if condition' ][ 'var' ] .
"])) \$_smarty_tpl->tpl_vars[" .
$parameter[ 'if condition' ][ 'var' ] .
"] = new Smarty_Variable(null{$_nocache});");
$_output .= "if (\$_smarty_tpl->tpl_vars[" . $parameter[ 'if condition' ][ 'var' ] . "]->value = " .
$parameter[ 'if condition' ][ 'value' ] . ") {?>";
}
return $_output;
} else { } else {
return $compiler->appendCode($tmp, "<?php if ({$parameter['if condition']}) {?>"); return $compiler->appendCode($_output, "<?php if ({$parameter['if condition']}) {?>");
} }
} }
} }

View File

@@ -58,7 +58,9 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase
* *
* @var array * @var array
*/ */
public $valid_scopes = array('local' => true, 'parent' => true, 'root' => true, 'tpl_root' => true); public $valid_scopes = array('parent' => Smarty::SCOPE_PARENT, 'root' => Smarty::SCOPE_ROOT,
'global' => Smarty::SCOPE_GLOBAL, 'tpl_root' => Smarty::SCOPE_TPL_ROOT,
'smarty' => Smarty::SCOPE_SMARTY);
/** /**
* Compiles code for the {include} tag * Compiles code for the {include} tag
@@ -106,31 +108,8 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase
$variable_template = true; $variable_template = true;
} }
if (isset($_attr[ 'assign' ])) {
// output will be stored in a smarty variable instead of being displayed
$_assign = $_attr[ 'assign' ];
}
// scope setup // scope setup
$_scope = Smarty::SCOPE_LOCAL; $_scope = $compiler->convertScope($_attr, $this->valid_scopes);
if (isset($_attr[ 'scope' ])) {
$_attr[ 'scope' ] = trim($_attr[ 'scope' ], "'\"");
if (!isset($this->valid_scopes[ $_attr[ 'scope' ] ])) {
$compiler->trigger_template_error("illegal value '{$_attr['scope']}' for \"scope\" attribute", null,
true);
}
if ($_attr[ 'scope' ] != 'local') {
if ($_attr[ 'scope' ] == 'parent') {
$_scope = Smarty::SCOPE_PARENT;
} elseif ($_attr[ 'scope' ] == 'root') {
$_scope = Smarty::SCOPE_ROOT;
} elseif ($_attr[ 'scope' ] == 'tpl_root') {
$_scope = Smarty::SCOPE_TPL_ROOT;
}
$_scope += (isset($_attr[ 'bubble_up' ]) && $_attr[ 'bubble_up' ] == 'false') ? 0 :
Smarty::SCOPE_BUBBLE_UP;
}
}
// set flag to cache subtemplate object when called within loop or template name is variable. // set flag to cache subtemplate object when called within loop or template name is variable.
if ($cache_tpl || $variable_template || $compiler->loopNesting > 0) { if ($cache_tpl || $variable_template || $compiler->loopNesting > 0) {
@@ -156,28 +135,14 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase
$merge_compiled_includes = ($compiler->smarty->merge_compiled_includes || $_attr[ 'inline' ] === true) && $merge_compiled_includes = ($compiler->smarty->merge_compiled_includes || $_attr[ 'inline' ] === true) &&
!$compiler->template->source->handler->recompiled; !$compiler->template->source->handler->recompiled;
if ($merge_compiled_includes && $_attr[ 'inline' ] !== true) { if ($merge_compiled_includes) {
// variable template name ? // variable template name ?
if ($variable_template) { if ($variable_template) {
$merge_compiled_includes = false; $merge_compiled_includes = false;
if ($compiler->template->caching) {
// must use individual cache file
//$_attr['caching'] = 1;
}
} }
// variable compile_id? // variable compile_id?
if (isset($_attr[ 'compile_id' ])) { if (isset($_attr[ 'compile_id' ]) && $compiler->isVariable($_attr[ 'compile_id' ])) {
if (!((substr_count($_attr[ 'compile_id' ], '"') == 2 || $merge_compiled_includes = false;
substr_count($_attr[ 'compile_id' ], "'") == 2 || is_numeric($_attr[ 'compile_id' ]))) ||
substr_count($_attr[ 'compile_id' ], '(') != 0 ||
substr_count($_attr[ 'compile_id' ], '$_smarty_tpl->') != 0
) {
$merge_compiled_includes = false;
if ($compiler->template->caching) {
// must use individual cache file
//$_attr['caching'] = 1;
}
}
} }
} }
@@ -217,6 +182,19 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase
if ($compiler->template->caching && $call_nocache) { if ($compiler->template->caching && $call_nocache) {
$merge_compiled_includes = false; $merge_compiled_includes = false;
} }
// assign attribute
if (isset($_attr[ 'assign' ])) {
// 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) {
// create nocache var to make it know for further compiling
$compiler->setNocacheInVariable($_attr[ 'assign' ]);
}
} else {
$_assign = $_attr[ 'assign' ];
}
}
$has_compiled_template = false; $has_compiled_template = false;
if ($merge_compiled_includes) { if ($merge_compiled_includes) {
@@ -235,20 +213,14 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase
unset($_attr[ 'file' ], $_attr[ 'assign' ], $_attr[ 'cache_id' ], $_attr[ 'compile_id' ], $_attr[ 'cache_lifetime' ], $_attr[ 'nocache' ], $_attr[ 'caching' ], $_attr[ 'scope' ], $_attr[ 'inline' ], $_attr[ 'bubble_up' ]); unset($_attr[ 'file' ], $_attr[ 'assign' ], $_attr[ 'cache_id' ], $_attr[ 'compile_id' ], $_attr[ 'cache_lifetime' ], $_attr[ 'nocache' ], $_attr[ 'caching' ], $_attr[ 'scope' ], $_attr[ 'inline' ], $_attr[ 'bubble_up' ]);
// remaining attributes must be assigned as smarty variable // remaining attributes must be assigned as smarty variable
$_vars_nc = ''; $_vars_nc = '';
$_vars = 'array()';
if (!empty($_attr)) { if (!empty($_attr)) {
if ($_scope == Smarty::SCOPE_LOCAL) { $_pairs = array();
$_pairs = array(); // create variables
// create variables foreach ($_attr as $key => $value) {
foreach ($_attr as $key => $value) { $_pairs[] = "'$key'=>$value";
$_pairs[] = "'$key'=>$value";
$_vars_nc .= "\$_smarty_tpl->tpl_vars['$key'] = new Smarty_Variable($value);\n";
}
$_vars = 'array(' . join(',', $_pairs) . ')';
} else {
$compiler->trigger_template_error('variable passing not allowed in parent/global scope', null, true);
} }
} else { $_vars = 'array(' . join(',', $_pairs) . ')';
$_vars = 'array()';
} }
$update_compile_id = $compiler->template->caching && !$compiler->tag_nocache && !$compiler->nocache && $update_compile_id = $compiler->template->caching && !$compiler->tag_nocache && !$compiler->nocache &&
$_compile_id != '$_smarty_tpl->compile_id'; $_compile_id != '$_smarty_tpl->compile_id';
@@ -257,10 +229,11 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase
if ($update_compile_id) { if ($update_compile_id) {
$_output .= $compiler->makeNocacheCode("\$_compile_id_save[] = \$_smarty_tpl->compile_id;\n\$_smarty_tpl->compile_id = {$_compile_id};\n"); $_output .= $compiler->makeNocacheCode("\$_compile_id_save[] = \$_smarty_tpl->compile_id;\n\$_smarty_tpl->compile_id = {$_compile_id};\n");
} }
if (!empty($_vars_nc) && $_caching == 9999 && $compiler->template->caching) { if (!empty($_attr) && $_caching == 9999 && $compiler->template->caching) {
//$compiler->suppressNocacheProcessing = false; $_vars_nc = "foreach ($_vars as \$ik => \$iv) {\n";
$_vars_nc .= "\$_smarty_tpl->tpl_vars[\$ik] = new Smarty_Variable(\$iv);\n";
$_vars_nc .= "}\n";
$_output .= substr($compiler->processNocacheCode('<?php ' . $_vars_nc . "?>\n", true), 6, - 3); $_output .= substr($compiler->processNocacheCode('<?php ' . $_vars_nc . "?>\n", true), 6, - 3);
//$compiler->suppressNocacheProcessing = true;
} }
if (isset($_assign)) { if (isset($_assign)) {
$_output .= "ob_start();\n"; $_output .= "ob_start();\n";

View File

@@ -39,44 +39,37 @@ class Smarty_Internal_Compile_While extends Smarty_Internal_CompileBase
// maybe nocache because of nocache variables // maybe nocache because of nocache variables
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache; $compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
$_output = "<?php\n";
if (is_array($parameter[ 'if condition' ])) { if (is_array($parameter[ 'if condition' ])) {
if ($compiler->nocache) { if ($compiler->nocache) {
$_nocache = ',true'; $_nocache = ',true';
// 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 = trim($parameter[ 'if condition' ][ 'var' ][ 'var' ], "'"); $var = $parameter[ 'if condition' ][ 'var' ][ 'var' ];
} else { } else {
$var = trim($parameter[ 'if condition' ][ 'var' ], "'"); $var = $parameter[ 'if condition' ][ 'var' ];
}
if (isset($compiler->template->tpl_vars[ $var ])) {
$compiler->template->tpl_vars[ $var ]->nocache = true;
} else {
$compiler->template->tpl_vars[ $var ] = new Smarty_Variable(null, true);
} }
$compiler->setNocacheInVariable($var);
} else { } else {
$_nocache = ''; $_nocache = '';
} }
$assignCompiler = new Smarty_Internal_Compile_Assign();
$assignAttr = array();
$assignAttr[][ 'value' ] = $parameter[ 'if condition' ][ 'value' ];
if (is_array($parameter[ 'if condition' ][ 'var' ])) { if (is_array($parameter[ 'if condition' ][ 'var' ])) {
$_output .= "if (!isset(\$_smarty_tpl->tpl_vars[" . $parameter[ 'if condition' ][ 'var' ][ 'var' ] . $assignAttr[][ 'var' ] = $parameter[ 'if condition' ][ 'var' ][ 'var' ];
"]) || !is_array(\$_smarty_tpl->tpl_vars[" . $_output = "<?php while (" . $parameter[ 'if condition' ][ 'value' ] . ") {?>";
$parameter[ 'if condition' ][ 'var' ][ 'var' ] . $_output .= $assignCompiler->compile($assignAttr, $compiler,
"]->value)) \$_smarty_tpl->_createLocalArrayVariable(" . array('smarty_internal_index' => $parameter[ 'if condition' ][ 'var' ][ 'smarty_internal_index' ]));
$parameter[ 'if condition' ][ 'var' ][ 'var' ] . "$_nocache);\n";
$_output .= "while (\$_smarty_tpl->tpl_vars[" . $parameter[ 'if condition' ][ 'var' ][ 'var' ] .
"]->value" . $parameter[ 'if condition' ][ 'var' ][ 'smarty_internal_index' ] . " = " .
$parameter[ 'if condition' ][ 'value' ] . ") {?>";
} else { } else {
$_output .= "if (!isset(\$_smarty_tpl->tpl_vars[" . $parameter[ 'if condition' ][ 'var' ] . $assignAttr[][ 'var' ] = $parameter[ 'if condition' ][ 'var' ];
"])) \$_smarty_tpl->tpl_vars[" . $parameter[ 'if condition' ][ 'var' ] . $_output = "<?php while (" . $parameter[ 'if condition' ][ 'value' ] . ") {?>";
"] = new Smarty_Variable(null{$_nocache});"; $_output .= $assignCompiler->compile($assignAttr, $compiler, array());
$_output .= "while (\$_smarty_tpl->tpl_vars[" . $parameter[ 'if condition' ][ 'var' ] . "]->value = " .
$parameter[ 'if condition' ][ 'value' ] . ") {?>";
} }
return $_output;
} else { } else {
$_output .= "while ({$parameter['if condition']}) {?>"; return "<?php\n while ({$parameter['if condition']}) {?>";
} }
return $_output;
} }
} }

View File

@@ -96,17 +96,16 @@ class Smarty_Internal_Data
if (is_array($tpl_var)) { if (is_array($tpl_var)) {
foreach ($tpl_var as $_key => $_val) { foreach ($tpl_var as $_key => $_val) {
if ($_key != '') { if ($_key != '') {
$this->tpl_vars[ $_key ] = new Smarty_Variable($_val, $nocache); $this->assign($_key, $_val, $nocache);
if ($this->_objType == 2 && $this->scope) {
$this->ext->_updateScope->updateScope($this, $_key);
}
} }
} }
} else { } else {
if ($tpl_var != '') { if ($tpl_var != '') {
$this->tpl_vars[ $tpl_var ] = new Smarty_Variable($value, $nocache); if ($this->_objType == 2) {
if ($this->_objType == 2 && $this->scope) { /** @var Smarty_Internal_Template $this */
$this->ext->_updateScope->updateScope($this, $tpl_var); $this->_assignInScope($tpl_var, $value, $nocache);
} else {
$this->tpl_vars[ $tpl_var ] = new Smarty_Variable($value, $nocache);
} }
} }
} }

View File

@@ -66,7 +66,7 @@ class Smarty_Internal_Method_Append
} }
} }
if ($data->_objType == 2 && $data->scope) { if ($data->_objType == 2 && $data->scope) {
$data->ext->_updateScope->updateScope($data, $tpl_var); $data->ext->_updateScope->_updateScope($data, $tpl_var);
} }
} }
return $data; return $data;

View File

@@ -42,7 +42,7 @@ class Smarty_Internal_Method_AppendByRef
$data->tpl_vars[ $tpl_var ]->value[] = &$value; $data->tpl_vars[ $tpl_var ]->value[] = &$value;
} }
if ($data->_objType == 2 && $data->scope) { if ($data->_objType == 2 && $data->scope) {
$data->ext->_updateScope->updateScope($data, $tpl_var); $data->ext->_updateScope->_updateScope($data, $tpl_var);
} }
} }
return $data; return $data;

View File

@@ -28,7 +28,7 @@ class Smarty_Internal_Method_AssignByRef
$data->tpl_vars[ $tpl_var ] = new Smarty_Variable(null, $nocache); $data->tpl_vars[ $tpl_var ] = new Smarty_Variable(null, $nocache);
$data->tpl_vars[ $tpl_var ]->value = &$value; $data->tpl_vars[ $tpl_var ]->value = &$value;
if ($data->_objType == 2 && $data->scope) { if ($data->_objType == 2 && $data->scope) {
$data->ext->_updateScope->updateScope($data, $tpl_var); $data->ext->_updateScope->_updateScope($data, $tpl_var);
} }
} }
return $data; return $data;

View File

@@ -34,7 +34,7 @@ class Smarty_Internal_Method_ConfigLoad
*/ */
public function configLoad(Smarty_Internal_Data $data, $config_file, $sections = null) public function configLoad(Smarty_Internal_Data $data, $config_file, $sections = null)
{ {
$this->_loadConfigFile($data, $config_file, $sections, 0); $this->_loadConfigFile($data, $config_file, $sections, null);
return $data; return $data;
} }
@@ -82,39 +82,15 @@ class Smarty_Internal_Method_ConfigLoad
public function _loadConfigVars(Smarty_Internal_Template $tpl, $_config_vars) public function _loadConfigVars(Smarty_Internal_Template $tpl, $_config_vars)
{ {
$this->_assignConfigVars($tpl->parent, $tpl, $_config_vars); $this->_assignConfigVars($tpl->parent, $tpl, $_config_vars);
$scope = $tpl->source->scope; if ($tpl->parent->_objType == 2 && ($tpl->source->scope || $tpl->parent->scope)) {
$scopes = array(); $scope = $tpl->source->scope | $tpl->scope;
if ($scope) { if ($scope) {
$scopes[] = $scope; // update scopes
} foreach ($tpl->smarty->ext->_updateScope->_getAffectedScopes($tpl->parent, $scope) as $ptr) {
if ($tpl->scope) {
$scopes[] = $tpl->scope;
}
if (empty($scopes)) {
return;
}
foreach ($scopes as $s) {
$s = ($bubble_up = $s >= Smarty::SCOPE_BUBBLE_UP) ? $s - Smarty::SCOPE_BUBBLE_UP : $s;
if ($bubble_up && $s) {
$ptr = $tpl->parent->parent;
if (isset($ptr)) {
$this->_assignConfigVars($ptr, $tpl, $_config_vars); $this->_assignConfigVars($ptr, $tpl, $_config_vars);
$ptr = $ptr->parent;
} }
if ($s == Smarty::SCOPE_PARENT) { if ($scope & Smarty::SCOPE_LOCAL) {
continue; //$this->_updateVarStack($tpl, $varName);
}
while (isset($ptr) && $ptr->_objType == 2) {
$this->_assignConfigVars($ptr, $tpl, $_config_vars);
$ptr = $ptr->parent;
}
if ($s == Smarty::SCOPE_TPL_ROOT) {
continue;
} elseif ($s == Smarty::SCOPE_ROOT) {
while (isset($ptr->parent)) {
$ptr = $ptr->parent;
$this->_assignConfigVars($ptr, $tpl, $_config_vars);
}
} }
} }
} }

View File

@@ -33,12 +33,16 @@ class Smarty_Internal_Runtime_TplFunction
} }
} }
if (function_exists($function)) { if (function_exists($function)) {
$this->saveTemplateVariables($tpl, $name);
$function ($tpl, $params); $function ($tpl, $params);
$this->restoreTemplateVariables($tpl, $name);
return; return;
} }
// try to load template function dynamically // try to load template function dynamically
if ($this->addTplFuncToCache($tpl, $name, $function)) { if ($this->addTplFuncToCache($tpl, $name, $function)) {
$this->saveTemplateVariables($tpl, $name);
$function ($tpl, $params); $function ($tpl, $params);
$this->restoreTemplateVariables($tpl, $name);
return; return;
} }
} }
@@ -86,7 +90,7 @@ class Smarty_Internal_Runtime_TplFunction
$tplPtr->smarty->ext->_updateCache->write($cache, $tplPtr, $tplPtr->smarty->ext->_updateCache->write($cache, $tplPtr,
preg_replace('/\s*\?>\s*$/', "\n", $content) . preg_replace('/\s*\?>\s*$/', "\n", $content) .
"\n" . preg_replace(array('/^\s*<\?php\s+/', "\n" . preg_replace(array('/^\s*<\?php\s+/',
'/\s*\?>\s*$/'), "\n", '/\s*\?>\s*$/',), "\n",
$match[ 0 ])); $match[ 0 ]));
} }
} }
@@ -96,4 +100,31 @@ class Smarty_Internal_Runtime_TplFunction
} }
return false; return false;
} }
/**
* Save current template variables on stack
*
* @param \Smarty_Internal_Template $tpl
* @param string $name stack name
*/
public function saveTemplateVariables(Smarty_Internal_Template $tpl, $name)
{
$tpl->_cache[ 'varStack' ][] =
array('tpl' => $tpl->tpl_vars, 'config' => $tpl->config_vars, 'name' => "_tplFunction_{$name}");
}
/**
* Restore saved variables into template objects
*
* @param \Smarty_Internal_Template $tpl
* @param string $name stack name
*/
public function restoreTemplateVariables(Smarty_Internal_Template $tpl, $name)
{
if (isset($tpl->_cache[ 'varStack' ])) {
$vars = array_pop($tpl->_cache[ 'varStack' ]);
$tpl->tpl_vars = $vars[ 'tpl' ];
$tpl->config_vars = $vars[ 'config' ];
}
}
} }

View File

@@ -10,65 +10,101 @@
**/ **/
class Smarty_Internal_Runtime_UpdateScope class Smarty_Internal_Runtime_UpdateScope
{ {
/** /**
* Update new assigned template variable in other effected scopes * Update new assigned template or config variable in other effected scopes
*
* @param Smarty_Internal_Template $tpl data object
* @param string|null $varName variable name
* @param int $scope scope to which bubble up variable value
* *
* @param \Smarty_Internal_Data $tpl data object
* @param string $varName variable name
* @param int $scope scope to which bubble up variable value
*/ */
public function updateScope(Smarty_Internal_Data $tpl, $varName, $scope = Smarty::SCOPE_LOCAL) public function _updateScope(Smarty_Internal_Template $tpl, $varName, $scope = 0)
{ {
$scopes = array(); $scope = $scope | $tpl->scope;
if ($scope) { if ($scope) {
$scopes[] = $scope; if ($scope & Smarty::SCOPE_GLOBAL && $varName) {
} Smarty::$global_tpl_vars[ $varName ] = $tpl->tpl_vars[ $varName ];
if ($tpl->scope) { }
$scopes[] = $tpl->scope; // update scopes
} foreach ($this->_getAffectedScopes($tpl, $scope) as $ptr) {
if (empty($scopes)) { $this->_updateObject($ptr, $tpl, $varName);
return; }
} if ($scope & Smarty::SCOPE_LOCAL) {
/* @var Smarty_Internal_Data $ptr */ $this->_updateVarStack($tpl, $varName);
$ptr = null;
foreach ($scopes as $s) {
$s = ($bubble_up = $s >= Smarty::SCOPE_BUBBLE_UP) ? $s - Smarty::SCOPE_BUBBLE_UP : $s;
if ($bubble_up && $s) {
$oldGlobal = null;
if ($s == Smarty::SCOPE_GLOBAL) {
$oldGlobal =
isset(Smarty::$global_tpl_vars[ $varName ]) ? Smarty::$global_tpl_vars[ $varName ] : null;
Smarty::$global_tpl_vars[ $varName ] = $tpl->tpl_vars[ $varName ];
}
if (isset($tpl->parent) && $tpl->parent->_objType == 2) {
$ptr = $tpl->parent;
if ($s == Smarty::SCOPE_GLOBAL && isset($oldGlobal) && isset($ptr->tpl_vars[ $varName ]) &&
$ptr->tpl_vars[ $varName ] !== $oldGlobal
) {
continue;
}
$ptr->tpl_vars[ $varName ] = $tpl->tpl_vars[ $varName ];
if (isset($ptr->parent)) {
$ptr = $ptr->parent;
}
} elseif (isset($tpl->parent)) {
$ptr = $tpl->parent;
}
if ($s == Smarty::SCOPE_PARENT) {
continue;
}
while (isset($ptr) && $ptr->_objType == 2) {
$ptr->tpl_vars[ $varName ] = $tpl->tpl_vars[ $varName ];
$ptr = $ptr->parent;
}
if ($s == Smarty::SCOPE_TPL_ROOT) {
continue;
}
while (isset($ptr) && $s != Smarty::SCOPE_GLOBAL) {
$ptr->tpl_vars[ $varName ] = $tpl->tpl_vars[ $varName ];
$ptr = isset($ptr->parent) ? $ptr->parent : null;
}
} }
} }
} }
/**
* Get array of objects which needs to be updated by given scope value
*
* @param Smarty_Internal_Template $tpl
* @param int $scope scope to which bubble up variable value
*
* @return array
*/
public function _getAffectedScopes(Smarty_Internal_Template $tpl, $scope)
{
$_stack = array();
$ptr = $tpl->parent;
while (isset($ptr) && $ptr->_objType == 2) {
if (($scope & Smarty::SCOPE_BUBBLE_UP) || ($scope & Smarty::SCOPE_PARENT)) {
$_stack[] = $ptr;
$scope = $scope & ~Smarty::SCOPE_PARENT;
} elseif (($scope & Smarty::SCOPE_TPL_ROOT) && (!isset($ptr->parent) || $ptr->parent->_objType != 2)) {
$_stack[] = $ptr;
}
$ptr = $ptr->parent;
}
if ($scope & Smarty::SCOPE_SMARTY) {
if (isset($tpl->smarty)) {
$_stack[] = $tpl->smarty;
}
} elseif ($scope & Smarty::SCOPE_ROOT) {
while (isset($ptr)) {
if ($ptr->_objType != 2) {
$_stack[] = $ptr;
break;
}
$ptr = $ptr->parent;
}
}
return $_stack;
}
/**
* Update variable in object
*
* @param \Smarty_Internal_Data $to
* @param \Smarty_Internal_Template $from
* @param string|null $varName variable name
*/
public function _updateObject(Smarty_Internal_Data $to, Smarty_Internal_Template $from, $varName)
{
if (!isset($to->tpl_vars[ $varName ])) {
$to->tpl_vars[ $varName ] = clone $from->tpl_vars[ $varName ];
} else {
$to->tpl_vars[ $varName ] = clone $to->tpl_vars[ $varName ];
$to->tpl_vars[ $varName ]->value = $from->tpl_vars[ $varName ]->value;
}
if ($to->_objType == 2) {
$this->_updateVarStack($to, $varName);
}
}
/**
* Update variable in template local variable stack
*
* @param \Smarty_Internal_Template $tpl
* @param string|null $varName variable name or null for config variables
*/
public function _updateVarStack(Smarty_Internal_Template $tpl, $varName)
{
$i = 0;
while (isset($tpl->_cache[ 'varStack' ][ $i ])) {
$tpl->_cache[ 'varStack' ][ $i ][ 'tpl' ][ $varName ] = $tpl->tpl_vars[ $varName ];
$i ++;
}
}
} }

View File

@@ -75,7 +75,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
public $tpl_function = array(); public $tpl_function = array();
/** /**
* Scope in which template is rendered * Scope in which variables shall be assigned
* *
* @var int * @var int
*/ */
@@ -295,23 +295,6 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
} }
// set template scope // set template scope
$tpl->scope = $scope; $tpl->scope = $scope;
$scopePtr = false;
$scope = $scope & ~Smarty::SCOPE_BUBBLE_UP;
if ($scope) {
if ($scope == Smarty::SCOPE_PARENT) {
$scopePtr = $this;
} else {
$scopePtr = $tpl;
while (isset($scopePtr->parent)) {
if (!$scopePtr->_isParentTemplate() && $scope & Smarty::SCOPE_TPL_ROOT) {
break;
}
$scopePtr = $scopePtr->parent;
}
}
$tpl->tpl_vars = $scopePtr->tpl_vars;
$tpl->config_vars = $scopePtr->config_vars;
}
if (!isset($tpl->smarty->_cache[ 'tplObjects' ][ $tpl->templateId ]) && !$tpl->source->handler->recompiled) { if (!isset($tpl->smarty->_cache[ 'tplObjects' ][ $tpl->templateId ]) && !$tpl->source->handler->recompiled) {
// if template is called multiple times set flag to to cache template objects // if template is called multiple times set flag to to cache template objects
$forceTplCache = $forceTplCache || $forceTplCache = $forceTplCache ||
@@ -351,10 +334,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
$tpl->render(); $tpl->render();
} }
} }
if ($scopePtr) { $i = 0;
$scopePtr->tpl_vars = $tpl->tpl_vars;
$scopePtr->config_vars = $tpl->config_vars;
}
} }
/** /**
@@ -385,45 +365,25 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
/** /**
* Assign variable in scope * Assign variable in scope
* *
* @param string $varName variable name * @param string $varName variable name
* @param mixed $value value * @param mixed $value value
* @param bool $nocache nocache flag * @param bool $nocache nocache flag
* @param int $scope scope into which variable shall be assigned * @param int $scope scope into which variable shall be assigned
* @param bool $smartyBC true if called in Smarty bc class
* *
* @throws \SmartyException
*/ */
public function _assignInScope($varName, $value, $nocache, $scope, $smartyBC) public function _assignInScope($varName, $value, $nocache = false, $scope = 0)
{ {
if ($smartyBC && isset($this->tpl_vars[ $varName ])) { if (isset($this->tpl_vars[ $varName ])) {
$this->tpl_vars[ $varName ] = clone $this->tpl_vars[ $varName ]; $this->tpl_vars[ $varName ] = clone $this->tpl_vars[ $varName ];
$this->tpl_vars[ $varName ]->value = $value; $this->tpl_vars[ $varName ]->value = $value;
$this->tpl_vars[ $varName ]->nocache = $nocache; if ($nocache) {
$this->tpl_vars[ $varName ]->nocache = $nocache;
}
} else { } else {
$this->tpl_vars[ $varName ] = new Smarty_Variable($value, $nocache); $this->tpl_vars[ $varName ] = new Smarty_Variable($value, $nocache);
} }
if ($scope || $this->scope & Smarty::SCOPE_BUBBLE_UP) { if (isset($scope) || isset($this->scope)) {
$this->ext->_updateScope->updateScope($this, $varName, $scope); $this->smarty->ext->_updateScope->_updateScope($this, $varName, $scope);
}
}
/**
* Template code runtime function to create a local Smarty variable for array assignments
*
* @param string $varName template variable name
* @param bool $nocache cache mode of variable
*/
public function _createLocalArrayVariable($varName, $nocache = false)
{
if (!isset($this->tpl_vars[ $varName ])) {
$this->tpl_vars[ $varName ] = new Smarty_Variable(array(), $nocache);
} else {
$this->tpl_vars[ $varName ] = clone $this->tpl_vars[ $varName ];
if (!(is_array($this->tpl_vars[ $varName ]->value) ||
$this->tpl_vars[ $varName ]->value instanceof ArrayAccess)
) {
settype($this->tpl_vars[ $varName ]->value, 'array');
}
} }
} }

View File

@@ -384,7 +384,7 @@ abstract class Smarty_Internal_TemplateCompilerBase
// add file dependency // add file dependency
$this->parent_compiler->template->compiled->file_dependency[ $this->template->source->uid ] = $this->parent_compiler->template->compiled->file_dependency[ $this->template->source->uid ] =
array($this->template->source->filepath, $this->template->source->getTimeStamp(), array($this->template->source->filepath, $this->template->source->getTimeStamp(),
$this->template->source->type); $this->template->source->type,);
$this->smarty->_current_file = $this->template->source->filepath; $this->smarty->_current_file = $this->template->source->filepath;
// get template source // get template source
if (!empty($this->template->source->components)) { if (!empty($this->template->source->components)) {
@@ -563,7 +563,7 @@ abstract class Smarty_Internal_TemplateCompilerBase
} }
} }
// check if tag is registered // check if tag is registered
foreach (array(Smarty::PLUGIN_COMPILER, Smarty::PLUGIN_FUNCTION, Smarty::PLUGIN_BLOCK) as $plugin_type) foreach (array(Smarty::PLUGIN_COMPILER, Smarty::PLUGIN_FUNCTION, Smarty::PLUGIN_BLOCK,) as $plugin_type)
{ {
if (isset($this->smarty->registered_plugins[ $plugin_type ][ $tag ])) { if (isset($this->smarty->registered_plugins[ $plugin_type ][ $tag ])) {
// if compiler function plugin call it now // if compiler function plugin call it now
@@ -817,7 +817,7 @@ abstract class Smarty_Internal_TemplateCompilerBase
'#(:SMARTY@!@|>)\s+(?=@!@SMARTY:|<)#s' => '\1\2', '#(:SMARTY@!@|>)\s+(?=@!@SMARTY:|<)#s' => '\1\2',
// remove spaces between attributes (but not in attribute values!) // remove spaces between attributes (but not in attribute values!)
'#(([a-z0-9]\s*=\s*("[^"]*?")|(\'[^\']*?\'))|<[a-z0-9_]+)\s+([a-z/>])#is' => '\1 \5', '#(([a-z0-9]\s*=\s*("[^"]*?")|(\'[^\']*?\'))|<[a-z0-9_]+)\s+([a-z/>])#is' => '\1 \5',
'#^\s+<#Ss' => '<', '#>\s+$#Ss' => '>', $this->stripRegEx => ''); '#^\s+<#Ss' => '<', '#>\s+$#Ss' => '>', $this->stripRegEx => '',);
$text = preg_replace(array_keys($expressions), array_values($expressions), $text); $text = preg_replace(array_keys($expressions), array_values($expressions), $text);
$_offset = 0; $_offset = 0;
@@ -960,7 +960,7 @@ abstract class Smarty_Internal_TemplateCompilerBase
$script = null; $script = null;
$cacheable = true; $cacheable = true;
$result = call_user_func_array($this->smarty->default_plugin_handler_func, $result = call_user_func_array($this->smarty->default_plugin_handler_func,
array($tag, $plugin_type, $this->template, &$callback, &$script, &$cacheable)); array($tag, $plugin_type, $this->template, &$callback, &$script, &$cacheable,));
if ($result) { if ($result) {
$this->tag_nocache = $this->tag_nocache || !$cacheable; $this->tag_nocache = $this->tag_nocache || !$cacheable;
if ($script !== null) { if ($script !== null) {
@@ -1118,7 +1118,7 @@ abstract class Smarty_Internal_TemplateCompilerBase
*/ */
public function convertScope($_attr, $validScopes) public function convertScope($_attr, $validScopes)
{ {
$_scope = Smarty::SCOPE_LOCAL; $_scope = 0;
if (isset($_attr[ 'scope' ])) { if (isset($_attr[ 'scope' ])) {
$_scopeName = trim($_attr[ 'scope' ], "'\""); $_scopeName = trim($_attr[ 'scope' ], "'\"");
if (is_numeric($_scopeName) && in_array($_scopeName, $validScopes)) { if (is_numeric($_scopeName) && in_array($_scopeName, $validScopes)) {
@@ -1133,7 +1133,7 @@ abstract class Smarty_Internal_TemplateCompilerBase
$err = var_export($_scopeName, true); $err = var_export($_scopeName, true);
$this->trigger_template_error("illegal value '{$err}' for \"scope\" attribute", null, true); $this->trigger_template_error("illegal value '{$err}' for \"scope\" attribute", null, true);
} }
if (isset($_attr[ 'bubble_up' ]) && $_attr[ 'bubble_up' ]) { if (isset($_attr[ 'bubble_up' ]) && $_attr[ 'bubble_up' ] && $_scope > 2) {
$_scope += Smarty::SCOPE_BUBBLE_UP; $_scope += Smarty::SCOPE_BUBBLE_UP;
} }
} }
@@ -1291,4 +1291,22 @@ abstract class Smarty_Internal_TemplateCompilerBase
{ {
$this->prefix_code[] = $code; $this->prefix_code[] = $code;
} }
/**
* get prefix code string
*
* @return string
*/
public function getPrefixCode()
{
$code = '';
$prefixArray = array_merge($this->prefix_code, array_pop($this->prefixCodeStack));
$this->prefixCodeStack[] = array();
foreach ($prefixArray as $c) {
$code = $this->appendCode($code, $c);
}
$this->prefix_code = array();
return $code;
}
} }

View File

@@ -28,9 +28,9 @@ class Smarty_Template_Config extends Smarty_Template_Source
/** /**
* scope into which the config variables shall be loaded * scope into which the config variables shall be loaded
* *
* @var string * @var int
*/ */
public $scope = 'local'; public $scope = 0;
/** /**
* Flag that source is a config file * Flag that source is a config file