diff --git a/NEW_FEATURES.txt b/NEW_FEATURES.txt index 5d130a94..904e8ad7 100644 --- a/NEW_FEATURES.txt +++ b/NEW_FEATURES.txt @@ -4,6 +4,58 @@ This file contains a brief description of new features which have been added to 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 does now observe the template_dir setting and will create separate cache files if required diff --git a/change_log.txt b/change_log.txt index 79a12af5..40e07e6d 100644 --- a/change_log.txt +++ b/change_log.txt @@ -2,6 +2,7 @@ 09.02.2016 - move some code from parser into compiler - reformat all code for unique style + - update/bugfix scope attribute handling reworked. Read the newfeatures.txt file 05.02.2016 - improvement internal compiler changes diff --git a/libs/Smarty.class.php b/libs/Smarty.class.php index f10d345a..644bdb54 100644 --- a/libs/Smarty.class.php +++ b/libs/Smarty.class.php @@ -121,12 +121,12 @@ class Smarty extends Smarty_Internal_TemplateBase /** * smarty version */ - const SMARTY_VERSION = '3.1.30-dev/30'; + const SMARTY_VERSION = '3.1.30-dev/31'; /** * define variable scopes */ - const SCOPE_LOCAL = 0; + const SCOPE_LOCAL = 1; const SCOPE_PARENT = 2; @@ -134,6 +134,8 @@ class Smarty extends Smarty_Internal_TemplateBase const SCOPE_ROOT = 8; + const SCOPE_SMARTY = 16; + const SCOPE_GLOBAL = 32; const SCOPE_BUBBLE_UP = 64; diff --git a/libs/sysplugins/smarty_internal_compile_assign.php b/libs/sysplugins/smarty_internal_compile_assign.php index 807ca22e..73e60e5b 100644 --- a/libs/sysplugins/smarty_internal_compile_assign.php +++ b/libs/sysplugins/smarty_internal_compile_assign.php @@ -16,13 +16,22 @@ */ 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 * * @var array */ - public $valid_scopes = array('local' => true, 'parent' => true, 'root' => true, 'global' => true, - 'tpl_root' => true); + public $valid_scopes = array('local' => Smarty::SCOPE_LOCAL, '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 {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 $this->required_attributes = array('var', 'value'); $this->shorttag_order = array('var', 'value'); - $this->optional_attributes = array('scope', 'bubble_up'); - $_nocache = 'null'; + $this->optional_attributes = array('scope'); + $_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) { - $_nocache = 'true'; + $_nocache = true; // create nocache var to make it know for further compiling - if (isset($compiler->template->tpl_vars[ trim($_attr[ 'var' ], "'") ])) { - $compiler->template->tpl_vars[ trim($_attr[ 'var' ], "'") ]->nocache = true; - } else { - $compiler->template->tpl_vars[ trim($_attr[ 'var' ], "'") ] = new Smarty_Variable(null, true); - } + $compiler->setNocacheInVariable($_attr[ 'var' ]); } // scope setup - $_scope = Smarty::SCOPE_LOCAL; - 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' ] == '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; - } + $_scope = $compiler->convertScope($_attr, $this->valid_scopes); + // optional parameter + $_params = ""; + if ($_nocache || $_scope) { + $_params .= ' ,' . var_export($_nocache, true); + } + if ($_scope) { + $_params .= ' ,' . $_scope; } if (isset($parameter[ 'smarty_internal_index' ])) { - $output = "_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 = - "_assignInScope({$_attr['var']}, {$_attr['value']}, {$_nocache}, {$_scope}, {$_smartyBC});\n?>"; + "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 = "_assignInScope({$_var}, {$_attr['value']}{$_params});\n?>"; } return $output; } diff --git a/libs/sysplugins/smarty_internal_compile_block.php b/libs/sysplugins/smarty_internal_compile_block.php index 8076a279..cc9fc6aa 100644 --- a/libs/sysplugins/smarty_internal_compile_block.php +++ b/libs/sysplugins/smarty_internal_compile_block.php @@ -212,7 +212,7 @@ class Smarty_Internal_Compile_Blockclose extends Smarty_Internal_Compile_Shared_ $compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode); $output = "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 .= "\$_smarty_tpl->ext->_inheritance->blockNesting--;\n"; diff --git a/libs/sysplugins/smarty_internal_compile_config_load.php b/libs/sysplugins/smarty_internal_compile_config_load.php index adacaa1b..4b6e751c 100644 --- a/libs/sysplugins/smarty_internal_compile_config_load.php +++ b/libs/sysplugins/smarty_internal_compile_config_load.php @@ -38,14 +38,24 @@ class Smarty_Internal_Compile_Config_Load extends Smarty_Internal_CompileBase * @var array * @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 * * @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 @@ -72,25 +82,8 @@ class Smarty_Internal_Compile_Config_Load extends Smarty_Internal_CompileBase } else { $section = 'null'; } - $_scope = Smarty::SCOPE_LOCAL; - 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; - } - } + // scope setup + $_scope = $compiler->convertScope($_attr, $this->valid_scopes); // create config object $_output = diff --git a/libs/sysplugins/smarty_internal_compile_function.php b/libs/sysplugins/smarty_internal_compile_function.php index 0d95e71e..1e8ccff1 100644 --- a/libs/sysplugins/smarty_internal_compile_function.php +++ b/libs/sysplugins/smarty_internal_compile_function.php @@ -148,23 +148,20 @@ class Smarty_Internal_Compile_Functionclose extends Smarty_Internal_CompileBase $output .= "ob_start();\n"; $output .= "\$_smarty_tpl->compiled->has_nocache_code = true;\n"; $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 .= "\$params = var_export(\$params, true);\n"; $output .= "echo \"/*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/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\";?>"; $compiler->parser->current_buffer->append_subtree($compiler->parser, new Smarty_Internal_ParseTree_Tag($compiler->parser, $output)); $compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode); $output = "template->compiled->nocache_hash}%%*/ \\\$value){\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 .= "\\\$_smarty_tpl->smarty->ext->_tplFunction->restoreTemplateVariables(\\\$_smarty_tpl, '{$_name}');?>\n"; $output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\";\n?>"; $output .= "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 .= "?>\n"; $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 .= "if (!function_exists('{$_funcName}')) {\n"; $output .= "function {$_funcName}(\$_smarty_tpl,\$params) {\n"; - $output .= "\$saved_tpl_vars = \$_smarty_tpl->tpl_vars;\n"; $output .= $_paramsCode; $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, new Smarty_Internal_ParseTree_Tag($compiler->parser, $output)); $compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode); - $output = " \$value){\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 = "\n"; $compiler->parser->current_buffer->append_subtree($compiler->parser, diff --git a/libs/sysplugins/smarty_internal_compile_if.php b/libs/sysplugins/smarty_internal_compile_if.php index 4286e703..f50750ae 100644 --- a/libs/sysplugins/smarty_internal_compile_if.php +++ b/libs/sysplugins/smarty_internal_compile_if.php @@ -40,38 +40,26 @@ class Smarty_Internal_Compile_If extends Smarty_Internal_CompileBase if (is_array($parameter[ 'if condition' ])) { if ($compiler->nocache) { - $_nocache = ',true'; // create nocache var to make it know for further compiling if (is_array($parameter[ 'if condition' ][ 'var' ])) { - $var = trim($parameter[ 'if condition' ][ 'var' ][ 'var' ], "'"); + $var = $parameter[ 'if condition' ][ 'var' ][ 'var' ]; } 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); - } - } else { - $_nocache = ''; + $compiler->setNocacheInVariable($var); } + $assignCompiler = new Smarty_Internal_Compile_Assign(); + $assignAttr = array(); + $assignAttr[][ 'value' ] = $parameter[ 'if condition' ][ 'value' ]; if (is_array($parameter[ 'if condition' ][ 'var' ])) { - $_output = - "tpl_vars[" . $parameter[ 'if condition' ][ 'var' ][ 'var' ] . - "]) || !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' ] . ") {?>"; + $assignAttr[][ 'var' ] = $parameter[ 'if condition' ][ 'var' ][ 'var' ]; + $_output = $assignCompiler->compile($assignAttr, $compiler, + array('smarty_internal_index' => $parameter[ 'if condition' ][ 'var' ][ 'smarty_internal_index' ])); } else { - $_output = "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' ] . ") {?>"; + $assignAttr[][ 'var' ] = $parameter[ 'if condition' ][ 'var' ]; + $_output = $assignCompiler->compile($assignAttr, $compiler, array()); } - + $_output .= ""; return $_output; } else { return ""; @@ -134,89 +122,53 @@ class Smarty_Internal_Compile_Elseif extends Smarty_Internal_CompileBase $compiler->trigger_template_error("missing elseif condition", null, true); } + $assignCode = ''; if (is_array($parameter[ 'if condition' ])) { $condition_by_assign = true; if ($compiler->nocache) { - $_nocache = ',true'; // create nocache var to make it know for further compiling if (is_array($parameter[ 'if condition' ][ 'var' ])) { - $var = trim($parameter[ 'if condition' ][ 'var' ][ 'var' ], "'"); + $var = $parameter[ 'if condition' ][ 'var' ][ 'var' ]; } else { - $var = trim($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); + $var = $parameter[ 'if condition' ][ 'var' ]; } + $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 { - $_nocache = ''; + $assignAttr[][ 'var' ] = $parameter[ 'if condition' ][ 'var' ]; + $assignCode = $assignCompiler->compile($assignAttr, $compiler, array()); } } else { $condition_by_assign = false; } - if (empty($compiler->prefix_code)) { + $prefixCode = $compiler->getPrefixCode(); + if (empty($prefixCode)) { if ($condition_by_assign) { $this->openTag($compiler, 'elseif', array($nesting + 1, $compiler->tag_nocache)); - if (is_array($parameter[ 'if condition' ][ 'var' ])) { - $_output = "tpl_vars[" . - $parameter[ 'if condition' ][ 'var' ][ 'var' ] . - "]) || !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 = - "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; + $_output = $compiler->appendCode("", $assignCode); + return $compiler->appendCode($_output, + ""); } else { $this->openTag($compiler, 'elseif', array($nesting, $compiler->tag_nocache)); - return ""; } } else { - $tmp = ''; - foreach ($compiler->prefix_code as $code) { - $tmp = $compiler->appendCode($tmp, $code); - } - $compiler->prefix_code = array(); - $tmp = $compiler->appendCode("", $tmp); + $_output = $compiler->appendCode("", $prefixCode); $this->openTag($compiler, 'elseif', array($nesting + 1, $compiler->tag_nocache)); if ($condition_by_assign) { - if (is_array($parameter[ 'if condition' ][ 'var' ])) { - $_output = $compiler->appendCode($tmp, "tpl_vars[" . - $parameter[ 'if condition' ][ 'var' ][ 'var' ] . - "]) || !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, "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; + $_output = $compiler->appendCode($_output, $assignCode); + return $compiler->appendCode($_output, + ""); } else { - return $compiler->appendCode($tmp, ""); + return $compiler->appendCode($_output, ""); } } } diff --git a/libs/sysplugins/smarty_internal_compile_include.php b/libs/sysplugins/smarty_internal_compile_include.php index 733bdee1..fd443792 100644 --- a/libs/sysplugins/smarty_internal_compile_include.php +++ b/libs/sysplugins/smarty_internal_compile_include.php @@ -58,7 +58,9 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase * * @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 @@ -106,31 +108,8 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase $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 = Smarty::SCOPE_LOCAL; - 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; - } - } + $_scope = $compiler->convertScope($_attr, $this->valid_scopes); // set flag to cache subtemplate object when called within loop or template name is variable. 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) && !$compiler->template->source->handler->recompiled; - if ($merge_compiled_includes && $_attr[ 'inline' ] !== true) { + if ($merge_compiled_includes) { // variable template name ? if ($variable_template) { $merge_compiled_includes = false; - if ($compiler->template->caching) { - // must use individual cache file - //$_attr['caching'] = 1; - } } // variable compile_id? - if (isset($_attr[ 'compile_id' ])) { - if (!((substr_count($_attr[ 'compile_id' ], '"') == 2 || - 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; - } - } + if (isset($_attr[ 'compile_id' ]) && $compiler->isVariable($_attr[ 'compile_id' ])) { + $merge_compiled_includes = false; } } @@ -217,6 +182,19 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase if ($compiler->template->caching && $call_nocache) { $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; 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' ]); // remaining attributes must be assigned as smarty variable $_vars_nc = ''; + $_vars = 'array()'; if (!empty($_attr)) { - if ($_scope == Smarty::SCOPE_LOCAL) { - $_pairs = array(); - // create variables - foreach ($_attr as $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); + $_pairs = array(); + // create variables + foreach ($_attr as $key => $value) { + $_pairs[] = "'$key'=>$value"; } - } else { - $_vars = 'array()'; + $_vars = 'array(' . join(',', $_pairs) . ')'; } $update_compile_id = $compiler->template->caching && !$compiler->tag_nocache && !$compiler->nocache && $_compile_id != '$_smarty_tpl->compile_id'; @@ -257,10 +229,11 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase if ($update_compile_id) { $_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) { - //$compiler->suppressNocacheProcessing = false; + if (!empty($_attr) && $_caching == 9999 && $compiler->template->caching) { + $_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('\n", true), 6, - 3); - //$compiler->suppressNocacheProcessing = true; } if (isset($_assign)) { $_output .= "ob_start();\n"; diff --git a/libs/sysplugins/smarty_internal_compile_while.php b/libs/sysplugins/smarty_internal_compile_while.php index 2563a406..30d83095 100644 --- a/libs/sysplugins/smarty_internal_compile_while.php +++ b/libs/sysplugins/smarty_internal_compile_while.php @@ -39,44 +39,37 @@ class Smarty_Internal_Compile_While extends Smarty_Internal_CompileBase // maybe nocache because of nocache variables $compiler->nocache = $compiler->nocache | $compiler->tag_nocache; - $_output = "nocache) { $_nocache = ',true'; // create nocache var to make it know for further compiling if (is_array($parameter[ 'if condition' ][ 'var' ])) { - $var = trim($parameter[ 'if condition' ][ 'var' ][ 'var' ], "'"); + $var = $parameter[ 'if condition' ][ 'var' ][ 'var' ]; } else { - $var = trim($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); + $var = $parameter[ 'if condition' ][ 'var' ]; } + $compiler->setNocacheInVariable($var); } else { $_nocache = ''; } + $assignCompiler = new Smarty_Internal_Compile_Assign(); + $assignAttr = array(); + $assignAttr[][ 'value' ] = $parameter[ 'if condition' ][ 'value' ]; if (is_array($parameter[ 'if condition' ][ 'var' ])) { - $_output .= "if (!isset(\$_smarty_tpl->tpl_vars[" . $parameter[ 'if condition' ][ 'var' ][ 'var' ] . - "]) || !is_array(\$_smarty_tpl->tpl_vars[" . - $parameter[ 'if condition' ][ 'var' ][ 'var' ] . - "]->value)) \$_smarty_tpl->_createLocalArrayVariable(" . - $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' ] . ") {?>"; + $assignAttr[][ 'var' ] = $parameter[ 'if condition' ][ 'var' ][ 'var' ]; + $_output = ""; + $_output .= $assignCompiler->compile($assignAttr, $compiler, + array('smarty_internal_index' => $parameter[ 'if condition' ][ 'var' ][ 'smarty_internal_index' ])); } else { - $_output .= "if (!isset(\$_smarty_tpl->tpl_vars[" . $parameter[ 'if condition' ][ 'var' ] . - "])) \$_smarty_tpl->tpl_vars[" . $parameter[ 'if condition' ][ 'var' ] . - "] = new Smarty_Variable(null{$_nocache});"; - $_output .= "while (\$_smarty_tpl->tpl_vars[" . $parameter[ 'if condition' ][ 'var' ] . "]->value = " . - $parameter[ 'if condition' ][ 'value' ] . ") {?>"; + $assignAttr[][ 'var' ] = $parameter[ 'if condition' ][ 'var' ]; + $_output = ""; + $_output .= $assignCompiler->compile($assignAttr, $compiler, array()); } + + return $_output; } else { - $_output .= "while ({$parameter['if condition']}) {?>"; + return ""; } - return $_output; } } diff --git a/libs/sysplugins/smarty_internal_data.php b/libs/sysplugins/smarty_internal_data.php index 57d2dca5..2d65ef9f 100644 --- a/libs/sysplugins/smarty_internal_data.php +++ b/libs/sysplugins/smarty_internal_data.php @@ -96,17 +96,16 @@ class Smarty_Internal_Data if (is_array($tpl_var)) { foreach ($tpl_var as $_key => $_val) { if ($_key != '') { - $this->tpl_vars[ $_key ] = new Smarty_Variable($_val, $nocache); - if ($this->_objType == 2 && $this->scope) { - $this->ext->_updateScope->updateScope($this, $_key); - } + $this->assign($_key, $_val, $nocache); } } } else { if ($tpl_var != '') { - $this->tpl_vars[ $tpl_var ] = new Smarty_Variable($value, $nocache); - if ($this->_objType == 2 && $this->scope) { - $this->ext->_updateScope->updateScope($this, $tpl_var); + if ($this->_objType == 2) { + /** @var Smarty_Internal_Template $this */ + $this->_assignInScope($tpl_var, $value, $nocache); + } else { + $this->tpl_vars[ $tpl_var ] = new Smarty_Variable($value, $nocache); } } } diff --git a/libs/sysplugins/smarty_internal_method_append.php b/libs/sysplugins/smarty_internal_method_append.php index 88db1a61..b89aacfd 100644 --- a/libs/sysplugins/smarty_internal_method_append.php +++ b/libs/sysplugins/smarty_internal_method_append.php @@ -66,7 +66,7 @@ class Smarty_Internal_Method_Append } } if ($data->_objType == 2 && $data->scope) { - $data->ext->_updateScope->updateScope($data, $tpl_var); + $data->ext->_updateScope->_updateScope($data, $tpl_var); } } return $data; diff --git a/libs/sysplugins/smarty_internal_method_appendbyref.php b/libs/sysplugins/smarty_internal_method_appendbyref.php index 35c2b677..64190d19 100644 --- a/libs/sysplugins/smarty_internal_method_appendbyref.php +++ b/libs/sysplugins/smarty_internal_method_appendbyref.php @@ -42,7 +42,7 @@ class Smarty_Internal_Method_AppendByRef $data->tpl_vars[ $tpl_var ]->value[] = &$value; } if ($data->_objType == 2 && $data->scope) { - $data->ext->_updateScope->updateScope($data, $tpl_var); + $data->ext->_updateScope->_updateScope($data, $tpl_var); } } return $data; diff --git a/libs/sysplugins/smarty_internal_method_assignbyref.php b/libs/sysplugins/smarty_internal_method_assignbyref.php index 4a83044a..5e2a2a69 100644 --- a/libs/sysplugins/smarty_internal_method_assignbyref.php +++ b/libs/sysplugins/smarty_internal_method_assignbyref.php @@ -28,7 +28,7 @@ class Smarty_Internal_Method_AssignByRef $data->tpl_vars[ $tpl_var ] = new Smarty_Variable(null, $nocache); $data->tpl_vars[ $tpl_var ]->value = &$value; if ($data->_objType == 2 && $data->scope) { - $data->ext->_updateScope->updateScope($data, $tpl_var); + $data->ext->_updateScope->_updateScope($data, $tpl_var); } } return $data; diff --git a/libs/sysplugins/smarty_internal_method_configload.php b/libs/sysplugins/smarty_internal_method_configload.php index 559d40c4..7a8e1b67 100644 --- a/libs/sysplugins/smarty_internal_method_configload.php +++ b/libs/sysplugins/smarty_internal_method_configload.php @@ -34,7 +34,7 @@ class Smarty_Internal_Method_ConfigLoad */ 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; } @@ -82,39 +82,15 @@ class Smarty_Internal_Method_ConfigLoad public function _loadConfigVars(Smarty_Internal_Template $tpl, $_config_vars) { $this->_assignConfigVars($tpl->parent, $tpl, $_config_vars); - $scope = $tpl->source->scope; - $scopes = array(); - if ($scope) { - $scopes[] = $scope; - } - 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)) { + if ($tpl->parent->_objType == 2 && ($tpl->source->scope || $tpl->parent->scope)) { + $scope = $tpl->source->scope | $tpl->scope; + if ($scope) { + // update scopes + foreach ($tpl->smarty->ext->_updateScope->_getAffectedScopes($tpl->parent, $scope) as $ptr) { $this->_assignConfigVars($ptr, $tpl, $_config_vars); - $ptr = $ptr->parent; } - if ($s == Smarty::SCOPE_PARENT) { - continue; - } - 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); - } + if ($scope & Smarty::SCOPE_LOCAL) { + //$this->_updateVarStack($tpl, $varName); } } } diff --git a/libs/sysplugins/smarty_internal_runtime_tplfunction.php b/libs/sysplugins/smarty_internal_runtime_tplfunction.php index d3fb3c51..21d6a0d8 100644 --- a/libs/sysplugins/smarty_internal_runtime_tplfunction.php +++ b/libs/sysplugins/smarty_internal_runtime_tplfunction.php @@ -33,12 +33,16 @@ class Smarty_Internal_Runtime_TplFunction } } if (function_exists($function)) { + $this->saveTemplateVariables($tpl, $name); $function ($tpl, $params); + $this->restoreTemplateVariables($tpl, $name); return; } // try to load template function dynamically if ($this->addTplFuncToCache($tpl, $name, $function)) { + $this->saveTemplateVariables($tpl, $name); $function ($tpl, $params); + $this->restoreTemplateVariables($tpl, $name); return; } } @@ -86,7 +90,7 @@ class Smarty_Internal_Runtime_TplFunction $tplPtr->smarty->ext->_updateCache->write($cache, $tplPtr, preg_replace('/\s*\?>\s*$/', "\n", $content) . "\n" . preg_replace(array('/^\s*<\?php\s+/', - '/\s*\?>\s*$/'), "\n", + '/\s*\?>\s*$/',), "\n", $match[ 0 ])); } } @@ -96,4 +100,31 @@ class Smarty_Internal_Runtime_TplFunction } 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' ]; + } + } } diff --git a/libs/sysplugins/smarty_internal_runtime_updatescope.php b/libs/sysplugins/smarty_internal_runtime_updatescope.php index 5c236c6c..093e9a3d 100644 --- a/libs/sysplugins/smarty_internal_runtime_updatescope.php +++ b/libs/sysplugins/smarty_internal_runtime_updatescope.php @@ -10,65 +10,101 @@ **/ 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) { - $scopes[] = $scope; - } - if ($tpl->scope) { - $scopes[] = $tpl->scope; - } - if (empty($scopes)) { - return; - } - /* @var Smarty_Internal_Data $ptr */ - $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; - } + if ($scope & Smarty::SCOPE_GLOBAL && $varName) { + Smarty::$global_tpl_vars[ $varName ] = $tpl->tpl_vars[ $varName ]; + } + // update scopes + foreach ($this->_getAffectedScopes($tpl, $scope) as $ptr) { + $this->_updateObject($ptr, $tpl, $varName); + } + if ($scope & Smarty::SCOPE_LOCAL) { + $this->_updateVarStack($tpl, $varName); } } } + + /** + * 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 ++; + } + } } diff --git a/libs/sysplugins/smarty_internal_template.php b/libs/sysplugins/smarty_internal_template.php index eff15d8b..e746a634 100644 --- a/libs/sysplugins/smarty_internal_template.php +++ b/libs/sysplugins/smarty_internal_template.php @@ -75,7 +75,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase public $tpl_function = array(); /** - * Scope in which template is rendered + * Scope in which variables shall be assigned * * @var int */ @@ -295,23 +295,6 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase } // set template 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 template is called multiple times set flag to to cache template objects $forceTplCache = $forceTplCache || @@ -351,10 +334,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase $tpl->render(); } } - if ($scopePtr) { - $scopePtr->tpl_vars = $tpl->tpl_vars; - $scopePtr->config_vars = $tpl->config_vars; - } + $i = 0; } /** @@ -385,45 +365,25 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase /** * Assign variable in scope * - * @param string $varName variable name - * @param mixed $value value - * @param bool $nocache nocache flag - * @param int $scope scope into which variable shall be assigned - * @param bool $smartyBC true if called in Smarty bc class + * @param string $varName variable name + * @param mixed $value value + * @param bool $nocache nocache flag + * @param int $scope scope into which variable shall be assigned * - * @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 ]->value = $value; - $this->tpl_vars[ $varName ]->nocache = $nocache; + if ($nocache) { + $this->tpl_vars[ $varName ]->nocache = $nocache; + } } else { $this->tpl_vars[ $varName ] = new Smarty_Variable($value, $nocache); } - if ($scope || $this->scope & Smarty::SCOPE_BUBBLE_UP) { - $this->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'); - } + if (isset($scope) || isset($this->scope)) { + $this->smarty->ext->_updateScope->_updateScope($this, $varName, $scope); } } diff --git a/libs/sysplugins/smarty_internal_templatecompilerbase.php b/libs/sysplugins/smarty_internal_templatecompilerbase.php index e2303bc0..8fe22a8d 100644 --- a/libs/sysplugins/smarty_internal_templatecompilerbase.php +++ b/libs/sysplugins/smarty_internal_templatecompilerbase.php @@ -384,7 +384,7 @@ abstract class Smarty_Internal_TemplateCompilerBase // add file dependency $this->parent_compiler->template->compiled->file_dependency[ $this->template->source->uid ] = 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; // get template source if (!empty($this->template->source->components)) { @@ -563,7 +563,7 @@ abstract class Smarty_Internal_TemplateCompilerBase } } // 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 compiler function plugin call it now @@ -817,7 +817,7 @@ abstract class Smarty_Internal_TemplateCompilerBase '#(:SMARTY@!@|>)\s+(?=@!@SMARTY:|<)#s' => '\1\2', // remove spaces between attributes (but not in attribute values!) '#(([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); $_offset = 0; @@ -960,7 +960,7 @@ abstract class Smarty_Internal_TemplateCompilerBase $script = null; $cacheable = true; $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) { $this->tag_nocache = $this->tag_nocache || !$cacheable; if ($script !== null) { @@ -1118,7 +1118,7 @@ abstract class Smarty_Internal_TemplateCompilerBase */ public function convertScope($_attr, $validScopes) { - $_scope = Smarty::SCOPE_LOCAL; + $_scope = 0; if (isset($_attr[ 'scope' ])) { $_scopeName = trim($_attr[ 'scope' ], "'\""); if (is_numeric($_scopeName) && in_array($_scopeName, $validScopes)) { @@ -1133,7 +1133,7 @@ abstract class Smarty_Internal_TemplateCompilerBase $err = var_export($_scopeName, 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; } } @@ -1291,4 +1291,22 @@ abstract class Smarty_Internal_TemplateCompilerBase { $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; + } + } diff --git a/libs/sysplugins/smarty_template_config.php b/libs/sysplugins/smarty_template_config.php index a74efb21..4889f350 100644 --- a/libs/sysplugins/smarty_template_config.php +++ b/libs/sysplugins/smarty_template_config.php @@ -28,9 +28,9 @@ class Smarty_Template_Config extends Smarty_Template_Source /** * 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