- 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
This commit is contained in:
uwetews
2016-03-09 01:01:32 +01:00
parent d88168d1b6
commit abf5be58ad
9 changed files with 93 additions and 71 deletions

View File

@@ -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
@@ -98,6 +80,15 @@ Smarty 3.1.30
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
=======

View File

@@ -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)

View File

@@ -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
*/

View File

@@ -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) {

View File

@@ -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 =

View File

@@ -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()';

View File

@@ -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
*

View File

@@ -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);
}
}
}

View File

@@ -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;
}