diff --git a/README.md b/README.md index 0ef3cfab..4cbd204d 100644 --- a/README.md +++ b/README.md @@ -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/). diff --git a/composer.json b/composer.json index df463a86..3e9eb62f 100644 --- a/composer.json +++ b/composer.json @@ -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": { diff --git a/src/Compile/Tag/ForTag.php b/src/Compile/Tag/ForTag.php index a66e50ce..f62d8771 100644 --- a/src/Compile/Tag/ForTag.php +++ b/src/Compile/Tag/ForTag.php @@ -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 { diff --git a/src/Compile/Tag/ForeachSection.php b/src/Compile/Tag/ForeachSection.php index e066309a..d72936d9 100644 --- a/src/Compile/Tag/ForeachSection.php +++ b/src/Compile/Tag/ForeachSection.php @@ -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)"; } } diff --git a/src/Compile/Tag/ForeachTag.php b/src/Compile/Tag/ForeachTag.php index 335fd2b2..458e9676 100644 --- a/src/Compile/Tag/ForeachTag.php +++ b/src/Compile/Tag/ForeachTag.php @@ -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; diff --git a/src/Compile/Tag/FunctionClose.php b/src/Compile/Tag/FunctionClose.php index baf2547e..e76822e0 100644 --- a/src/Compile/Tag/FunctionClose.php +++ b/src/Compile/Tag/FunctionClose.php @@ -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}%%*/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, diff --git a/src/Compiler/Configfile.php b/src/Compiler/Configfile.php index 6a7a0381..75fc6a03 100644 --- a/src/Compiler/Configfile.php +++ b/src/Compiler/Configfile.php @@ -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( diff --git a/src/Compiler/Template.php b/src/Compiler/Template.php index 6673c7f2..4f04aab5 100644 --- a/src/Compiler/Template.php +++ b/src/Compiler/Template.php @@ -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); } } } diff --git a/src/Data.php b/src/Data.php index 3e750bc0..73801c0c 100644 --- a/src/Data.php +++ b/src/Data.php @@ -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; - } - } + } diff --git a/src/DataObject.php b/src/DataObject.php index f5bcb78b..945fa8c0 100644 --- a/src/DataObject.php +++ b/src/DataObject.php @@ -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'); diff --git a/src/Debug.php b/src/Debug.php index 43d4e107..fd1efa38 100644 --- a/src/Debug.php +++ b/src/Debug.php @@ -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); diff --git a/src/Resource/BasePlugin.php b/src/Resource/BasePlugin.php index a15809b8..2212ead0 100644 --- a/src/Resource/BasePlugin.php +++ b/src/Resource/BasePlugin.php @@ -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); } diff --git a/src/Runtime/ForeachRuntime.php b/src/Runtime/ForeachRuntime.php index d8791ff6..5012ce4d 100644 --- a/src/Runtime/ForeachRuntime.php +++ b/src/Runtime/ForeachRuntime.php @@ -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]; diff --git a/src/Runtime/MakeNocacheRuntime.php b/src/Runtime/MakeNocacheRuntime.php index bf755df9..1805465e 100644 --- a/src/Runtime/MakeNocacheRuntime.php +++ b/src/Runtime/MakeNocacheRuntime.php @@ -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) { diff --git a/src/Smarty.php b/src/Smarty.php index f241ae33..bd62c190 100644 --- a/src/Smarty.php +++ b/src/Smarty.php @@ -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; + } + } diff --git a/src/Template.php b/src/Template.php index ae806889..2642e5ec 100644 --- a/src/Template.php +++ b/src/Template.php @@ -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; + } + } + + } diff --git a/src/Template/Cached.php b/src/Template/Cached.php index 308d7130..857e807e 100644 --- a/src/Template/Cached.php +++ b/src/Template/Cached.php @@ -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); } } diff --git a/src/Template/Compiled.php b/src/Template/Compiled.php index 0e20e3da..efd0053b 100644 --- a/src/Template/Compiled.php +++ b/src/Template/Compiled.php @@ -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; } } diff --git a/src/TemplateBase.php b/src/TemplateBase.php index 6bada619..4ad90512 100644 --- a/src/TemplateBase.php +++ b/src/TemplateBase.php @@ -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; + } + } diff --git a/tests/UnitTests/A_Core/Filter/FilterTest.php b/tests/UnitTests/A_Core/Filter/FilterTest.php index 37a047fb..ad005518 100644 --- a/tests/UnitTests/A_Core/Filter/FilterTest.php +++ b/tests/UnitTests/A_Core/Filter/FilterTest.php @@ -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 diff --git a/tests/UnitTests/SmartyMethodsTests/GetTemplateVars/GetTemplateVarsTest.php b/tests/UnitTests/SmartyMethodsTests/GetTemplateVars/GetTemplateVarsTest.php index 1dcb41ed..4aab7c3b 100644 --- a/tests/UnitTests/SmartyMethodsTests/GetTemplateVars/GetTemplateVarsTest.php +++ b/tests/UnitTests/SmartyMethodsTests/GetTemplateVars/GetTemplateVarsTest.php @@ -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)); } } diff --git a/tests/UnitTests/__shared/PHPunitplugins/function.checkvar.php b/tests/UnitTests/__shared/PHPunitplugins/function.checkvar.php index 7a27073e..4893c50a 100644 --- a/tests/UnitTests/__shared/PHPunitplugins/function.checkvar.php +++ b/tests/UnitTests/__shared/PHPunitplugins/function.checkvar.php @@ -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} =";