WIP rewriting variable scopes

This commit is contained in:
Simon Wisselink
2023-01-10 17:35:34 +01:00
parent 5052ce0d88
commit 3d10630510
22 changed files with 456 additions and 698 deletions

View File

@@ -7,7 +7,7 @@ Smarty is a template engine for PHP, facilitating the separation of presentation
Read the [documentation](https://smarty-php.github.io/smarty/) to find out how to use it.
## Requirements
Smarty can be run with PHP 7.1 to PHP 8.2.
Smarty v5 can be run with PHP 7.2 to PHP 8.2.
## Installation
Smarty versions 3.1.11 or later can be installed with [Composer](https://getcomposer.org/).

View File

@@ -30,7 +30,7 @@
"forum": "https://github.com/smarty-php/smarty/discussions"
},
"require": {
"php": "^7.1 || ^8.0",
"php": "^7.2 || ^8.0",
"symfony/polyfill-mbstring": "^1.27"
},
"autoload": {

View File

@@ -50,7 +50,7 @@ class ForTag extends Base {
$var = $_statement['var'];
$index = '';
}
$output .= "\$_smarty_tpl->tpl_vars[$var] = new \\Smarty\\Variable(null, \$_smarty_tpl->isRenderingCache);\n";
$output .= "\$_smarty_tpl->assign($var, null);\n";
$output .= "\$_smarty_tpl->tpl_vars[$var]->value{$index} = {$_statement['value']};\n";
}
if (is_array($_attr['var'])) {
@@ -70,7 +70,7 @@ class ForTag extends Base {
$var = $_statement['var'];
$index = '';
}
$output .= "\$_smarty_tpl->tpl_vars[$var] = new \\Smarty\\Variable(null, \$_smarty_tpl->isRenderingCache);";
$output .= "\$_smarty_tpl->assign($var, null);";
if (isset($_attr['step'])) {
$output .= "\$_smarty_tpl->tpl_vars[$var]->step = $_attr[step];";
} else {

View File

@@ -201,6 +201,6 @@ abstract class ForeachSection extends Base {
$compiler->trigger_template_error("missing or illegal \$smarty.{$tag} property attribute", null, true);
}
$tagVar = "'__smarty_{$tag}_{$name}'";
return "(isset(\$_smarty_tpl->tpl_vars[{$tagVar}]->value['{$property}']) ? \$_smarty_tpl->tpl_vars[{$tagVar}]->value['{$property}'] : null)";
return "(\$_smarty_tpl->getValue({$tagVar})['{$property}'] ?? null)";
}
}

View File

@@ -216,7 +216,7 @@ class ForeachTag extends ForeachSection {
$output .= "if (\$_from !== null) foreach (\$_from as {$keyTerm}{$itemVar}->value) {\n";
$output .= "{$itemVar}->do_else = false;\n";
if (isset($attributes['key']) && isset($itemAttr['key'])) {
$output .= "\$_smarty_tpl->tpl_vars['{$key}']->value = {$itemVar}->key;\n";
$output .= "\$_smarty_tpl->assign('{$key}', {$itemVar}->key);\n";
}
if (isset($itemAttr['iteration'])) {
$output .= "{$itemVar}->iteration++;\n";
@@ -257,11 +257,9 @@ class ForeachTag extends ForeachSection {
* @param string $input
*
* @return bool|string
*
* @TODO: this may no longer work if we add a getter for tpl_vars, recheck this!
*/
private function getVariableName($input) {
if (preg_match('~^[$]_smarty_tpl->tpl_vars\[[\'"]*([0-9]*[a-zA-Z_]\w*)[\'"]*\]->value$~', $input, $match)) {
if (preg_match('~^[$]_smarty_tpl->getValue\([\'"]*([0-9]*[a-zA-Z_]\w*)[\'"]*\]\)$~', $input, $match)) {
return $match[1];
}
return false;

View File

@@ -67,10 +67,10 @@ class FunctionClose extends Base {
$output .= "ob_start();\n";
$output .= "\$_smarty_tpl->compiled->has_nocache_code = true;\n";
$output .= $_paramsCode;
$output .= "foreach (\$params as \$key => \$value) {\n\$_smarty_tpl->tpl_vars[\$key] = new \\Smarty\\Variable(\$value, \$_smarty_tpl->isRenderingCache);\n}\n";
$output .= "foreach (\$params as \$key => \$value) {\n\$_smarty_tpl->assign(\$key, \$value);\n}\n";
$output .= "\$params = var_export(\$params, true);\n";
$output .= "echo \"/*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/<?php ";
$output .= "\\\$_smarty_tpl->smarty->getRuntime('TplFunction')->saveTemplateVariables(\\\$_smarty_tpl, '{$_name}');\nforeach (\$params as \\\$key => \\\$value) {\n\\\$_smarty_tpl->tpl_vars[\\\$key] = new \\Smarty\\Variable(\\\$value, \\\$_smarty_tpl->isRenderingCache);\n}\n?>";
$output .= "\\\$_smarty_tpl->smarty->getRuntime('TplFunction')->saveTemplateVariables(\\\$_smarty_tpl, '{$_name}');\nforeach (\$params as \\\$key => \\\$value) {\n\\\$_smarty_tpl->assign(\\\$key, \\\$value);\n}\n?>";
$output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\";?>";
$compiler->parser->current_buffer->append_subtree(
$compiler->parser,
@@ -109,7 +109,7 @@ class FunctionClose extends Base {
$output .= "if (!function_exists('{$_funcName}')) {\n";
$output .= "function {$_funcName}(\\Smarty\\Template \$_smarty_tpl,\$params) {\n";
$output .= $_paramsCode;
$output .= "foreach (\$params as \$key => \$value) {\n\$_smarty_tpl->tpl_vars[\$key] = new \\Smarty\\Variable(\$value, \$_smarty_tpl->isRenderingCache);\n}\n";
$output .= "foreach (\$params as \$key => \$value) {\n\$_smarty_tpl->assign(\$key, \$value);\n}\n";
$output .= "?>\n";
$compiler->parser->current_buffer->append_subtree(
$compiler->parser,

View File

@@ -89,10 +89,7 @@ class Configfile extends BaseCompiler {
$this->template->source->type,
];
if ($this->smarty->debugging) {
if (!isset($this->smarty->_debug)) {
$this->smarty->_debug = new \Smarty\Debug();
}
$this->smarty->_debug->start_compile($this->template);
$this->smarty->getDebug()->start_compile($this->template);
}
// init the lexer/parser to compile the config file
/* @var ConfigfileLexer $this->lex */
@@ -134,7 +131,7 @@ class Configfile extends BaseCompiler {
mb_internal_encoding($mbEncoding);
}
if ($this->smarty->debugging) {
$this->smarty->_debug->end_compile($this->template);
$this->smarty->getDebug()->end_compile($this->template);
}
// template header code
$template_header = sprintf(

View File

@@ -390,10 +390,7 @@ class Template extends BaseCompiler {
// save template object in compiler class
$this->template = $template;
if ($this->smarty->debugging) {
if (!isset($this->smarty->_debug)) {
$this->smarty->_debug = new \Smarty\Debug();
}
$this->smarty->_debug->start_compile($this->template);
$this->smarty->getDebug()->start_compile($this->template);
}
$this->parent_compiler = $parent_compiler ? $parent_compiler : $this;
$nocache = isset($nocache) ? $nocache : false;
@@ -439,7 +436,7 @@ class Template extends BaseCompiler {
);
} catch (\Exception $e) {
if ($this->smarty->debugging) {
$this->smarty->_debug->end_compile($this->template);
$this->smarty->getDebug()->end_compile($this->template);
}
$this->_tag_stack = [];
// free memory
@@ -449,7 +446,7 @@ class Template extends BaseCompiler {
throw $e;
}
if ($this->smarty->debugging) {
$this->smarty->_debug->end_compile($this->template);
$this->smarty->getDebug()->end_compile($this->template);
}
$this->parent_compiler = null;
$this->parser = null;
@@ -507,9 +504,8 @@ class Template extends BaseCompiler {
// not a variable variable
$var = trim($variable, '\'');
$this->tag_nocache = $this->tag_nocache |
$this->template->_getVariable(
$this->template->getVariable(
$var,
null,
true,
false
)->isNocache();
@@ -766,11 +762,10 @@ class Template extends BaseCompiler {
public function setNocacheInVariable($varName) {
// create nocache var to make it know for further compiling
if ($_var = $this->getId($varName)) {
if (isset($this->template->tpl_vars[$_var])) {
$this->template->tpl_vars[$_var] = clone $this->template->tpl_vars[$_var];
$this->template->tpl_vars[$_var]->nocache = true;
if ($this->template->hasVariable($_var)) {
$this->template->getVariable($_var)->setNocache(true);
} else {
$this->template->tpl_vars[$_var] = new \Smarty\Variable(null, true);
$this->template->assign($_var, null, true);
}
}
}

View File

@@ -17,6 +17,16 @@ namespace Smarty;
abstract class Data
{
/**
* define variable scopes
*/
const SCOPE_LOCAL = 1;
const SCOPE_PARENT = 2;
const SCOPE_TPL_ROOT = 4;
const SCOPE_ROOT = 8;
const SCOPE_SMARTY = 16;
const SCOPE_GLOBAL = 32;
/**
* Global smarty instance
*
@@ -24,13 +34,6 @@ abstract class Data
*/
public $smarty = null;
/**
* This object type (Smarty = 1, template = 2, data = 4)
*
* @var int
*/
public $_objType = 4;
/**
* template variables
*
@@ -39,9 +42,9 @@ abstract class Data
public $tpl_vars = array();
/**
* parent template (if any)
* parent data container (if any)
*
* @var Smarty|Template|DataObject
* @var Data
*/
public $parent = null;
@@ -52,13 +55,6 @@ abstract class Data
*/
public $config_vars = array();
/**
* \Smarty\Data constructor.
*/
public function __construct()
{
}
/**
* assigns a Smarty variable
*
@@ -76,18 +72,7 @@ abstract class Data
$this->assign($_key, $_val, $nocache);
}
} else {
if ($tpl_var !== '') {
if ($this->_objType === 2) {
/**
*
*
* @var Template $this
*/
$this->_assignInScope($tpl_var, $value, $nocache);
} else {
$this->tpl_vars[ $tpl_var ] = new Variable($value, $nocache);
}
}
$this->tpl_vars[ $tpl_var ] = new Variable($value, $nocache);
}
return $this;
}
@@ -109,36 +94,25 @@ abstract class Data
public function append($tpl_var, $value = null, $merge = false, $nocache = false)
{
if (is_array($tpl_var)) {
// $tpl_var is an array, ignore $value
foreach ($tpl_var as $_key => $_val) {
if ($_key !== '') {
$this->append($_key, $_val, $merge, $nocache);
}
$this->append($_key, $_val, $merge, $nocache);
}
} else {
if ($tpl_var !== '' && isset($value)) {
if (!isset($this->tpl_vars[ $tpl_var ])) {
$tpl_var_inst = $this->_getVariable($tpl_var, null, true, false);
if ($tpl_var_inst instanceof UndefinedVariable) {
$this->tpl_vars[ $tpl_var ] = new \Smarty\Variable(null, $nocache);
} else {
$this->tpl_vars[ $tpl_var ] = clone $tpl_var_inst;
}
}
if (!(is_array($this->tpl_vars[ $tpl_var ]->value)
|| $this->tpl_vars[ $tpl_var ]->value instanceof ArrayAccess)
) {
settype($this->tpl_vars[ $tpl_var ]->value, 'array');
}
if ($merge && is_array($value)) {
foreach ($value as $_mkey => $_mval) {
$this->tpl_vars[ $tpl_var ]->value[ $_mkey ] = $_mval;
}
} else {
$this->tpl_vars[ $tpl_var ]->value[] = $value;
}
$newValue = $this->getValue($tpl_var) ?? [];
if (!is_array($newValue)) {
$newValue = (array) $newValue;
}
$this->_updateScope($tpl_var);
if ($merge && is_array($value)) {
foreach ($value as $_mkey => $_mval) {
$newValue[$_mkey] = $_mval;
}
} else {
$newValue[] = $value;
}
$this->assign($tpl_var, $newValue, $nocache);
}
return $this;
}
@@ -154,65 +128,9 @@ abstract class Data
*/
public function assignGlobal($varName, $value = null, $nocache = false)
{
if ($varName !== '') {
$this->_getSmartyObj()->setGlobalVariable($varName, new \Smarty\Variable($value, $nocache));
}
return $this;
return $this->_getSmartyObj()->assign($varName, $value, $nocache);
}
/**
* appends values to template variables by reference
*
* @param string $tpl_var the template variable name
* @param mixed &$value the referenced value to append
* @param boolean $merge flag if array elements shall be merged
*
* @return Data
*/
public function appendByRef($tpl_var, &$value, $merge = false)
{
if ($tpl_var !== '' && isset($value)) {
if (!isset($this->tpl_vars[ $tpl_var ])) {
$this->tpl_vars[ $tpl_var ] = new \Smarty\Variable();
}
if (!is_array($this->tpl_vars[ $tpl_var ]->value)) {
settype($this->tpl_vars[ $tpl_var ]->value, 'array');
}
if ($merge && is_array($value)) {
foreach ($value as $_key => $_val) {
$this->tpl_vars[ $tpl_var ]->value[ $_key ] = &$value[ $_key ];
}
} else {
$this->tpl_vars[ $tpl_var ]->value[] = &$value;
}
$this->_updateScope($tpl_var);
}
return $this;
}
/**
* assigns values to template variables by reference
*
* @param string $tpl_var the template variable name
* @param $value
* @param boolean $nocache if true any output of this variable will be not cached
*
* @return Data
*/
public function assignByRef($tpl_var, &$value, $nocache = false)
{
if ($tpl_var !== '') {
$this->tpl_vars[ $tpl_var ] = new \Smarty\Variable(null, $nocache);
$this->tpl_vars[ $tpl_var ]->value = &$value;
$this->_updateScope($tpl_var);
}
return $this;
}
protected function _updateScope($varName, $tagScope = 0) {
// implemented in \Smarty\Template only
}
/**
* Returns a single or all template variables
*
@@ -220,14 +138,15 @@ abstract class Data
* @param bool $searchParents include parent templates?
*
* @return mixed variable value or or array of variables
*@api Smarty::getTemplateVars()
* @api Smarty::getTemplateVars()
* @link https://www.smarty.net/docs/en/api.get.template.vars.tpl
*
*/
public function getTemplateVars($varName = null, Data $_ptr = null, $searchParents = true)
public function getTemplateVars($varName = null, $searchParents = true)
{
if (isset($varName)) {
$_var = $this->_getVariable($varName, $_ptr, $searchParents, false);
return $this->getValue($varName, $searchParents);
$_var = $_ptr->getVariable($varName, $searchParents, false);
if (is_object($_var)) {
return $_var->value;
} else {
@@ -263,98 +182,70 @@ abstract class Data
}
/**
* gets the object of a Smarty variable
* Wrapper for ::getVariable()
*
* @deprecated since 5.0
*
* @param $varName
* @param $searchParents
* @param $errorEnable
*
* @return void
*/
public function _getVariable($varName, $searchParents = true, $errorEnable = true) {
trigger_error('Using ::_getVariable() to is deprecated and will be ' .
'removed in a future release. Use getVariable() instead.', E_USER_DEPRECATED);
return $this->getVariable($varName, $searchParents, $errorEnable);
}
/**
* Gets the object of a Smarty variable
*
* @param string $varName the name of the Smarty variable
* @param Data|null $_ptr optional pointer to data object
* @param bool $searchParents search also in parent data
* @param bool $errorEnable
*
* @return Variable
*/
public function _getVariable(
$varName,
Data $_ptr = null,
$searchParents = true,
$errorEnable = true
) {
if ($_ptr === null) {
$_ptr = $this;
public function getVariable($varName, $searchParents = true, $errorEnable = true) {
if (isset($this->tpl_vars[$varName])) {
return $this->tpl_vars[$varName];
}
while ($_ptr !== null) {
if (isset($_ptr->tpl_vars[ $varName ])) {
// found it, return it
return $_ptr->tpl_vars[ $varName ];
}
// not found, try at parent
if ($searchParents && isset($_ptr->parent)) {
$_ptr = $_ptr->parent;
} else {
$_ptr = null;
}
}
if ($this->_getSmartyObj()->getGlobalVariable($varName)) {
// found it, return it
return $this->_getSmartyObj()->getGlobalVariable($varName);
if ($this->parent) {
return $this->parent->getVariable($varName, $searchParents, $errorEnable);
}
if ($errorEnable && $this->_getSmartyObj()->error_unassigned) {
// force a notice
$x = $$varName;
}
return new UndefinedVariable;
return new UndefinedVariable();
}
/**
* Indicates if given variable has been set.
* @param $varName
*
* @return bool
*/
public function hasVariable($varName): bool {
return !($this->getVariable($varName) instanceof UndefinedVariable);
}
/**
* Returns the value of the Smarty\Variable given by $varName, or null if the variable does not exist.
*
* @param $varName
* @param bool $searchParents
*
* @return mixed|null
*/
public function getValue($varName) {
$variable = $this->_getVariable($varName);
public function getValue($varName, $searchParents = true) {
$variable = $this->getVariable($varName, $searchParents);
return isset($variable) ? $variable->getValue() : null;
}
/**
* Follow the parent chain an merge template and config variables
*
* @param Data|null $data
*/
public function _mergeVars(Data $data = null)
{
if (isset($data)) {
if (!empty($this->tpl_vars)) {
$data->tpl_vars = array_merge($this->tpl_vars, $data->tpl_vars);
}
if (!empty($this->config_vars)) {
$data->config_vars = array_merge($this->config_vars, $data->config_vars);
}
} else {
$data = $this;
}
if (isset($this->parent)) {
$this->parent->_mergeVars($data);
}
}
/**
* Return true if this instance is a Data obj
*
* @return bool
*/
public function _isDataObj()
{
return $this->_objType === 4;
}
/**
* Return true if this instance is a template obj
*
* @return bool
*/
public function _isTplObj()
{
return $this->_objType === 2;
}
/**
* Get Smarty object
*
@@ -421,80 +312,32 @@ abstract class Data
return $this;
}
/**
* load a config file, optionally load just selected sections
*
* @param string $config_file filename
* @param mixed $sections array of section names, single
* section or null
*
* @return Data
* @throws \Exception
*@api Smarty::configLoad()
* @link https://www.smarty.net/docs/en/api.config.load.tpl
*
*/
public function configLoad($config_file, $sections = null)
{
$this->_loadConfigfile($config_file, $sections, null);
return $this;
}
/**
* load a config file, optionally load just selected sections
* Gets a config variable value
*
* @param string $config_file filename
* @param mixed $sections array of section names, single
* section or null
* @param int $scope scope into which config variables
* shall be loaded
* @param null $varName the name of the config variable
*
* @throws \Exception
*@link https://www.smarty.net/docs/en/api.config.load.tpl
*
* @api Smarty::configLoad()
* @return mixed the value of the config variable
* @throws Exception
*/
public function _loadConfigfile($config_file, $sections = null, $scope = 0)
public function getConfigVariable($varName = null)
{
/* @var \Smarty $smarty */
$smarty = $this->_getSmartyObj();
/* @var \Smarty\Template $confObj */
$confObj = new Template($config_file, $smarty, $this, null, null, null, null, true);
$confObj->caching = Smarty::CACHING_OFF;
$confObj->source->config_sections = $sections;
$confObj->source->scope = $scope;
$confObj->compiled = \Smarty\Template\Compiled::load($confObj);
$confObj->compiled->render($confObj);
if ($this->_isTplObj()) {
$this->compiled->file_dependency[ $confObj->source->uid ] =
array($confObj->source->filepath, $confObj->source->getTimeStamp(), $confObj->source->type);
}
}
/**
* gets a config variable value
*
* @param string $varName the name of the config variable
* @param bool $errorEnable
*
* @return null|string the value of the config variable
*/
public function getConfigVariable($varName = null, $errorEnable = true)
{
$_ptr = $this;
while ($_ptr !== null) {
if (isset($_ptr->config_vars[ $varName ])) {
// found it, return it
return $_ptr->config_vars[ $varName ];
}
// not found, try at parent
$_ptr = $_ptr->parent;
if (isset($this->config_vars[$varName])) {
return $this->config_vars[$varName];
}
if ($this->smarty->error_unassigned && $errorEnable) {
// force a notice
$x = $$varName;
$returnValue = $this->parent ? $this->parent->getConfigVariable($varName) : null;
if ($returnValue === null && $this->_getSmartyObj()->error_unassigned) {
throw new Exception("Undefined variable $varName");
}
return null;
return $returnValue;
}
/**
@@ -504,34 +347,16 @@ abstract class Data
* @link https://www.smarty.net/docs/en/api.get.config.vars.tpl
*
* @param string $varname variable name or null
* @param bool $search_parents include parent templates?
*
* @return mixed variable value or or array of variables
*/
public function getConfigVars($varname = null, $search_parents = true)
public function getConfigVars($varname = null)
{
$_ptr = $this;
$var_array = array();
while ($_ptr !== null) {
if (isset($varname)) {
if (isset($_ptr->config_vars[ $varname ])) {
return $_ptr->config_vars[ $varname ];
}
} else {
$var_array = array_merge($_ptr->config_vars, $var_array);
}
// not found, try at parent
if ($search_parents) {
$_ptr = $_ptr->parent;
} else {
$_ptr = null;
}
}
if (isset($varname)) {
return '';
} else {
return $var_array;
return $this->getConfigVariable($varname);
}
return array_merge($this->parent ? $this->parent->getConfigVars() : [], $this->config_vars);
}
/**
@@ -560,33 +385,6 @@ abstract class Data
}
}
/**
* gets a stream variable
*
* @param string $variable the stream of the variable
*
* @return mixed
* @throws \Smarty\Exception
*@api Smarty::getStreamVariable()
*
*/
public function getStreamVariable($variable)
{
$_result = '';
$fp = fopen($variable, 'r+');
if ($fp) {
while (!feof($fp) && ($current_line = fgets($fp)) !== false) {
$_result .= $current_line;
}
fclose($fp);
return $_result;
}
$smarty = $this->smarty ?? $this;
if ($smarty->error_unassigned) {
throw new Exception('Undefined stream variable "' . $variable . '"');
} else {
return null;
}
}
}

View File

@@ -10,8 +10,6 @@
namespace Smarty;
use Smarty\Exception;
/**
* class for the Smarty data object
* The Smarty data object will hold Smarty variables in the current scope
@@ -21,20 +19,6 @@ use Smarty\Exception;
*/
class DataObject extends Data {
/**
* Counter
*
* @var int
*/
public static $count = 0;
/**
* Data block name
*
* @var string
*/
public $dataObjectName = '';
/**
* Smarty object
*
@@ -53,8 +37,7 @@ class DataObject extends Data {
*/
public function __construct($_parent = null, $smarty = null, $name = null) {
parent::__construct();
self::$count++;
$this->dataObjectName = 'Data_object ' . (isset($name) ? "'{$name}'" : self::$count);
$this->smarty = $smarty;
if (is_object($_parent)) {
// when object set up back pointer
@@ -62,7 +45,7 @@ class DataObject extends Data {
} elseif (is_array($_parent)) {
// set up variable values
foreach ($_parent as $_key => $_val) {
$this->tpl_vars[$_key] = new Variable($_val);
$this->assign($_key, $_val);
}
} elseif ($_parent !== null) {
throw new Exception('Wrong type for template variables');

View File

@@ -224,7 +224,7 @@ class Debug extends Data
ksort($_config_vars);
$debugging = $smarty->debugging;
$_template = new \Smarty\Template($debObj->debug_tpl, $debObj);
if ($obj->_isTplObj()) {
if ($obj instanceof \Smarty\Template) {
$_template->assign('template_name', $obj->source->type . ':' . $obj->source->name);
}
if ($obj->_objType === 1 || $full) {
@@ -253,18 +253,12 @@ class Debug extends Data
*
* @return \StdClass
*/
public function get_debug_vars($obj)
private function get_debug_vars($obj)
{
$config_vars = array();
foreach ($obj->config_vars as $key => $var) {
$config_vars[ $key ][ 'value' ] = $var;
if ($obj->_isTplObj()) {
$config_vars[ $key ][ 'scope' ] = $obj->source->type . ':' . $obj->source->name;
} elseif ($obj->_isDataObj()) {
$tpl_vars[ $key ][ 'scope' ] = $obj->dataObjectName;
} else {
$config_vars[ $key ][ 'scope' ] = 'Smarty object';
}
$config_vars[$key]['value'] = $var;
$config_vars[$key]['scope'] = get_class($obj) . ':' . spl_object_id($obj);
}
$tpl_vars = array();
foreach ($obj->tpl_vars as $key => $var) {
@@ -283,13 +277,7 @@ class Debug extends Data
}
}
}
if ($obj->_isTplObj()) {
$tpl_vars[ $key ][ 'scope' ] = $obj->source->type . ':' . $obj->source->name;
} elseif ($obj->_isDataObj()) {
$tpl_vars[ $key ][ 'scope' ] = $obj->dataObjectName;
} else {
$tpl_vars[ $key ][ 'scope' ] = 'Smarty object';
}
$tpl_vars[$key]['scope'] = get_class($obj) . ':' . spl_object_id($obj);
}
if (isset($obj->parent)) {
$parent = $this->get_debug_vars($obj->parent);

View File

@@ -130,25 +130,23 @@ abstract class BasePlugin
/**
* modify template_resource according to resource handlers specifications
*
* @param \Smarty\Template|\Smarty $obj Smarty instance
* @param \Smarty\Template|null $template Smarty instance
* @param string $template_resource template_resource to extract resource handler and
* name of
*
* @return string unique resource name
* @throws \Smarty\Exception
*/
public static function getUniqueTemplateName($obj, $template_resource)
public static function getUniqueTemplateName($smarty, $template, $template_resource)
{
$smarty = $obj->_getSmartyObj();
[$name, $type] = self::parseResourceName($template_resource, $smarty->default_resource_type);
// TODO: optimize for Smarty's internal resource types
$resource = BasePlugin::load($smarty, $type);
// go relative to a given template?
$_file_is_dotted = $name[ 0 ] === '.' && ($name[ 1 ] === '.' || $name[ 1 ] === '/');
if ($obj->_isTplObj() && $_file_is_dotted
&& ($obj->source->type === 'file' || $obj->parent->source->type === 'extends')
if ($template && $_file_is_dotted && ($template->source->type === 'file' || $template->parent->source->type === 'extends')
) {
$name = $smarty->_realpath(dirname($obj->parent->source->filepath) . DIRECTORY_SEPARATOR . $name);
$name = $smarty->_realpath(dirname($template->parent->source->filepath) . DIRECTORY_SEPARATOR . $name);
}
return $resource->buildUniqueResourceName($smarty, $name);
}

View File

@@ -59,35 +59,35 @@ class ForeachRuntime {
if (!isset($total)) {
$total = empty($from) ? 0 : ($needTotal ? count($from) : 1);
}
if (isset($tpl->tpl_vars[$item])) {
if ($tpl->hasVariable($item)) {
$saveVars['item'] = [
$item,
$tpl->tpl_vars[$item],
$tpl->getVariable($item),
];
}
$tpl->tpl_vars[$item] = new \Smarty\Variable(null, $tpl->isRenderingCache);
$tpl->assign($item,null);
if ($total === 0) {
$from = null;
} else {
if ($key) {
if (isset($tpl->tpl_vars[$key])) {
if ($tpl->hasVariable($key)) {
$saveVars['key'] = [
$key,
$tpl->tpl_vars[$key],
$tpl->getVariable($key),
];
}
$tpl->tpl_vars[$key] = new \Smarty\Variable(null, $tpl->isRenderingCache);
$tpl->assign($key, null);
}
}
if ($needTotal) {
$tpl->tpl_vars[$item]->total = $total;
$tpl->getVariable($item)->total = $total;
}
if ($name) {
$namedVar = "__smarty_foreach_{$name}";
if (isset($tpl->tpl_vars[$namedVar])) {
if ($tpl->hasVariable($namedVar)) {
$saveVars['named'] = [
$namedVar,
$tpl->tpl_vars[$namedVar],
$tpl->getVariable($namedVar),
];
}
$namedProp = [];
@@ -103,7 +103,7 @@ class ForeachRuntime {
if (isset($properties['show'])) {
$namedProp['show'] = ($total > 0);
}
$tpl->tpl_vars[$namedVar] = new \Smarty\Variable($namedProp);
$tpl->assign($namedVar, $namedProp);
}
$this->stack[] = $saveVars;
return $from;
@@ -148,7 +148,7 @@ class ForeachRuntime {
if (!empty($saveVars)) {
if (isset($saveVars['item'])) {
$item = &$saveVars['item'];
$tpl->tpl_vars[$item[0]]->value = $item[1]->value;
$tpl->assign($item[0], $item[1]->getValue());
}
if (isset($saveVars['key'])) {
$tpl->tpl_vars[$saveVars['key'][0]] = $saveVars['key'][1];

View File

@@ -22,9 +22,9 @@ class MakeNocacheRuntime {
* @throws \Smarty\Exception
*/
public function save(Template $tpl, $var) {
if (isset($tpl->tpl_vars[$var])) {
if ($tpl->hasVariable($var)) {
$export =
preg_replace('/^\\\\Smarty\\\\Variable::__set_state[(]|[)]$/', '', var_export($tpl->tpl_vars[$var], true));
preg_replace('/^\\\\Smarty\\\\Variable::__set_state[(]|[)]$/', '', var_export($tpl->getVariable($var), true));
if (preg_match('/(\w+)::__set_state/', $export, $match)) {
throw new \Smarty\Exception("{make_nocache \${$var}} in template '{$tpl->source->name}': variable does contain object '{$match[1]}' not implementing method '__set_state'");
}
@@ -43,7 +43,7 @@ class MakeNocacheRuntime {
*/
public function store(Template $tpl, $var, $properties) {
// do not overwrite existing nocache variables
if (!isset($tpl->tpl_vars[$var]) || !$tpl->tpl_vars[$var]->nocache) {
if (!$tpl->getVariable($var)->isNocache()) {
$newVar = new \Smarty\Variable();
unset($properties['nocache']);
foreach ($properties as $k => $v) {

View File

@@ -53,15 +53,7 @@ class Smarty extends \Smarty\TemplateBase
* smarty version
*/
const SMARTY_VERSION = '5.0.0';
/**
* define variable scopes
*/
const SCOPE_LOCAL = 1;
const SCOPE_PARENT = 2;
const SCOPE_TPL_ROOT = 4;
const SCOPE_ROOT = 8;
const SCOPE_SMARTY = 16;
const SCOPE_GLOBAL = 32;
/**
* define caching modes
*/
@@ -93,11 +85,6 @@ class Smarty extends \Smarty\TemplateBase
const PLUGIN_MODIFIER = 'modifier';
const PLUGIN_MODIFIERCOMPILER = 'modifiercompiler';
/**
* assigned global tpl vars
*/
private $global_tpl_vars = [];
/**
* The character set to adhere to (defaults to "UTF-8")
*/
@@ -1022,17 +1009,13 @@ class Smarty extends \Smarty\TemplateBase
if (!empty($data) && is_array($data)) {
// set up variable values
foreach ($data as $_key => $_val) {
$tpl->tpl_vars[ $_key ] = new \Smarty\Variable($_val);
$tpl->assign($_key, $_val);
}
}
if ($this->debugging || $this->debugging_ctrl === 'URL') {
$tpl->smarty->_debug = new \Smarty\Debug();
// check URL debugging control
if (!$this->debugging && $this->debugging_ctrl === 'URL') {
$tpl->smarty->_debug->debugUrl($tpl->smarty);
}
}
return $tpl;
if (!$this->debugging && $this->debugging_ctrl === 'URL') {
$tpl->smarty->getDebug()->debugUrl($tpl->smarty);
}
return $tpl;
}
/**
@@ -1061,7 +1044,7 @@ class Smarty extends \Smarty\TemplateBase
$caching = (int)($caching === null ? $this->caching : $caching);
if ((isset($template) && strpos($template_name, ':.') !== false) || $this->allow_ambiguous_resources) {
$_templateId =
\Smarty\Resource\BasePlugin::getUniqueTemplateName((isset($template) ? $template : $this), $template_name) .
\Smarty\Resource\BasePlugin::getUniqueTemplateName($this, $template ?? null, $template_name) .
"#{$cache_id}#{$compile_id}#{$caching}";
} else {
$_templateId = $this->_joined_template_dir . "#{$template_name}#{$cache_id}#{$compile_id}#{$caching}";
@@ -2251,5 +2234,73 @@ class Smarty extends \Smarty\TemplateBase
return $this->global_tpl_vars[$varName] ?? null;
}
/**
* fetches a rendered Smarty template
*
* @param string $template the resource handle of the template file or template object
* @param mixed $cache_id cache id to be used with this template
* @param mixed $compile_id compile id to be used with this template
* @param object $parent next higher level of Smarty variables
*
* @return string rendered template output
* @throws Exception
* @throws Exception
*/
public function fetch($template = null, $cache_id = null, $compile_id = null, $parent = null) {
return $this->returnOrCreateTemplate($template)->fetch($cache_id, $compile_id, $parent);
}
/**
* displays a Smarty template
*
* @param string $template the resource handle of the template file or template object
* @param mixed $cache_id cache id to be used with this template
* @param mixed $compile_id compile id to be used with this template
* @param object $parent next higher level of Smarty variables
*
* @throws \Exception
* @throws \Smarty\Exception
*/
public function display($template = null, $cache_id = null, $compile_id = null, $parent = null) {
return $this->returnOrCreateTemplate($template)->display($cache_id, $compile_id, $parent);
}
/**
* test if cache is valid
*
* @param null|string|\Smarty\Template $template the resource handle of the template file or template
* object
* @param mixed $cache_id cache id to be used with this template
* @param mixed $compile_id compile id to be used with this template
* @param object $parent next higher level of Smarty variables
*
* @return bool cache status
* @throws \Exception
* @throws \Smarty\Exception
* @link https://www.smarty.net/docs/en/api.is.cached.tpl
*
* @api Smarty::isCached()
*/
public function isCached($template = null, $cache_id = null, $compile_id = null, $parent = null) {
return $this->returnOrCreateTemplate($template)->isCached($cache_id, $compile_id, $parent);
}
/**
* @param $template
* @param $cache_id
* @param $compile_id
* @param $parent
*
* @return Template
* @throws Exception
*/
private function returnOrCreateTemplate($template, $cache_id, $compile_id, $parent) {
if (!($template instanceof Template)) {
$template = $this->createTemplate($template, $cache_id, $compile_id, $parent ?: $this, false);
$template->caching = $this->caching;
}
return $template;
}
}

View File

@@ -27,15 +27,6 @@ use Smarty\Template\Config;
#[\AllowDynamicProperties]
class Template extends TemplateBase {
/**
* Sub template Info Cache
* - index name
* - value use count
*
* @var int[]
*/
public static $subTplInfo = [];
/**
* This object type (Smarty = 1, template = 2, data = 4)
*
@@ -175,10 +166,7 @@ class Template extends TemplateBase {
*/
public function render($no_output_filter = true, $display = null) {
if ($this->smarty->debugging) {
if (!isset($this->smarty->_debug)) {
$this->smarty->_debug = new \Smarty\Debug();
}
$this->smarty->_debug->start_template($this, $display);
$this->smarty->getDebug()->start_template($this, $display);
}
// checks if template exists
if (!$this->source->exists) {
@@ -223,16 +211,16 @@ class Template extends TemplateBase {
}
}
if ($this->smarty->debugging) {
$this->smarty->_debug->end_template($this);
$this->smarty->getDebug()->end_template($this);
// debug output
$this->smarty->_debug->display_debug($this, true);
$this->smarty->getDebug()->display_debug($this, true);
}
return '';
} else {
if ($this->smarty->debugging) {
$this->smarty->_debug->end_template($this);
$this->smarty->getDebug()->end_template($this);
if ($this->smarty->debugging === 2 && $display === false) {
$this->smarty->_debug->display_debug($this, true);
$this->smarty->getDebug()->display_debug($this, true);
}
}
if (
@@ -314,7 +302,7 @@ class Template extends TemplateBase {
if (!empty($data)) {
// set up variable values
foreach ($data as $_key => $_val) {
$tpl->tpl_vars[$_key] = new \Smarty\Variable($_val, $this->isRenderingCache);
$tpl->assign($_key, $_val);
}
}
if ($tpl->caching === 9999) {
@@ -327,16 +315,13 @@ class Template extends TemplateBase {
}
if (isset($uid)) {
if ($smarty->debugging) {
if (!isset($smarty->_debug)) {
$smarty->_debug = new \Smarty\Debug();
}
$smarty->_debug->start_template($tpl);
$smarty->_debug->start_render($tpl);
$smarty->getDebug()->start_template($tpl);
$smarty->getDebug()->start_render($tpl);
}
$tpl->compiled->getRenderedTemplateCode($tpl, $content_func);
if ($smarty->debugging) {
$smarty->_debug->end_template($tpl);
$smarty->_debug->end_render($tpl);
$smarty->getDebug()->end_template($tpl);
$smarty->getDebug()->end_render($tpl);
}
} else {
if (isset($tpl->compiled)) {
@@ -347,51 +332,17 @@ class Template extends TemplateBase {
}
}
/**
* Get called sub-templates and save call count
*/
public function _subTemplateRegister() {
foreach ($this->compiled->includes as $name => $count) {
if (isset(self::$subTplInfo[$name])) {
self::$subTplInfo[$name] += $count;
} else {
self::$subTplInfo[$name] = $count;
}
}
}
/**
* Check if this is a sub template
*
* @return bool true is sub template
*/
public function _isSubTpl() {
return isset($this->parent) && $this->parent->_isTplObj();
return isset($this->parent) && $this->parent instanceof Template;
}
/**
* 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
*/
public function _assignInScope($varName, $value, $nocache = false, $scope = 0) {
if (isset($this->tpl_vars[$varName])) {
$this->tpl_vars[$varName] = clone $this->tpl_vars[$varName];
$this->tpl_vars[$varName]->value = $value;
if ($nocache || $this->isRenderingCache) {
$this->tpl_vars[$varName]->nocache = true;
}
} else {
$this->tpl_vars[$varName] = new \Smarty\Variable($value, $nocache || $this->isRenderingCache);
}
if ($scope >= 0) {
if ($scope > 0 || $this->scope > 0) {
$this->_updateScope($varName, $scope);
}
}
public function assign($tpl_var, $value = null, $nocache = false) {
return parent::assign($tpl_var, $value, $nocache || $this->isRenderingCache);
}
/**
@@ -677,14 +628,14 @@ class Template extends TemplateBase {
return;
}
}
if ($this->parent->_isTplObj() && ($tagScope || $this->parent->scope)) {
if ($this->parent instanceof Template && ($tagScope || $this->parent->scope)) {
$mergedScope = $tagScope | $this->scope;
if ($mergedScope) {
// update scopes
/* @var \Smarty\Data $ptr */
foreach ($this->parent->_getAffectedScopes($mergedScope) as $ptr) {
$this->_assignConfigVars($ptr->config_vars, $new_config_vars);
if ($tagScope && $ptr->_isTplObj() && isset($this->_var_stack)) {
if ($tagScope && $ptr instanceof Template && isset($this->_var_stack)) {
$this->_updateConfigVarStack($new_config_vars);
}
}
@@ -787,7 +738,7 @@ class Template extends TemplateBase {
// update scopes
foreach ($this->_getAffectedScopes($mergedScope) as $ptr) {
$this->_updateVariableInOtherScope($ptr->tpl_vars, $varName);
if ($tagScope && $ptr->_isTplObj() && isset($this->_var_stack)) {
if ($tagScope && $ptr instanceof Template && isset($this->_var_stack)) {
$this->_updateVarStack($ptr, $varName);
}
}
@@ -804,7 +755,7 @@ class Template extends TemplateBase {
private function _getAffectedScopes($mergedScope) {
$_stack = [];
$ptr = $this->parent;
if ($mergedScope && isset($ptr) && $ptr->_isTplObj()) {
if ($mergedScope && isset($ptr) && $ptr instanceof Template) {
$_stack[] = $ptr;
$mergedScope = $mergedScope & ~\Smarty\Smarty::SCOPE_PARENT;
if (!$mergedScope) {
@@ -813,7 +764,7 @@ class Template extends TemplateBase {
}
$ptr = $ptr->parent;
}
while (isset($ptr) && $ptr->_isTplObj()) {
while (isset($ptr) && $ptr instanceof Template) {
$_stack[] = $ptr;
$ptr = $ptr->parent;
}
@@ -823,7 +774,7 @@ class Template extends TemplateBase {
}
} elseif ($mergedScope & \Smarty\Smarty::SCOPE_ROOT) {
while (isset($ptr)) {
if (!$ptr->_isTplObj()) {
if (!$ptr instanceof Template) {
$_stack[] = $ptr;
break;
}
@@ -833,35 +784,6 @@ class Template extends TemplateBase {
return $_stack;
}
/**
* Update variable in other scope
*
* @param array $tpl_vars template variable array
* @param string $varName variable name
*/
private function _updateVariableInOtherScope(&$tpl_vars, $varName) {
if (!isset($tpl_vars[$varName])) {
$tpl_vars[$varName] = clone $this->tpl_vars[$varName];
} else {
$tpl_vars[$varName] = clone $tpl_vars[$varName];
$tpl_vars[$varName]->value = $this->tpl_vars[$varName]->value;
}
}
/**
* Update variable in template local variable stack
*
* @param Template $tpl
* @param string|null $varName variable name or null for config variables
*/
private function _updateVarStack(Template $tpl, $varName) {
$i = 0;
while (isset($tpl->_var_stack[$i])) {
$this->_updateVariableInOtherScope($tpl->_var_stack[$i]['tpl'], $varName);
$i++;
}
}
private function getFrameCompiler(): Compiler\CodeFrame {
return new \Smarty\Compiler\CodeFrame($this);
}
@@ -906,4 +828,147 @@ class Template extends TemplateBase {
$this->right_delimiter = $right_delimiter;
}
/**
* gets a stream variable
*
* @param string $variable the stream of the variable
*
* @return mixed
* @throws \Smarty\Exception
*
*/
public function getStreamVariable($variable)
{
$_result = '';
$fp = fopen($variable, 'r+');
if ($fp) {
while (!feof($fp) && ($current_line = fgets($fp)) !== false) {
$_result .= $current_line;
}
fclose($fp);
return $_result;
}
if ($this->_getSmartyObj()->error_unassigned) {
throw new Exception('Undefined stream variable "' . $variable . '"');
}
return null;
}
/**
* @inheritdoc
*/
public function _loadConfigfile($config_file, $sections = null, $scope = 0)
{
$confObj = parent::_loadConfigfile($config_file, $sections, $scope);
$this->compiled->file_dependency[ $confObj->source->uid ] =
array($confObj->source->filepath, $confObj->source->getTimeStamp(), $confObj->source->type);
return $confObj;
}
public function fetch($cache_id = null, $compile_id = null, $parent = null) {
$result = $this->_execute($cache_id, $compile_id, $parent, 0);
return $result === null ? ob_get_clean() : $result;
}
public function display($cache_id = null, $compile_id = null, $parent = null) {
$this->_execute($cache_id, $compile_id, $parent, 1);
}
/**
* test if cache is valid
*
* @param mixed $cache_id cache id to be used with this template
* @param mixed $compile_id compile id to be used with this template
* @param object $parent next higher level of Smarty variables
*
* @return bool cache status
* @throws \Exception
* @throws \Smarty\Exception
* @link https://www.smarty.net/docs/en/api.is.cached.tpl
*
* @api Smarty::isCached()
*/
public function isCached($template = null, $cache_id = null, $compile_id = null, $parent = null) {
return $this->_execute($template, $cache_id, $compile_id, $parent, 2);
}
/**
* fetches a rendered Smarty template
*
* @param mixed $cache_id cache id to be used with this template
* @param mixed $compile_id compile id to be used with this template
* @param object $parent next higher level of Smarty variables
* @param string $function function type 0 = fetch, 1 = display, 2 = isCache
*
* @return mixed
* @throws \Exception
* @throws \Smarty\Exception|\Throwable
*/
private function _execute($cache_id, $compile_id, $parent, $function) {
$smarty = $this->_getSmartyObj();
// make sure we have integer values
$this->caching = (int)$this->caching;
// fetch template content
$level = ob_get_level();
try {
$_smarty_old_error_level =
isset($smarty->error_reporting) ? error_reporting($smarty->error_reporting) : null;
if ($smarty->isMutingUndefinedOrNullWarnings()) {
$errorHandler = new \Smarty\ErrorHandler();
$errorHandler->activate();
}
/* @var Template $parent */
if (isset($parent->_objType) && ($parent->_objType === 2) && !empty($parent->tplFunctions)) {
$this->tplFunctions = array_merge($parent->tplFunctions, $this->tplFunctions);
}
if ($function === 2) {
if ($this->caching) {
// return cache status of template
if (!isset($this->cached)) {
$this->loadCached();
}
$result = $this->cached->isCached($this);
} else {
return false;
}
} else {
$savedTplVars = $this->tpl_vars;
$savedConfigVars = $this->config_vars;
ob_start();
$result = $this->render(false, $function);
$this->_cleanUp();
$this->tpl_vars = $savedTplVars;
$this->config_vars = $savedConfigVars;
}
if (isset($errorHandler)) {
$errorHandler->deactivate();
}
if (isset($_smarty_old_error_level)) {
error_reporting($_smarty_old_error_level);
}
return $result;
} catch (\Throwable $e) {
while (ob_get_level() > $level) {
ob_end_clean();
}
if (isset($errorHandler)) {
$errorHandler->deactivate();
}
if (isset($_smarty_old_error_level)) {
error_reporting($_smarty_old_error_level);
}
throw $e;
}
}
}

View File

@@ -120,17 +120,14 @@ class Cached extends ResourceBase {
public function render(Template $_template, $no_output_filter = true) {
if ($this->isCached($_template)) {
if ($_template->smarty->debugging) {
if (!isset($_template->smarty->_debug)) {
$_template->smarty->_debug = new \Smarty\Debug();
}
$_template->smarty->_debug->start_cache($_template);
$_template->smarty->getDebug()->start_cache($_template);
}
if (!$this->processed) {
$this->process($_template);
}
$this->getRenderedTemplateCode($_template);
if ($_template->smarty->debugging) {
$_template->smarty->_debug->end_cache($_template);
$_template->smarty->getDebug()->end_cache($_template);
}
return;
} else {
@@ -180,7 +177,7 @@ class Cached extends ResourceBase {
if (!$_template->smarty->cache_locking || $this->handler->locked($_template->smarty, $this) === null) {
// load cache file for the following checks
if ($_template->smarty->debugging) {
$_template->smarty->_debug->start_cache($_template);
$_template->smarty->getDebug()->start_cache($_template);
}
if ($this->handler->process($_template, $this) === false) {
$this->valid = false;
@@ -188,7 +185,7 @@ class Cached extends ResourceBase {
$this->processed = true;
}
if ($_template->smarty->debugging) {
$_template->smarty->_debug->end_cache($_template);
$_template->smarty->getDebug()->end_cache($_template);
}
} else {
$this->is_locked = true;
@@ -291,7 +288,7 @@ class Cached extends ResourceBase {
}
$_template->compiled->render($_template);
if ($_template->smarty->debugging) {
$_template->smarty->_debug->start_cache($_template);
$_template->smarty->getDebug()->start_cache($_template);
}
$this->removeNoCacheHash($_template, $no_output_filter);
$compile_check = (int)$_template->compile_check;
@@ -305,7 +302,7 @@ class Cached extends ResourceBase {
$_template->compile_check = $compile_check;
$this->getRenderedTemplateCode($_template);
if ($_template->smarty->debugging) {
$_template->smarty->_debug->end_cache($_template);
$_template->smarty->getDebug()->end_cache($_template);
}
}

View File

@@ -96,10 +96,7 @@ class Compiled extends ResourceBase {
throw new \Smarty\Exception("Unable to load {$type} '{$_template->source->type}:{$_template->source->name}'");
}
if ($_template->smarty->debugging) {
if (!isset($_template->smarty->_debug)) {
$_template->smarty->_debug = new \Smarty\Debug();
}
$_template->smarty->_debug->start_render($_template);
$_template->smarty->getDebug()->start_render($_template);
}
if (!$this->processed) {
$this->process($_template);
@@ -117,7 +114,7 @@ class Compiled extends ResourceBase {
$_template->cached->hashes[$this->nocache_hash] = true;
}
if ($_template->smarty->debugging) {
$_template->smarty->_debug->end_render($_template);
$_template->smarty->getDebug()->end_render($_template);
}
}
@@ -153,7 +150,6 @@ class Compiled extends ResourceBase {
$_smarty_tpl->compile_check = $compileCheck;
}
}
$_smarty_tpl->_subTemplateRegister();
$this->processed = true;
}
}

View File

@@ -10,13 +10,6 @@
namespace Smarty;
use Smarty\Cacheresource\Base;
use Smarty\Data;
use Smarty\Smarty;
use Smarty\Template;
use Smarty\DataObject;
use Smarty\Exception;
/**
* Class with shared smarty/template methods
*
@@ -77,166 +70,9 @@ abstract class TemplateBase extends Data {
public $_var_stack = null;
/**
* fetches a rendered Smarty template
*
* @param string $template the resource handle of the template file or template object
* @param mixed $cache_id cache id to be used with this template
* @param mixed $compile_id compile id to be used with this template
* @param object $parent next higher level of Smarty variables
*
* @return string rendered template output
* @throws Exception
* @throws Exception
* @var Debug
*/
public function fetch($template = null, $cache_id = null, $compile_id = null, $parent = null) {
$result = $this->_execute($template, $cache_id, $compile_id, $parent, 0);
return $result === null ? ob_get_clean() : $result;
}
/**
* displays a Smarty template
*
* @param string $template the resource handle of the template file or template object
* @param mixed $cache_id cache id to be used with this template
* @param mixed $compile_id compile id to be used with this template
* @param object $parent next higher level of Smarty variables
*
* @throws \Exception
* @throws \Smarty\Exception
*/
public function display($template = null, $cache_id = null, $compile_id = null, $parent = null) {
// display template
$this->_execute($template, $cache_id, $compile_id, $parent, 1);
}
/**
* test if cache is valid
*
* @param null|string|\Smarty\Template $template the resource handle of the template file or template
* object
* @param mixed $cache_id cache id to be used with this template
* @param mixed $compile_id compile id to be used with this template
* @param object $parent next higher level of Smarty variables
*
* @return bool cache status
* @throws \Exception
* @throws \Smarty\Exception
* @link https://www.smarty.net/docs/en/api.is.cached.tpl
*
* @api Smarty::isCached()
*/
public function isCached($template = null, $cache_id = null, $compile_id = null, $parent = null) {
return $this->_execute($template, $cache_id, $compile_id, $parent, 2);
}
/**
* fetches a rendered Smarty template
*
* @param string $template the resource handle of the template file or template object
* @param mixed $cache_id cache id to be used with this template
* @param mixed $compile_id compile id to be used with this template
* @param object $parent next higher level of Smarty variables
* @param string $function function type 0 = fetch, 1 = display, 2 = isCache
*
* @return mixed
* @throws \Exception
* @throws \Smarty\Exception
*/
private function _execute($template, $cache_id, $compile_id, $parent, $function) {
$smarty = $this->_getSmartyObj();
$saveVars = true;
if ($template === null) {
if (!$this->_isTplObj()) {
throw new Exception($function . '():Missing \'$template\' parameter');
} else {
$template = $this;
}
} elseif (is_object($template)) {
/* @var Template $template */
if (!isset($template->_objType) || !$template->_isTplObj()) {
throw new Exception($function . '():Template object expected');
}
} else {
// get template object
$saveVars = false;
$template = $smarty->createTemplate($template, $cache_id, $compile_id, $parent ?: $this, false);
if ($this->_objType === 1) {
// set caching in template object
$template->caching = $this->caching;
}
}
// make sure we have integer values
$template->caching = (int)$template->caching;
// fetch template content
$level = ob_get_level();
try {
$_smarty_old_error_level =
isset($smarty->error_reporting) ? error_reporting($smarty->error_reporting) : null;
if ($smarty->isMutingUndefinedOrNullWarnings()) {
$errorHandler = new \Smarty\ErrorHandler();
$errorHandler->activate();
}
if ($this->_objType === 2) {
/* @var Template $this */
$template->tplFunctions = $this->tplFunctions;
$template->inheritance = $this->inheritance;
}
/* @var Template $parent */
if (isset($parent->_objType) && ($parent->_objType === 2) && !empty($parent->tplFunctions)) {
$template->tplFunctions = array_merge($parent->tplFunctions, $template->tplFunctions);
}
if ($function === 2) {
if ($template->caching) {
// return cache status of template
if (!isset($template->cached)) {
$template->loadCached();
}
$result = $template->cached->isCached($template);
} else {
return false;
}
} else {
if ($saveVars) {
$savedTplVars = $template->tpl_vars;
$savedConfigVars = $template->config_vars;
}
ob_start();
$template->_mergeVars();
$template->tpl_vars = array_merge($this->_getSmartyObj()->getAllGlobalTemplateVars(), $template->tpl_vars);
$result = $template->render(false, $function);
$template->_cleanUp();
if ($saveVars) {
$template->tpl_vars = $savedTplVars;
$template->config_vars = $savedConfigVars;
}
}
if (isset($errorHandler)) {
$errorHandler->deactivate();
}
if (isset($_smarty_old_error_level)) {
error_reporting($_smarty_old_error_level);
}
return $result;
} catch (\Throwable $e) {
while (ob_get_level() > $level) {
ob_end_clean();
}
if (isset($errorHandler)) {
$errorHandler->deactivate();
}
if (isset($_smarty_old_error_level)) {
error_reporting($_smarty_old_error_level);
}
throw $e;
}
}
private $debug;
/**
* Registers object to be used in templates
@@ -361,7 +197,7 @@ abstract class TemplateBase extends Data {
$smarty = $this->_getSmartyObj();
$dataObj = new DataObject($parent, $smarty, $name);
if ($smarty->debugging) {
\Smarty\Debug::register_data($dataObj);
$smarty->getDebug()->register_data($dataObj);
}
return $dataObj;
}
@@ -378,6 +214,16 @@ abstract class TemplateBase extends Data {
return $smarty->debug_tpl;
}
/**
* @return Debug
*/
public function getDebug(): Debug {
if (!isset($this->debug)) {
$this->debug = new \Smarty\Debug();
}
return $this->debug;
}
/**
* return a reference to a registered object
@@ -591,4 +437,50 @@ abstract class TemplateBase extends Data {
return $this;
}
/**
* load a config file, optionally load just selected sections
*
* @param string $config_file filename
* @param mixed $sections array of section names, single
* section or null
*
* @return $this
* @throws \Exception
*@api Smarty::configLoad()
* @link https://www.smarty.net/docs/en/api.config.load.tpl
*
*/
public function configLoad($config_file, $sections = null)
{
$this->_loadConfigfile($config_file, $sections, null);
return $this;
}
/**
* load a config file, optionally load just selected sections
*
* @param string $config_file filename
* @param mixed $sections array of section names, single
* section or null
* @param int $scope scope into which config variables
* shall be loaded
* @returns Template
* @throws \Exception
* @link https://www.smarty.net/docs/en/api.config.load.tpl
*
* @api Smarty::configLoad()
*/
public function _loadConfigfile($config_file, $sections = null, $scope = 0)
{
$smarty = $this->_getSmartyObj();
$confObj = new Template($config_file, $smarty, $this, null, null, null, null, true);
$confObj->caching = Smarty::CACHING_OFF;
$confObj->source->config_sections = $sections;
$confObj->source->scope = $scope;
$confObj->compiled = \Smarty\Template\Compiled::load($confObj);
$confObj->compiled->render($confObj);
return $confObj;
}
}

View File

@@ -236,7 +236,7 @@ function myoutputfilter($input)
function myoutputfilter2($input, $tpl)
{
return $input . ' filter ' . $tpl->tpl_vars[ 'bar' ];
return $input . ' filter ' . $tpl->getValue('bar');
}
class myprefilterclass

View File

@@ -57,7 +57,7 @@ class GetTemplateVarsTest extends PHPUnit_Smarty
$data2 = $this->smarty->createData($data1);
$this->smarty->assign('foo', 'bar');
$this->smarty->assign('blar', 'buh');
$this->assertEquals("bar", $this->smarty->getTemplateVars('foo', $data2));
$this->assertEquals("bar", $data2->getTemplateVars('foo'));
}
/**
@@ -70,7 +70,7 @@ class GetTemplateVarsTest extends PHPUnit_Smarty
$this->smarty->assign('foo', 'bar');
$data1->assign('blar', 'buh');
$data2->assign('foo2', 'bar2');
$vars = $this->smarty->getTemplateVars(null, $data2);
$vars = $data2->getTemplateVars(null);
$this->assertTrue(is_array($vars));
$this->assertEquals("bar", $vars['foo']);
$this->assertEquals("bar2", $vars['foo2']);
@@ -87,7 +87,7 @@ class GetTemplateVarsTest extends PHPUnit_Smarty
$this->smarty->assign('foo', 'bar');
$data1->assign('blar', 'buh');
$data2->assign('foo2', 'bar2');
$vars = $this->smarty->getTemplateVars(null, $data2, false);
$vars = $data2->getTemplateVars(null, false);
$this->assertTrue(is_array($vars));
$this->assertFalse(isset($vars['foo']));
$this->assertEquals("bar2", $vars['foo2']);
@@ -105,8 +105,8 @@ class GetTemplateVarsTest extends PHPUnit_Smarty
$this->smarty->assign('foo', 'bar');
$data1->assign('blar', 'buh');
$data2->assign('foo2', 'bar2');
$this->assertEquals("", $this->smarty->getTemplateVars('foo', $data2, false));
$this->assertEquals("bar2", $this->smarty->getTemplateVars('foo2', $data2, false));
$this->assertEquals("", $this->smarty->getTemplateVars('blar', $data2, false));
$this->assertEquals("", $data2->getTemplateVars('foo', false));
$this->assertEquals("bar2", $data2->getTemplateVars('foo2', false));
$this->assertEquals("", $data2->getTemplateVars('blar', false));
}
}

View File

@@ -29,7 +29,7 @@ function smarty_function_checkvar($params, \Smarty\Template $template)
while ($ptr) {
if (in_array('template', $types) && $ptr instanceof Template) {
$output .= "#{$ptr->source->name}:\${$var} =";
$output .= isset($ptr->tpl_vars[$var]) ? preg_replace('/\s/', '', var_export($ptr->tpl_vars[$var]->value, true)) : '>unassigned<';
$output .= $ptr->hasVariable($var) ? preg_replace('/\s/', '', var_export($ptr->getValue($var), true)) : '>unassigned<';
$i = 0;
while (isset($ptr->_var_stack[ $i ])) {
$output .= "#{$ptr->_var_stack[ $i ]['name']} = ";
@@ -39,7 +39,7 @@ function smarty_function_checkvar($params, \Smarty\Template $template)
$ptr = $ptr->parent;
} elseif (in_array('data', $types) && $ptr instanceof DataObject) {
$output .= "#data:\${$var} =";
$output .= isset($ptr->tpl_vars[$var]) ? preg_replace('/\s/', '', var_export($ptr->tpl_vars[$var]->value, true)) : '>unassigned<';
$output .= $ptr->hasVariable($var) ? preg_replace('/\s/', '', var_export($ptr->getValue($var), true)) : '>unassigned<';
$ptr = $ptr->parent;
} else {
$ptr = null;
@@ -47,8 +47,8 @@ function smarty_function_checkvar($params, \Smarty\Template $template)
}
if (in_array('smarty', $types)) {
$output .= "#Smarty:\${$var} =";
$output .= isset($template->smarty->tpl_vars[ $var ]) ?
preg_replace('/\s/', '', var_export($template->smarty->tpl_vars[ $var ]->value, true)) : '>unassigned<';
$output .= $template->smarty->hasVariable($var) ?
preg_replace('/\s/', '', var_export($template->smarty->getValue($var), true)) : '>unassigned<';
}
if (in_array('global', $types)) {
$output .= "#global:\${$var} =";