From abf5be58ad4fdd372899bef92ea8bb41cf6bce7f Mon Sep 17 00:00:00 2001 From: uwetews Date: Wed, 9 Mar 2016 01:01:32 +0100 Subject: [PATCH] - improvement rework of 'scope' attribute handling see see NEW_FEATURES.txt https://github.com/smarty-php/smarty/issues/194 https://github.com/smarty-php/smarty/issues/186 https://github.com/smarty-php/smarty/issues/179 --- NEW_FEATURES.txt | 51 ++++++------- change_log.txt | 4 + libs/Smarty.class.php | 4 +- .../smarty_internal_compile_assign.php | 10 ++- .../smarty_internal_compile_config_load.php | 8 +- .../smarty_internal_compile_include.php | 4 +- .../smarty_internal_method_configload.php | 73 ++++++++++++------- libs/sysplugins/smarty_internal_template.php | 6 +- .../smarty_internal_templatecompilerbase.php | 4 - 9 files changed, 93 insertions(+), 71 deletions(-) diff --git a/NEW_FEATURES.txt b/NEW_FEATURES.txt index f230206b..1f58862e 100644 --- a/NEW_FEATURES.txt +++ b/NEW_FEATURES.txt @@ -50,46 +50,28 @@ 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='tpl_root' - the variable will be assigned in the outermost root template called by $smarty->display() + or $smarty->fetch() and is bubbled up all {include} sub-templates to the current template. + scope='smarty' - the variable will be assigned in the Smarty object and is bubbled up all {include} sub-templates + to the current template. + scope='global' - the variable will be assigned as Smarty object global variable and is bubbled up all {include} + sub-templates to the current template. + scope='root' - the variable will be assigned if a data object was used for variable definitions in the data + object or in the Smarty object otherwise and is bubbled up all {include} sub-templates to the + current template. 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. + The scope attribute 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 @@ -97,7 +79,16 @@ Smarty 3.1.30 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--} - + + Note: The scopes should be used only to the extend really need. If a variable value assigned in an included + sub-template should be returned to the calling sub-template just use {$foo='bar' scope='parent'}. + Use scopes only with variables for which it's realy needed. Avoid general scope settings with the + {include} tag as it can have a performance impact. + + The {assign}, {append}, {config_load} and {$foo...=...} tags have a new option flag 'noscope'.Thi + Example: {$foo='bar' noscope} This will assign $foo only in the current template and any scope settings + at {include} is ignored. + Caching ======= diff --git a/change_log.txt b/change_log.txt index 3273585e..401b8f68 100644 --- a/change_log.txt +++ b/change_log.txt @@ -1,4 +1,8 @@  ===== 3.1.30-dev ===== (xx.xx.xx) + 09.03.2014 + - improvement rework of 'scope' attribute handling see see NEW_FEATURES.txt https://github.com/smarty-php/smarty/issues/194 + https://github.com/smarty-php/smarty/issues/186 https://github.com/smarty-php/smarty/issues/179 + 04.03.2016 - bugfix change from 01.03.2016 will cause $smarty->isCached(..) failure if called multiple time for same template (forum topic 25935) diff --git a/libs/Smarty.class.php b/libs/Smarty.class.php index 45b24085..462a77cf 100644 --- a/libs/Smarty.class.php +++ b/libs/Smarty.class.php @@ -121,7 +121,7 @@ class Smarty extends Smarty_Internal_TemplateBase /** * smarty version */ - const SMARTY_VERSION = '3.1.30-dev/52'; + const SMARTY_VERSION = '3.1.30-dev/53'; /** * define variable scopes @@ -138,8 +138,6 @@ class Smarty extends Smarty_Internal_TemplateBase const SCOPE_GLOBAL = 32; - const SCOPE_BUBBLE_UP = 64; - /** * define caching modes */ diff --git a/libs/sysplugins/smarty_internal_compile_assign.php b/libs/sysplugins/smarty_internal_compile_assign.php index b7d4d5ba..3bd33847 100644 --- a/libs/sysplugins/smarty_internal_compile_assign.php +++ b/libs/sysplugins/smarty_internal_compile_assign.php @@ -22,9 +22,9 @@ class Smarty_Internal_Compile_Assign extends Smarty_Internal_CompileBase * @var array * @see Smarty_Internal_CompileBase */ - public $option_flags = array('nocache', 'bubble_up'); + public $option_flags = array('nocache', 'noscope'); - /** + /** * Valid scope names * * @var array @@ -65,7 +65,11 @@ class Smarty_Internal_Compile_Assign extends Smarty_Internal_CompileBase $compiler->setNocacheInVariable($_attr[ 'var' ]); } // scope setup - $_scope = $compiler->convertScope($_attr, $this->valid_scopes); + if ($_attr[ 'noscope' ]) { + $_scope = - 1; + } else { + $_scope = $compiler->convertScope($_attr, $this->valid_scopes); + } // optional parameter $_params = ""; if ($_nocache || $_scope) { diff --git a/libs/sysplugins/smarty_internal_compile_config_load.php b/libs/sysplugins/smarty_internal_compile_config_load.php index 4b6e751c..d59ea3f8 100644 --- a/libs/sysplugins/smarty_internal_compile_config_load.php +++ b/libs/sysplugins/smarty_internal_compile_config_load.php @@ -46,7 +46,7 @@ class Smarty_Internal_Compile_Config_Load extends Smarty_Internal_CompileBase * @var array * @see Smarty_Internal_CompileBase */ - public $option_flags = array('nocache', 'bubble_up'); + public $option_flags = array('nocache', 'noscope'); /** * Valid scope names @@ -83,7 +83,11 @@ class Smarty_Internal_Compile_Config_Load extends Smarty_Internal_CompileBase $section = 'null'; } // scope setup - $_scope = $compiler->convertScope($_attr, $this->valid_scopes); + if ($_attr[ 'noscope' ]) { + $_scope = - 1; + } else { + $_scope = $compiler->convertScope($_attr, $this->valid_scopes); + } // create config object $_output = diff --git a/libs/sysplugins/smarty_internal_compile_include.php b/libs/sysplugins/smarty_internal_compile_include.php index c9f608a7..37e32f9b 100644 --- a/libs/sysplugins/smarty_internal_compile_include.php +++ b/libs/sysplugins/smarty_internal_compile_include.php @@ -43,7 +43,7 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase * @var array * @see Smarty_Internal_CompileBase */ - public $option_flags = array('nocache', 'inline', 'caching', 'bubble_up'); + public $option_flags = array('nocache', 'inline', 'caching'); /** * Attribute definition: Overwrites base class. @@ -214,7 +214,7 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase } } // delete {include} standard attributes - 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' ]); // remaining attributes must be assigned as smarty variable $_vars_nc = ''; $_vars = 'array()'; diff --git a/libs/sysplugins/smarty_internal_method_configload.php b/libs/sysplugins/smarty_internal_method_configload.php index 7a8e1b67..2a38b188 100644 --- a/libs/sysplugins/smarty_internal_method_configload.php +++ b/libs/sysplugins/smarty_internal_method_configload.php @@ -76,21 +76,31 @@ class Smarty_Internal_Method_ConfigLoad * load config variables into template object * * @param \Smarty_Internal_Template $tpl - * @param array $_config_vars + * @param array $new_config_vars * */ - public function _loadConfigVars(Smarty_Internal_Template $tpl, $_config_vars) + public function _loadConfigVars(Smarty_Internal_Template $tpl, $new_config_vars) { - $this->_assignConfigVars($tpl->parent, $tpl, $_config_vars); - 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); + $this->_assignConfigVars($tpl->parent->config_vars, $tpl, $new_config_vars); + $tagScope = $tpl->source->scope; + if ($tagScope >= 0) { + if ($tagScope == Smarty::SCOPE_LOCAL) { + $this->_updateVarStack($tpl, $new_config_vars); + $tagScope = 0; + if (!$tpl->scope) { + return; } - if ($scope & Smarty::SCOPE_LOCAL) { - //$this->_updateVarStack($tpl, $varName); + } + if ($tpl->parent->_objType == 2 && ($tagScope || $tpl->parent->scope)) { + $mergedScope = $tagScope | $tpl->scope; + if ($mergedScope) { + // update scopes + foreach ($tpl->smarty->ext->_updateScope->_getAffectedScopes($tpl->parent, $mergedScope) as $ptr) { + $this->_assignConfigVars($ptr->config_vars, $tpl, $new_config_vars); + if ($tagScope && $ptr->_objType == 2 && isset($tpl->_cache[ 'varStack' ])) { + $this->_updateVarStack($tpl, $new_config_vars); + } + } } } } @@ -99,32 +109,30 @@ class Smarty_Internal_Method_ConfigLoad /** * Assign all config variables in given scope * - * @param \Smarty_Internal_Data $scope_ptr + * @param array $config_vars config variables in scope * @param \Smarty_Internal_Template $tpl - * @param array $_config_vars + * @param array $new_config_vars loaded config variables */ - public function _assignConfigVars(Smarty_Internal_Data $scope_ptr, Smarty_Internal_Template $tpl, $_config_vars) + public function _assignConfigVars(&$config_vars, Smarty_Internal_Template $tpl, $new_config_vars) { // copy global config vars - foreach ($_config_vars[ 'vars' ] as $variable => $value) { - if ($tpl->smarty->config_overwrite || !isset($scope_ptr->config_vars[ $variable ])) { - $scope_ptr->config_vars[ $variable ] = $value; + foreach ($new_config_vars[ 'vars' ] as $variable => $value) { + if ($tpl->smarty->config_overwrite || !isset($config_vars[ $variable ])) { + $config_vars[ $variable ] = $value; } else { - $scope_ptr->config_vars[ $variable ] = - array_merge((array) $scope_ptr->config_vars[ $variable ], (array) $value); + $config_vars[ $variable ] = array_merge((array) $config_vars[ $variable ], (array) $value); } } // scan sections $sections = $tpl->source->config_sections; if (!empty($sections)) { foreach ((array) $sections as $tpl_section) { - if (isset($_config_vars[ 'sections' ][ $tpl_section ])) { - foreach ($_config_vars[ 'sections' ][ $tpl_section ][ 'vars' ] as $variable => $value) { - if ($tpl->smarty->config_overwrite || !isset($scope_ptr->config_vars[ $variable ])) { - $scope_ptr->config_vars[ $variable ] = $value; + if (isset($new_config_vars[ 'sections' ][ $tpl_section ])) { + foreach ($new_config_vars[ 'sections' ][ $tpl_section ][ 'vars' ] as $variable => $value) { + if ($tpl->smarty->config_overwrite || !isset($config_vars[ $variable ])) { + $config_vars[ $variable ] = $value; } else { - $scope_ptr->config_vars[ $variable ] = - array_merge((array) $scope_ptr->config_vars[ $variable ], (array) $value); + $config_vars[ $variable ] = array_merge((array) $config_vars[ $variable ], (array) $value); } } } @@ -132,6 +140,21 @@ class Smarty_Internal_Method_ConfigLoad } } + /** + * Update config variables in template local variable stack + * + * @param \Smarty_Internal_Template $tpl + * @param array $config_vars + */ + public function _updateVarStack(Smarty_Internal_Template $tpl, $config_vars) + { + $i = 0; + while (isset($tpl->_cache[ 'varStack' ][ $i ])) { + $this->_assignConfigVars($tpl->_cache[ 'varStack' ][ $i ][ 'config' ], $tpl, $config_vars); + $i ++; + } + } + /** * gets a config variable value * diff --git a/libs/sysplugins/smarty_internal_template.php b/libs/sysplugins/smarty_internal_template.php index 9b14beea..01c16cba 100644 --- a/libs/sysplugins/smarty_internal_template.php +++ b/libs/sysplugins/smarty_internal_template.php @@ -383,8 +383,10 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase } else { $this->tpl_vars[ $varName ] = new Smarty_Variable($value, $nocache || $this->isRenderingCache); } - if (isset($scope) || isset($this->scope)) { - $this->smarty->ext->_updateScope->_updateScope($this, $varName, $scope); + if ($scope >= 0) { + 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 38bfc799..2d8cb299 100644 --- a/libs/sysplugins/smarty_internal_templatecompilerbase.php +++ b/libs/sysplugins/smarty_internal_templatecompilerbase.php @@ -403,7 +403,6 @@ abstract class Smarty_Internal_TemplateCompilerBase $this->smarty->_debug->end_compile($this->template); } $this->_tag_stack = array(); - self::$_tag_objects = array(); // free memory $this->parent_compiler = null; $this->template = null; @@ -1140,9 +1139,6 @@ 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' ] && $_scope > 2) { - $_scope += Smarty::SCOPE_BUBBLE_UP; - } } return $_scope; }