From 7408c18cdc2273de7b64a1a0c9df6f4700d97bfc Mon Sep 17 00:00:00 2001 From: Simon Wisselink Date: Fri, 3 Feb 2023 15:50:31 +0100 Subject: [PATCH] WIP for performance improvements. Removed $smarty->_current_file and $smarty->allow_ambiguous_resources properties, both unused. Removed public Source::filepath property. Cached an Compiled files (and Exceptions) no longer rely on the filepath being set. Removed explicit tests for cached and compiled filenames. The exact implementation is not important. Added tests for compile_check property, fixing a file_exists check that would always be done on source template files, even when compile_check was true. Remove code duplication between Source en Config classes. Added a local $_smarty_current_dir to the generated code files for backwards compatability for {$smarty.current_dir}. --- CHANGELOG.md | 2 + TODO.txt | 8 +- src/Cacheresource/File.php | 11 +- src/Compile/SpecialVariableCompiler.php | 4 +- src/Compile/Tag/Block.php | 1 - src/Compile/Tag/BlockClose.php | 4 + src/Compile/Tag/ExtendsTag.php | 2 +- src/Compile/Tag/FunctionClose.php | 9 +- src/Compile/Tag/IncludeTag.php | 3 +- src/Compiler/CodeFrame.php | 12 +- src/Compiler/Configfile.php | 6 +- src/Compiler/Template.php | 17 +- src/Data.php | 6 +- src/Debug.php | 17 +- src/Resource/BasePlugin.php | 24 - src/Resource/CustomPlugin.php | 7 +- src/Resource/ExtendsPlugin.php | 10 +- src/Resource/FilePlugin.php | 83 +- src/Resource/StreamPlugin.php | 14 +- src/Resource/StringEval.php | 2 +- src/Resource/StringPlugin.php | 4 +- src/Runtime/InheritanceRuntime.php | 9 +- src/Smarty.php | 2093 ++++++++--------- src/Template.php | 91 +- src/Template/Cached.php | 15 +- src/Template/Compiled.php | 19 +- src/Template/Config.php | 44 +- src/Template/GeneratedPhpFile.php | 18 +- src/Template/Source.php | 76 +- tests/PHPUnit_Smarty.php | 4 +- .../File/CacheResourceFileTest.php | 18 +- .../_shared/CacheResourceTestCommon.php | 6 +- .../PHPunitplugins/resource.filetest.php | 4 +- .../CompileCompilerPluginTest.php | 6 +- .../DefaultConfigHandlerTest.php | 6 +- .../Ambiguous/CustomResourceAmbiguousTest.php | 8 +- .../PHPunitplugins/resource.ambiguous.php | 22 +- .../ResourceMysqlPluginTest.php | 2 +- .../DefaultTemplateHandlerTest.php | 2 +- .../ResourceTests/Eval/EvalResourceTest.php | 10 +- .../Extends/ExtendsResourceTest.php | 8 +- .../ResourceTests/File/FileResourceTest.php | 43 +- .../FileIndexed/FileResourceIndexedTest.php | 35 +- .../Registered/RegisteredResourceTest.php | 4 +- .../PHPunitplugins/resource.db.php | 1 - .../PHPunitplugins/resource.db2.php | 1 - .../PHPunitplugins/resource.db3.php | 1 - .../PHPunitplugins/resource.db4.php | 1 - .../Stream/StreamResourceTest.php | 4 +- .../String/StringResourceTest.php | 11 +- .../UnitTests/SecurityTests/SecurityTest.php | 4 +- .../ClearCompiledTest.php | 24 +- .../CompileCheck/CompileCheckTest.php | 139 ++ .../BlockPlugin/CompileBlockPluginTest.php | 4 +- .../resources/resource.extendsall.php | 3 +- 55 files changed, 1510 insertions(+), 1472 deletions(-) create mode 100644 tests/UnitTests/SmartyMethodsTests/CompileCheck/CompileCheckTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index e310311f..e1695956 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed direct access to `$smarty->cache_dir`. Use `$smarty->setCacheDir()`. - Removed `$smarty->loadPlugin()`, use `$smarty->registerPlugin()` instead. - Removed `$smarty->appendByRef()` and `$smarty->assignByRef()`. +- Removed `$smarty->_current_file` +- Removed `$smarty->allow_ambiguous_resources`, but ambiguous resources handlers should still work ### Fixed - `$smarty->muteUndefinedOrNullWarnings()` now also mutes PHP7 notices for undefined array indexes [#736](https://github.com/smarty-php/smarty/issues/736) diff --git a/TODO.txt b/TODO.txt index 6ca51bcd..d7378442 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,5 +1,10 @@ # @TODO +## Performance improvements +- context: pass template variables in an array +- why do we do 300k assign() calls? (answer: foreach?) +- debugging: see if removing debugging code speeds up + ## Review direct variable property access - review ->value{$index} in ForTag @@ -12,9 +17,6 @@ ## Review public static vars - such as _CHARSET and _IS_WINDOWS -## Benchmark -- benchmark to see that performance hasn't degraded - ## Block / inheritance - Consider phasing out $smarty.block.child as this reverses the inheritance hierarchy and might cause infinite loops when combined with $smarty.block.parent diff --git a/src/Cacheresource/File.php b/src/Cacheresource/File.php index 9bd2c778..538f0103 100644 --- a/src/Cacheresource/File.php +++ b/src/Cacheresource/File.php @@ -36,7 +36,7 @@ class File extends Base $source = $_template->getSource(); $smarty = $_template->getSmarty(); $_compile_dir_sep = $smarty->use_sub_dirs ? DIRECTORY_SEPARATOR : '^'; - $_filepath = sha1($source->uid . $smarty->_joined_template_dir); + $_filepath = $source->uid; $cached->filepath = $smarty->getCacheDir(); if (isset($_template->cache_id)) { $cached->filepath .= preg_replace( @@ -61,11 +61,8 @@ class File extends Base DIRECTORY_SEPARATOR . $_filepath[ 4 ] . $_filepath[ 5 ] . DIRECTORY_SEPARATOR; } - $cached->filepath .= $_filepath; - $basename = $source->getBasename(); - if (!empty($basename)) { - $cached->filepath .= '.' . $basename; - } + $cached->filepath .= $_filepath . '_' . $source->getBasename(); + if ($smarty->cache_locking) { $cached->lock_id = $cached->filepath . '.lock'; } @@ -205,7 +202,7 @@ class File extends Base if (isset($resource_name)) { $_save_stat = $smarty->caching; $smarty->caching = \Smarty\Smarty::CACHING_LIFETIME_CURRENT; - $tpl = $smarty->createTemplate($resource_name); + $tpl = $smarty->doCreateTemplate($resource_name); $smarty->caching = $_save_stat; // remove from template cache if ($tpl->getSource()->exists) { diff --git a/src/Compile/SpecialVariableCompiler.php b/src/Compile/SpecialVariableCompiler.php index 0ba96656..08f9aa69 100644 --- a/src/Compile/SpecialVariableCompiler.php +++ b/src/Compile/SpecialVariableCompiler.php @@ -82,7 +82,7 @@ class SpecialVariableCompiler extends Base { $compiled_ref = '$_' . smarty_strtoupper_ascii($variable); break; case 'template': - return 'basename($_smarty_tpl->getSource()->filepath)'; + return '$_smarty_tpl->template_resource'; case 'template_object': if (isset($compiler->getSmarty()->security_policy)) { $compiler->trigger_template_error("(secure mode) template_object not permitted"); @@ -90,7 +90,7 @@ class SpecialVariableCompiler extends Base { } return '$_smarty_tpl'; case 'current_dir': - return 'dirname($_smarty_tpl->getSource()->filepath)'; + return '$_smarty_current_dir'; case 'version': return "\\Smarty\\Smarty::SMARTY_VERSION"; case 'const': diff --git a/src/Compile/Tag/Block.php b/src/Compile/Tag/Block.php index 8bbd44f6..ce6df4f7 100644 --- a/src/Compile/Tag/Block.php +++ b/src/Compile/Tag/Block.php @@ -84,7 +84,6 @@ class Block extends Inheritance { ] ); - // @TODO what is this for? $compiler->getParser()->current_buffer = new Template(); $compiler->getTemplate()->getCompiled()->setNocacheCode(false); $compiler->suppressNocacheProcessing = true; diff --git a/src/Compile/Tag/BlockClose.php b/src/Compile/Tag/BlockClose.php index 7dc9c60d..0c052001 100644 --- a/src/Compile/Tag/BlockClose.php +++ b/src/Compile/Tag/BlockClose.php @@ -50,6 +50,9 @@ class BlockClose extends Inheritance { $output .= "public \${$property} = " . var_export($value, true) . ";\n"; } $output .= "public function callBlock(\\Smarty\\Template \$_smarty_tpl) {\n"; + + $output .= (new \Smarty\Compiler\CodeFrame($compiler->getTemplate()))->insertLocalVariables(); + if ($compiler->getTemplate()->getCompiled()->getNocacheCode()) { $output .= "\$_smarty_tpl->getCached()->hashes['{$compiler->getTemplate()->getCompiled()->nocache_hash}'] = true;\n"; } @@ -104,4 +107,5 @@ class BlockClose extends Inheritance { $compiler->suppressNocacheProcessing = true; return $output; } + } \ No newline at end of file diff --git a/src/Compile/Tag/ExtendsTag.php b/src/Compile/Tag/ExtendsTag.php index f295339b..2e9e0aed 100644 --- a/src/Compile/Tag/ExtendsTag.php +++ b/src/Compile/Tag/ExtendsTag.php @@ -103,7 +103,7 @@ class ExtendsTag extends Inheritance { $compiler->getParser()->template_postfix[] = new \Smarty\ParseTree\Tag( $compiler->getParser(), 'getInheritance()->endChild($_smarty_tpl' . - (isset($template) ? ", {$template}" : '') . ");\n?>" + (isset($template) ? ", {$template}, \$_smarty_current_dir" : '') . ");\n?>" ); } diff --git a/src/Compile/Tag/FunctionClose.php b/src/Compile/Tag/FunctionClose.php index b7dda8b1..6e208ffe 100644 --- a/src/Compile/Tag/FunctionClose.php +++ b/src/Compile/Tag/FunctionClose.php @@ -48,11 +48,12 @@ class FunctionClose extends Base { unset($_parameter['name']); // default parameter $_paramsArray = $this->formatParamsArray($_attr); + + $_paramsCode = (new \Smarty\Compiler\CodeFrame($compiler->getTemplate()))->insertLocalVariables(); + if (!empty($_paramsArray)) { $_params = 'array(' . implode(',', $_paramsArray) . ')'; - $_paramsCode = "\$params = array_merge($_params, \$params);\n"; - } else { - $_paramsCode = ''; + $_paramsCode .= "\$params = array_merge($_params, \$params);\n"; } $_functionCode = $compiler->getParser()->current_buffer; // setup buffer for template function code @@ -67,6 +68,7 @@ class FunctionClose extends Base { $output .= $compiler->cStyleComment(" {$_funcNameCaching} ") . "\n"; $output .= "if (!function_exists('{$_funcNameCaching}')) {\n"; $output .= "function {$_funcNameCaching} (\\Smarty\\Template \$_smarty_tpl,\$params) {\n"; + $output .= "ob_start();\n"; $output .= "\$_smarty_tpl->getCompiled()->setNocacheCode(true);\n"; $output .= $_paramsCode; @@ -149,7 +151,6 @@ class FunctionClose extends Base { * @return string */ public function removeNocache($match) { - // @TODO why is this here, and will the $this->compiler property survive long enough for the callback? $hash = $this->compiler->getTemplate()->getCompiled()->nocache_hash; $code = preg_replace( diff --git a/src/Compile/Tag/IncludeTag.php b/src/Compile/Tag/IncludeTag.php index 478d4abd..f7619cc7 100644 --- a/src/Compile/Tag/IncludeTag.php +++ b/src/Compile/Tag/IncludeTag.php @@ -108,7 +108,6 @@ class IncludeTag extends Base { $_caching = Smarty::CACHING_OFF; // caching was on and {include} is not in nocache mode - // @TODO see if we can do without this if ($compiler->getTemplate()->caching && !$compiler->isNocacheActive()) { $_caching = \Smarty\Template::CACHING_NOCACHE_CODE; } @@ -178,7 +177,7 @@ class IncludeTag extends Base { $_output .= "ob_start();\n"; } $_output .= "\$_smarty_tpl->renderSubTemplate({$fullResourceName}, $_cache_id, \$_smarty_tpl->compile_id, " . - "$_caching, $_cache_lifetime, $_vars, (int) {$_scope});\n"; + "$_caching, $_cache_lifetime, $_vars, (int) {$_scope}, \$_smarty_current_dir);\n"; if (isset($_assign)) { $_output .= "\$_smarty_tpl->assign({$_assign}, ob_get_clean(), false, {$_scope});\n"; } diff --git a/src/Compiler/CodeFrame.php b/src/Compiler/CodeFrame.php index 7a815081..69d17ed9 100644 --- a/src/Compiler/CodeFrame.php +++ b/src/Compiler/CodeFrame.php @@ -59,13 +59,16 @@ class CodeFrame "_template->getSource()->filepath) + str_replace('*/', '* /', $this->_template->getSource()->getFullResourceName()) ); $output .= "/* @var \\Smarty\\Template \$_smarty_tpl */\n"; $dec = "\$_smarty_tpl->" . ($cache ? "getCached()" : "getCompiled()"); $dec .= "->isFresh(\$_smarty_tpl, " . var_export($properties, true) . ')'; $output .= "if ({$dec}) {\n"; $output .= "function {$properties['unifunc']} (\\Smarty\\Template \$_smarty_tpl) {\n"; + + $output .= $this->insertLocalVariables(); + if (!$cache && !empty($compiler->tpl_function)) { $output .= '$_smarty_tpl->getSmarty()->getRuntime(\'TplFunction\')->registerTplFunctions($_smarty_tpl, '; $output .= var_export($compiler->tpl_function, true); @@ -113,4 +116,11 @@ class CodeFrame } return $output; } + + /** + * @return string + */ + public function insertLocalVariables(): string { + return '$_smarty_current_dir = ' . var_export(dirname($this->_template->getSource()->getFilepath()), true) . ";\n"; + } } diff --git a/src/Compiler/Configfile.php b/src/Compiler/Configfile.php index 1d50e3f2..7297a62b 100644 --- a/src/Compiler/Configfile.php +++ b/src/Compiler/Configfile.php @@ -84,7 +84,7 @@ class Configfile extends BaseCompiler { $this->template = $template; $this->template->getCompiled()->file_dependency[$this->template->getSource()->uid] = [ - $this->template->getSource()->filepath, + $this->template->getSource()->getResourceName(), $this->template->getSource()->getTimeStamp(), $this->template->getSource()->type, ]; @@ -126,7 +126,7 @@ class Configfile extends BaseCompiler { "\n", \Smarty\Smarty::SMARTY_VERSION, date("Y-m-d H:i:s"), - str_replace('*/', '* /', $this->template->getSource()->filepath) + str_replace('*/', '* /', $this->template->getSource()->getFullResourceName()) ); $code = 'parent->assignConfigVars(' . var_export($this->config_data, true) . ', $_smarty_tpl->getValue("sections")); ?>'; @@ -151,7 +151,7 @@ class Configfile extends BaseCompiler { } $match = preg_split("/\n/", $this->lex->data); $error_text = - "Syntax error in config file '{$this->template->getSource()->filepath}' on line {$line} '{$match[$line - 1]}' "; + "Syntax error in config file '{$this->template->getSource()->getFullResourceName()}' on line {$line} '{$match[$line - 1]}' "; if (isset($args)) { // individual error message $error_text .= $args; diff --git a/src/Compiler/Template.php b/src/Compiler/Template.php index dc60472f..03ee5110 100644 --- a/src/Compiler/Template.php +++ b/src/Compiler/Template.php @@ -403,12 +403,11 @@ class Template extends BaseCompiler { if ($this->template->getSource()->handler->checkTimestamps()) { $this->parent_compiler->getTemplate()->getCompiled()->file_dependency[$this->template->getSource()->uid] = [ - $this->template->getSource()->filepath, + $this->template->getSource()->getResourceName(), $this->template->getSource()->getTimeStamp(), $this->template->getSource()->type, ]; } - $this->smarty->_current_file = $this->template->getSource()->filepath; // get template source if (!empty($this->template->getSource()->components)) { // we have array of inheritance templates by extends: resource @@ -811,7 +810,7 @@ class Template extends BaseCompiler { ) ); } else { - $templateName = $this->template->getSource()->type . ':' . $this->template->getSource()->filepath; + $templateName = $this->template->getSource()->getFullResourceName(); } // $line += $this->trace_line_offset; $match = preg_split("/\n/", $lex->data); @@ -848,12 +847,12 @@ class Template extends BaseCompiler { $e = new CompilerException( $error_text, 0, - $this->template->getSource()->filepath, + $this->template->getSource()->getFullResourceName(), $line ); $e->source = trim(preg_replace('![\t\r\n]+!', ' ', $match[$line - 1])); $e->desc = $args; - $e->template = $this->template->getSource()->filepath; + $e->template = $this->template->getSource()->getFullResourceName(); throw $e; } @@ -1128,13 +1127,6 @@ class Template extends BaseCompiler { return $this->has_code ? $_output : null; } -// @TODO: This code was in here in v4, but it might not do anything (anymore) -// foreach ($args['_attr'] ?? [] as $attribute) { -// if (is_array($attribute)) { -// $args = array_merge($args, $attribute); -// } -// } - // remaining tastes: (object-)function, (object-function-)block, custom-compiler // opening and closing tags for these are handled with the same handler $base_tag = $this->getBaseTag($tag); @@ -1485,5 +1477,4 @@ class Template extends BaseCompiler { public function getTagStack(): array { return $this->_tag_stack; } - } diff --git a/src/Data.php b/src/Data.php index 5385f694..adacf216 100644 --- a/src/Data.php +++ b/src/Data.php @@ -51,7 +51,7 @@ class Data * Default scope for new variables * @var int */ - private $defaultScope = self::SCOPE_LOCAL; + protected $defaultScope = self::SCOPE_LOCAL; /** * create Smarty data object @@ -454,11 +454,11 @@ class Data */ public function configLoad($config_file, $sections = null) { - $template = $this->getSmarty()->createTemplate($config_file, null, null, $this, null, null, null, true); + $template = $this->getSmarty()->doCreateTemplate($config_file, null, null, $this, null, null, true); $template->caching = Smarty::CACHING_OFF; $template->assign('sections', (array) $sections ?? []); // trigger a call to $this->assignConfigVars - $template->getCompiled(true)->render($template); + $template->fetch(); return $this; } diff --git a/src/Debug.php b/src/Debug.php index 4591ac46..946a0cde 100644 --- a/src/Debug.php +++ b/src/Debug.php @@ -213,8 +213,6 @@ class Debug extends Data $debObj->registered_filters = array(); $debObj->escape_html = true; $debObj->caching = \Smarty::CACHING_OFF; - $debObj->compile_id = null; - $debObj->cache_id = null; // prepare information of assigned variables $ptr = $this->get_debug_vars($obj); $_assigned_vars = $ptr->tpl_vars; @@ -222,7 +220,7 @@ class Debug extends Data $_config_vars = $ptr->config_vars; ksort($_config_vars); $debugging = $smarty->debugging; - $_template = $debObj->createTemplate($debObj->debug_tpl); + $_template = $debObj->doCreateTemplate($debObj->debug_tpl); if ($obj instanceof \Smarty\Template) { $_template->assign('template_name', $obj->getSource()->type . ':' . $obj->getSource()->name); } elseif ($obj instanceof Smarty || $full) { @@ -305,10 +303,7 @@ class Debug extends Data private function get_key(\Smarty\Template $template) { static $_is_stringy = array('string' => true, 'eval' => true); - // calculate Uid if not already done - if ($template->getSource()->uid === '') { - $template->getSource()->filepath; - } + $key = $template->getSource()->uid; if (isset($this->template_data[ $this->index ][ $key ])) { return $key; @@ -326,11 +321,7 @@ class Debug extends Data */ public function ignore(\Smarty\Template $template) { - // calculate Uid if not already done - if ($template->getSource()->uid === '') { - $template->getSource()->filepath; - } - $this->ignore_uid[ $template->getSource()->uid ] = true; + $this->ignore_uid[$template->getSource()->uid] = true; } /** @@ -377,7 +368,7 @@ class Debug extends Data $this->template_data[$this->index][$key]['name'] = '\'' . substr($template->getSource()->name, 0, 25) . '...\''; } else { - $this->template_data[$this->index][$key]['name'] = $template->getSource()->filepath; + $this->template_data[$this->index][$key]['name'] = $template->getSource()->getResourceName(); } $this->template_data[$this->index][$key]['compile_time'] = 0; $this->template_data[$this->index][$key]['render_time'] = 0; diff --git a/src/Resource/BasePlugin.php b/src/Resource/BasePlugin.php index bad56cbf..56f7dfa0 100644 --- a/src/Resource/BasePlugin.php +++ b/src/Resource/BasePlugin.php @@ -96,30 +96,6 @@ abstract class BasePlugin throw new \Smarty\Exception("Unknown resource type '{$type}'"); } - /** - * extract resource_type and resource_name from template_resource and config_resource - * - * @note "C:/foo.tpl" was forced to file resource up till Smarty 3.1.3 (including). - * - * @param string $resource_name template_resource or config_resource to parse - * @param string $default_resource the default resource_type defined in $smarty - * - * @return array with parsed resource name and type - */ - public static function parseResourceName($resource_name, $default_resource) - { - if (preg_match('/^([A-Za-z0-9_\-]{2,})[:]/', $resource_name, $match)) { - $type = $match[ 1 ]; - $name = substr($resource_name, strlen($match[ 0 ])); - } else { - // no resource given, use default - // or single character before the colon is not a resource type, but part of the filepath - $type = $default_resource; - $name = $resource_name; - } - return array($name, $type); - } - /** * Load template's source into current template object * diff --git a/src/Resource/CustomPlugin.php b/src/Resource/CustomPlugin.php index fa2675ff..b50ef7aa 100644 --- a/src/Resource/CustomPlugin.php +++ b/src/Resource/CustomPlugin.php @@ -45,20 +45,19 @@ abstract class CustomPlugin extends BasePlugin { } /** - * populate Source Object with meta data from Resource + * populate Source Object with metadata from Resource * * @param Source $source source object - * @param Template $_template template object + * @param Template|null $_template template object */ public function populate(Source $source, Template $_template = null) { - $source->filepath = $source->type . ':' . $this->generateSafeName($source->name); $source->uid = sha1($source->type . ':' . $source->name); $mtime = $this->fetchTimestamp($source->name); if ($mtime !== null) { $source->timestamp = $mtime; } else { $this->fetch($source->name, $content, $timestamp); - $source->timestamp = isset($timestamp) ? $timestamp : false; + $source->timestamp = $timestamp ?? false; if (isset($content)) { $source->content = $content; } diff --git a/src/Resource/ExtendsPlugin.php b/src/Resource/ExtendsPlugin.php index b8aeab2c..acce54e2 100644 --- a/src/Resource/ExtendsPlugin.php +++ b/src/Resource/ExtendsPlugin.php @@ -32,17 +32,13 @@ class ExtendsPlugin extends BasePlugin $exists = true; foreach ($components as $component) { $_s = Source::load(null, $smarty, $component); - if ($_s->type === 'php') { - throw new \Smarty\Exception("Resource type {$_s->type} cannot be used with the extends resource type"); - } $sources[ $_s->uid ] = $_s; - $uid .= $_s->filepath; + $uid .= $_s->uid; if ($_template) { $exists = $exists && $_s->exists; } } $source->components = $sources; - $source->filepath = $_s->filepath; $source->uid = sha1($uid . $source->getSmarty()->_joined_template_dir); $source->exists = $exists; if ($_template) { @@ -76,7 +72,7 @@ class ExtendsPlugin extends BasePlugin public function getContent(Source $source) { if (!$source->exists) { - throw new \Smarty\Exception("Unable to load template '{$source->type}:{$source->name}'"); + throw new \Smarty\Exception("Unable to load '{$source->type}:{$source->name}'"); } $_components = array_reverse($source->components); $_content = ''; @@ -97,7 +93,7 @@ class ExtendsPlugin extends BasePlugin */ public function getBasename(Source $source) { - return str_replace(':', '.', basename($source->filepath)); + return str_replace(':', '.', basename($source->getResourceName())); } /* diff --git a/src/Resource/FilePlugin.php b/src/Resource/FilePlugin.php index 481c2efb..7fd8667d 100644 --- a/src/Resource/FilePlugin.php +++ b/src/Resource/FilePlugin.php @@ -10,6 +10,7 @@ namespace Smarty\Resource; +use Smarty\Smarty; use Smarty\Template; use Smarty\Template\Source; use Smarty\Exception; @@ -24,25 +25,26 @@ use Smarty\Exception; class FilePlugin extends BasePlugin { /** - * populate Source Object with meta data from Resource + * populate Source Object with metadata from Resource * * @param Source $source source object - * @param Template $_template template object + * @param Template|null $_template template object * - * @throws \Smarty\Exception + * @throws Exception */ public function populate(Source $source, Template $_template = null) { - $source->filepath = $this->buildFilepath($source, $_template); - if ($source->filepath !== false) { + + $source->uid = sha1( + $source->name . ($source->isConfig ? $source->getSmarty()->_joined_config_dir : + $source->getSmarty()->_joined_template_dir) + ); + + if ($path = $this->getFilePath($source->name, $source->getSmarty(), $source->isConfig)) { if (isset($source->getSmarty()->security_policy) && is_object($source->getSmarty()->security_policy)) { - $source->getSmarty()->security_policy->isTrustedResourceDir($source->filepath, $source->isConfig); + $source->getSmarty()->security_policy->isTrustedResourceDir($path, $source->isConfig); } $source->exists = true; - $source->uid = sha1( - $source->filepath . ($source->isConfig ? $source->getSmarty()->_joined_config_dir : - $source->getSmarty()->_joined_template_dir) - ); - $source->timestamp = filemtime($source->filepath); + $source->timestamp = filemtime($path); } else { $source->timestamp = $source->exists = false; } @@ -54,11 +56,11 @@ class FilePlugin extends BasePlugin { * @param Source $source source object */ public function populateTimestamp(Source $source) { - if (!$source->exists) { - $source->timestamp = $source->exists = is_file($source->filepath); + if (!$source->exists && $path = $this->getFilePath($source->name, $source->getSmarty(), $source->isConfig)) { + $source->timestamp = $source->exists = is_file($path); } - if ($source->exists) { - $source->timestamp = filemtime($source->filepath); + if ($source->exists && $path) { + $source->timestamp = filemtime($path); } } @@ -72,7 +74,7 @@ class FilePlugin extends BasePlugin { */ public function getContent(Source $source) { if ($source->exists) { - return file_get_contents($source->filepath); + return file_get_contents($this->getFilePath($source->getResourceName(), $source->getSmarty(), $source->isConfig())); } throw new Exception( 'Unable to read ' . ($source->isConfig ? 'config' : 'template') . @@ -88,43 +90,30 @@ class FilePlugin extends BasePlugin { * @return string resource's basename */ public function getBasename(Source $source) { - return basename($source->filepath); + return basename($source->getResourceName()); } /** * build template filepath by traversing the template_dir array * - * @param Source $source source object - * @param Template $_template template object + * @param $file + * @param Smarty $smarty + * @param bool $isConfig * * @return string fully qualified filepath - * @throws Exception */ - protected function buildFilepath(Source $source, Template $_template = null) { - $file = $source->name; + public function getFilePath($file, \Smarty\Smarty $smarty, bool $isConfig = false) { // absolute file ? if ($file[0] === '/' || $file[1] === ':') { - $file = $source->getSmarty()->_realpath($file, true); + $file = $smarty->_realpath($file, true); return is_file($file) ? $file : false; } - // go relative to a given template? - if ($file[0] === '.' && $_template && $_template->_isSubTpl() - && preg_match('#^[.]{1,2}[\\\/]#', $file) - ) { - if ($_template->parent->getSource()->type !== 'file' && $_template->parent->getSource()->type !== 'extends') { - throw new Exception("Template '{$file}' cannot be relative to template of resource type '{$_template->parent->getSource()->type}'"); - } - // normalize path - $path = - $source->getSmarty()->_realpath(dirname($_template->parent->getSource()->filepath) . DIRECTORY_SEPARATOR . $file); - // files relative to a template only get one shot - return is_file($path) ? $path : false; - } + // normalize DIRECTORY_SEPARATOR if (strpos($file, DIRECTORY_SEPARATOR === '/' ? '\\' : '/') !== false) { $file = str_replace(DIRECTORY_SEPARATOR === '/' ? '\\' : '/', DIRECTORY_SEPARATOR, $file); } - $_directories = $source->getSmarty()->getTemplateDir(null, $source->isConfig); + $_directories = $smarty->getTemplateDir(null, $isConfig); // template_dir index? if ($file[0] === '[' && preg_match('#^\[([^\]]+)\](.+)$#', $file, $fileMatch)) { $file = $fileMatch[2]; @@ -160,16 +149,32 @@ class FilePlugin extends BasePlugin { foreach ($_directories as $_directory) { $path = $_directory . $file; if (is_file($path)) { - return (strpos($path, '.' . DIRECTORY_SEPARATOR) !== false) ? $source->getSmarty()->_realpath($path) : $path; + return (strpos($path, '.' . DIRECTORY_SEPARATOR) !== false) ? $smarty->_realpath($path) : $path; } } if (!isset($_index_dirs)) { // Could be relative to cwd - $path = $source->getSmarty()->_realpath($file, true); + $path = $smarty->_realpath($file, true); if (is_file($path)) { return $path; } } return false; } + + /** + * Returns the timestamp of the resource indicated by $resourceName, or false if it doesn't exist. + * + * @param string $resourceName + * @param Smarty $smarty + * @param bool $isConfig + * + * @return false|int + */ + public function getResourceNameTimestamp(string $resourceName, \Smarty\Smarty $smarty, bool $isConfig = false) { + if ($path = $this->getFilePath($resourceName, $smarty, $isConfig)) { + return filemtime($path); + } + return false; + } } diff --git a/src/Resource/StreamPlugin.php b/src/Resource/StreamPlugin.php index c2cf8bef..91afffdc 100644 --- a/src/Resource/StreamPlugin.php +++ b/src/Resource/StreamPlugin.php @@ -34,11 +34,6 @@ class StreamPlugin extends RecompiledPlugin { * @return void */ public function populate(Source $source, Template $_template = null) { - if (strpos($source->resource, '://') !== false) { - $source->filepath = $source->resource; - } else { - $source->filepath = str_replace(':', '://', $source->resource); - } $source->uid = false; $source->content = $this->getContent($source); $source->timestamp = $source->exists = !!$source->content; @@ -52,9 +47,16 @@ class StreamPlugin extends RecompiledPlugin { * @return string template source */ public function getContent(Source $source) { + + if (strpos($source->getResourceName(), '://') !== false) { + $filepath = $source->getResourceName(); + } else { + $filepath = str_replace(':', '://', $source->getFullResourceName()); + } + $t = ''; // the availability of the stream has already been checked in Smarty\Resource\Base::fetch() - $fp = fopen($source->filepath, 'r+'); + $fp = fopen($filepath, 'r+'); if ($fp) { while (!feof($fp) && ($current_line = fgets($fp)) !== false) { $t .= $current_line; diff --git a/src/Resource/StringEval.php b/src/Resource/StringEval.php index 143af606..5c35e743 100644 --- a/src/Resource/StringEval.php +++ b/src/Resource/StringEval.php @@ -33,7 +33,7 @@ class StringEval extends RecompiledPlugin */ public function populate(\Smarty\Template\Source $source, \Smarty\Template $_template = null) { - $source->uid = $source->filepath = sha1($source->name); + $source->uid = sha1($source->name); $source->timestamp = $source->exists = true; } diff --git a/src/Resource/StringPlugin.php b/src/Resource/StringPlugin.php index a78bcc02..6b5bee4d 100644 --- a/src/Resource/StringPlugin.php +++ b/src/Resource/StringPlugin.php @@ -24,7 +24,7 @@ use Smarty\Template\Source; class StringPlugin extends BasePlugin { /** - * populate Source Object with meta data from Resource + * populate Source Object with metadata from Resource * * @param Source $source source object * @param Template $_template template object @@ -32,7 +32,7 @@ class StringPlugin extends BasePlugin { * @return void */ public function populate(Source $source, Template $_template = null) { - $source->uid = $source->filepath = sha1($source->name . $source->getSmarty()->_joined_template_dir); + $source->uid = sha1($source->name); $source->timestamp = $source->exists = true; } diff --git a/src/Runtime/InheritanceRuntime.php b/src/Runtime/InheritanceRuntime.php index 5a023d03..ffd7aae6 100644 --- a/src/Runtime/InheritanceRuntime.php +++ b/src/Runtime/InheritanceRuntime.php @@ -102,7 +102,7 @@ class InheritanceRuntime { * @throws \Exception * @throws \Smarty\Exception */ - public function endChild(Template $tpl, $template = null) { + public function endChild(Template $tpl, $template = null, ?string $currentDir = null) { --$this->inheritanceLevel; if (!$this->inheritanceLevel) { ob_end_clean(); @@ -114,7 +114,10 @@ class InheritanceRuntime { $tpl->cache_id, $tpl->compile_id, $tpl->caching ? \Smarty\Template::CACHING_NOCACHE_CODE : 0, - $tpl->cache_lifetime + $tpl->cache_lifetime, + [], + null, + $currentDir ); } } @@ -221,7 +224,7 @@ class InheritanceRuntime { $this->callBlock($block->parent, $tpl); } else { throw new Exception("inheritance: illegal '{\$smarty.block.parent}' used in child template '" . - "{$tpl->getInheritance()->sources[$block->tplIndex]->filepath}' block '{$block->name}'"); + "{$tpl->getInheritance()->sources[$block->tplIndex]->getResourceName()}' block '{$block->name}'"); } } diff --git a/src/Smarty.php b/src/Smarty.php index e7d207fe..7e3579aa 100644 --- a/src/Smarty.php +++ b/src/Smarty.php @@ -48,475 +48,465 @@ use Smarty\Smarty\Runtime\TplFunctionRuntime; /** * This is the main Smarty class */ -class Smarty extends \Smarty\TemplateBase -{ - /** - * smarty version - */ - const SMARTY_VERSION = '5.0.0'; +class Smarty extends \Smarty\TemplateBase { - /** - * define caching modes - */ - const CACHING_OFF = 0; - const CACHING_LIFETIME_CURRENT = 1; - const CACHING_LIFETIME_SAVED = 2; - /** - * define constant for clearing cache files be saved expiration dates - */ - const CLEAR_EXPIRED = -1; - /** - * define compile check modes - */ - const COMPILECHECK_OFF = 0; - const COMPILECHECK_ON = 1; - /** - * filter types - */ - const FILTER_POST = 'post'; - const FILTER_PRE = 'pre'; - const FILTER_OUTPUT = 'output'; - const FILTER_VARIABLE = 'variable'; - /** - * plugin types - */ - const PLUGIN_FUNCTION = 'function'; - const PLUGIN_BLOCK = 'block'; - const PLUGIN_COMPILER = 'compiler'; - const PLUGIN_MODIFIER = 'modifier'; - const PLUGIN_MODIFIERCOMPILER = 'modifiercompiler'; + /** + * smarty version + */ + const SMARTY_VERSION = '5.0.0'; - /** - * The character set to adhere to (defaults to "UTF-8") - */ - public static $_CHARSET = 'UTF-8'; + /** + * define caching modes + */ + const CACHING_OFF = 0; + const CACHING_LIFETIME_CURRENT = 1; + const CACHING_LIFETIME_SAVED = 2; + /** + * define constant for clearing cache files be saved expiration dates + */ + const CLEAR_EXPIRED = -1; + /** + * define compile check modes + */ + const COMPILECHECK_OFF = 0; + const COMPILECHECK_ON = 1; + /** + * filter types + */ + const FILTER_POST = 'post'; + const FILTER_PRE = 'pre'; + const FILTER_OUTPUT = 'output'; + const FILTER_VARIABLE = 'variable'; + /** + * plugin types + */ + const PLUGIN_FUNCTION = 'function'; + const PLUGIN_BLOCK = 'block'; + const PLUGIN_COMPILER = 'compiler'; + const PLUGIN_MODIFIER = 'modifier'; + const PLUGIN_MODIFIERCOMPILER = 'modifiercompiler'; - /** - * The date format to be used internally - * (accepts date() and strftime()) - */ - public static $_DATE_FORMAT = '%b %e, %Y'; + /** + * The character set to adhere to (defaults to "UTF-8") + */ + public static $_CHARSET = 'UTF-8'; - /** - * Flag denoting if PCRE should run in UTF-8 mode - */ - public static $_UTF8_MODIFIER = 'u'; + /** + * The date format to be used internally + * (accepts date() and strftime()) + */ + public static $_DATE_FORMAT = '%b %e, %Y'; - /** - * Flag denoting if operating system is windows - */ - public static $_IS_WINDOWS = false; + /** + * Flag denoting if PCRE should run in UTF-8 mode + */ + public static $_UTF8_MODIFIER = 'u'; - /** - * auto literal on delimiters with whitespace - * - * @var boolean - */ - public $auto_literal = true; + /** + * Flag denoting if operating system is windows + */ + public static $_IS_WINDOWS = false; - /** - * display error on not assigned variables - * - * @var boolean - */ - public $error_unassigned = false; + /** + * auto literal on delimiters with whitespace + * + * @var boolean + */ + public $auto_literal = true; - /** - * flag if template_dir is normalized - * - * @var bool - */ - public $_templateDirNormalized = false; + /** + * display error on not assigned variables + * + * @var boolean + */ + public $error_unassigned = false; - /** - * joined template directory string used in cache keys - * - * @var string - */ - public $_joined_template_dir = null; + /** + * flag if template_dir is normalized + * + * @var bool + */ + public $_templateDirNormalized = false; - /** - * flag if config_dir is normalized - * - * @var bool - */ - public $_configDirNormalized = false; + /** + * joined template directory string used in cache keys + * + * @var string + */ + public $_joined_template_dir = null; - /** - * joined config directory string used in cache keys - * - * @var string - */ - public $_joined_config_dir = null; + /** + * flag if config_dir is normalized + * + * @var bool + */ + public $_configDirNormalized = false; - /** - * default template handler - * - * @var callable - */ - public $default_template_handler_func = null; + /** + * joined config directory string used in cache keys + * + * @var string + */ + public $_joined_config_dir = null; - /** - * default config handler - * - * @var callable - */ - public $default_config_handler_func = null; + /** + * default template handler + * + * @var callable + */ + public $default_template_handler_func = null; - /** - * default plugin handler - * - * @var callable - */ - private $default_plugin_handler_func = null; + /** + * default config handler + * + * @var callable + */ + public $default_config_handler_func = null; - /** - * flag if template_dir is normalized - * - * @var bool - */ - public $_compileDirNormalized = false; + /** + * default plugin handler + * + * @var callable + */ + private $default_plugin_handler_func = null; - /** - * flag if template_dir is normalized - * - * @var bool - */ - public $_cacheDirNormalized = false; + /** + * flag if template_dir is normalized + * + * @var bool + */ + public $_compileDirNormalized = false; - /** - * force template compiling? - * - * @var boolean - */ - public $force_compile = false; + /** + * flag if template_dir is normalized + * + * @var bool + */ + public $_cacheDirNormalized = false; - /** - * use sub dirs for compiled/cached files? - * - * @var boolean - */ - public $use_sub_dirs = false; + /** + * force template compiling? + * + * @var boolean + */ + public $force_compile = false; - /** - * allow ambiguous resources (that are made unique by the resource handler) - * - * @var boolean - */ - private $allow_ambiguous_resources = false; + /** + * use sub dirs for compiled/cached files? + * + * @var boolean + */ + public $use_sub_dirs = false; - /** - * merge compiled includes - * - * @var boolean - */ - public $merge_compiled_includes = false; + /** + * merge compiled includes + * + * @var boolean + */ + public $merge_compiled_includes = false; - /** - * force cache file creation - * - * @var boolean - */ - public $force_cache = false; + /** + * force cache file creation + * + * @var boolean + */ + public $force_cache = false; - /** - * template left-delimiter - * - * @var string - */ - private $left_delimiter = "{"; + /** + * template left-delimiter + * + * @var string + */ + private $left_delimiter = "{"; - /** - * template right-delimiter - * - * @var string - */ - private $right_delimiter = "}"; + /** + * template right-delimiter + * + * @var string + */ + private $right_delimiter = "}"; - /** - * array of strings which shall be treated as literal by compiler - * - * @var array string - */ - public $literals = array(); + /** + * array of strings which shall be treated as literal by compiler + * + * @var array string + */ + public $literals = []; - /** - * class name - * This should be instance of \Smarty\Security. - * - * @var string - * @see \Smarty\Security - */ - public $security_class = \Smarty\Security::class; + /** + * class name + * This should be instance of \Smarty\Security. + * + * @var string + * @see \Smarty\Security + */ + public $security_class = \Smarty\Security::class; - /** - * implementation of security class - * - * @var \Smarty\Security - */ - public $security_policy = null; + /** + * implementation of security class + * + * @var \Smarty\Security + */ + public $security_policy = null; - /** - * debug mode - * Setting this to true enables the debug-console. - * - * @var boolean - */ - public $debugging = false; + /** + * debug mode + * Setting this to true enables the debug-console. + * + * @var boolean + */ + public $debugging = false; - /** - * This determines if debugging is enable-able from the browser. - * - * - * @var string - */ - public $debugging_ctrl = 'NONE'; + /** + * This determines if debugging is enable-able from the browser. + * + * + * @var string + */ + public $debugging_ctrl = 'NONE'; - /** - * Name of debugging URL-param. - * Only used when $debugging_ctrl is set to 'URL'. - * The name of the URL-parameter that activates debugging. - * - * @var string - */ - public $smarty_debug_id = 'SMARTY_DEBUG'; + /** + * Name of debugging URL-param. + * Only used when $debugging_ctrl is set to 'URL'. + * The name of the URL-parameter that activates debugging. + * + * @var string + */ + public $smarty_debug_id = 'SMARTY_DEBUG'; - /** - * Path of debug template. - * - * @var string - */ - public $debug_tpl = null; + /** + * Path of debug template. + * + * @var string + */ + public $debug_tpl = null; - /** - * When set, smarty uses this value as error_reporting-level. - * - * @var int - */ - public $error_reporting = null; + /** + * When set, smarty uses this value as error_reporting-level. + * + * @var int + */ + public $error_reporting = null; - /** - * Controls whether variables with the same name overwrite each other. - * - * @var boolean - */ - public $config_overwrite = true; + /** + * Controls whether variables with the same name overwrite each other. + * + * @var boolean + */ + public $config_overwrite = true; - /** - * Controls whether config values of on/true/yes and off/false/no get converted to boolean. - * - * @var boolean - */ - public $config_booleanize = true; + /** + * Controls whether config values of on/true/yes and off/false/no get converted to boolean. + * + * @var boolean + */ + public $config_booleanize = true; - /** - * Controls whether hidden config sections/vars are read from the file. - * - * @var boolean - */ - public $config_read_hidden = false; + /** + * Controls whether hidden config sections/vars are read from the file. + * + * @var boolean + */ + public $config_read_hidden = false; - /** - * locking concurrent compiles - * - * @var boolean - */ - public $compile_locking = true; + /** + * locking concurrent compiles + * + * @var boolean + */ + public $compile_locking = true; - /** - * Controls whether cache resources should use locking mechanism - * - * @var boolean - */ - public $cache_locking = false; + /** + * Controls whether cache resources should use locking mechanism + * + * @var boolean + */ + public $cache_locking = false; - /** - * seconds to wait for acquiring a lock before ignoring the write lock - * - * @var float - */ - public $locking_timeout = 10; + /** + * seconds to wait for acquiring a lock before ignoring the write lock + * + * @var float + */ + public $locking_timeout = 10; - /** - * resource type used if none given - * Must be a valid key of $registered_resources. - * - * @var string - */ - public $default_resource_type = 'file'; + /** + * resource type used if none given + * Must be a valid key of $registered_resources. + * + * @var string + */ + public $default_resource_type = 'file'; - /** - * cache resource - * Must be a subclass of \Smarty\Cacheresource\Base - * - * @var \Smarty\Cacheresource\Base - */ - private $cacheResource; + /** + * cache resource + * Must be a subclass of \Smarty\Cacheresource\Base + * + * @var \Smarty\Cacheresource\Base + */ + private $cacheResource; - /** - * config type - * - * @var string - */ - public $default_config_type = 'file'; + /** + * config type + * + * @var string + */ + public $default_config_type = 'file'; - /** - * check If-Modified-Since headers - * - * @var boolean - */ - public $cache_modified_check = false; + /** + * check If-Modified-Since headers + * + * @var boolean + */ + public $cache_modified_check = false; - /** - * registered plugins - * - * @var array - */ - public $registered_plugins = array(); + /** + * registered plugins + * + * @var array + */ + public $registered_plugins = []; - /** - * registered objects - * - * @var array - */ - public $registered_objects = array(); + /** + * registered objects + * + * @var array + */ + public $registered_objects = []; - /** - * registered classes - * - * @var array - */ - public $registered_classes = array(); + /** + * registered classes + * + * @var array + */ + public $registered_classes = []; - /** - * registered filters - * - * @var array - */ - public $registered_filters = array(); + /** + * registered filters + * + * @var array + */ + public $registered_filters = []; - /** - * registered resources - * - * @var array - */ - public $registered_resources = array(); + /** + * registered resources + * + * @var array + */ + public $registered_resources = []; - /** - * registered cache resources - * - * @var array - * @deprecated since 5.0 - */ - private $registered_cache_resources = array(); + /** + * registered cache resources + * + * @var array + * @deprecated since 5.0 + */ + private $registered_cache_resources = []; - /** - * default modifier - * - * @var array - */ - public $default_modifiers = array(); + /** + * default modifier + * + * @var array + */ + public $default_modifiers = []; - /** - * autoescape variable output - * - * @var boolean - */ - public $escape_html = false; + /** + * autoescape variable output + * + * @var boolean + */ + public $escape_html = false; - /** - * start time for execution time calculation - * - * @var int - */ - public $start_time = 0; + /** + * start time for execution time calculation + * + * @var int + */ + public $start_time = 0; - /** - * required by the compiler for BC - * - * @var string - */ - public $_current_file = null; + /** + * internal flag to enable parser debugging + * + * @var bool + */ + public $_parserdebug = false; - /** - * internal flag to enable parser debugging - * - * @var bool - */ - public $_parserdebug = false; + /** + * Debug object + * + * @var \Smarty\Debug + */ + public $_debug = null; - /** - * Debug object - * - * @var \Smarty\Debug - */ - public $_debug = null; + /** + * template directory + * + * @var array + */ + protected $template_dir = ['./templates/']; - /** - * template directory - * - * @var array - */ - protected $template_dir = array('./templates/'); + /** + * flags for normalized template directory entries + * + * @var array + */ + protected $_processedTemplateDir = []; - /** - * flags for normalized template directory entries - * - * @var array - */ - protected $_processedTemplateDir = array(); + /** + * config directory + * + * @var array + */ + protected $config_dir = ['./configs/']; - /** - * config directory - * - * @var array - */ - protected $config_dir = array('./configs/'); + /** + * flags for normalized template directory entries + * + * @var array + */ + protected $_processedConfigDir = []; - /** - * flags for normalized template directory entries - * - * @var array - */ - protected $_processedConfigDir = array(); + /** + * compile directory + * + * @var string + */ + protected $compile_dir = './templates_c/'; - /** - * compile directory - * - * @var string - */ - protected $compile_dir = './templates_c/'; + /** + * cache directory + * + * @var string + */ + protected $cache_dir = './cache/'; - /** - * cache directory - * - * @var string - */ - protected $cache_dir = './cache/'; - - /** - * PHP7 Compatibility mode - * @var bool - */ - private $isMutingUndefinedOrNullWarnings = false; + /** + * PHP7 Compatibility mode + * + * @var bool + */ + private $isMutingUndefinedOrNullWarnings = false; /** * Cache of loaded resource handlers. + * * @var array */ public $_resource_handlers = []; /** * Cache of loaded cacheresource handlers. + * * @var array */ public $_cacheresource_handlers = []; /** * List of extensions + * * @var ExtensionInterface[] */ private $extensions = []; @@ -526,19 +516,18 @@ class Smarty extends \Smarty\TemplateBase private $BCPluginsAdapter; /** - * Initialize new Smarty object - */ - public function __construct() - { + * Initialize new Smarty object + */ + public function __construct() { + + $this->start_time = microtime(true); + // Check if we're running on Windows + \Smarty\Smarty::$_IS_WINDOWS = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; + // let PCRE (preg_*) treat strings as ISO-8859-1 if we're not dealing with UTF-8 + if (\Smarty\Smarty::$_CHARSET !== 'UTF-8') { + \Smarty\Smarty::$_UTF8_MODIFIER = ''; + } - $this->start_time = microtime(true); - // Check if we're running on Windows - \Smarty\Smarty::$_IS_WINDOWS = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; - // let PCRE (preg_*) treat strings as ISO-8859-1 if we're not dealing with UTF-8 - if (\Smarty\Smarty::$_CHARSET !== 'UTF-8') { - \Smarty\Smarty::$_UTF8_MODIFIER = ''; - } - $this->BCPluginsAdapter = new BCPluginsAdapter($this); $this->extensions[] = new CoreExtension(); @@ -546,7 +535,7 @@ class Smarty extends \Smarty\TemplateBase $this->extensions[] = $this->BCPluginsAdapter; $this->cacheResource = new File(); - } + } /** * Load an additional extension. @@ -568,174 +557,162 @@ class Smarty extends \Smarty\TemplateBase return $this->extensions; } + /** + * Check if a template resource exists + * + * @param string $resource_name template name + * + * @return bool status + * @throws \Smarty\Exception + */ + public function templateExists($resource_name) { + // create source object + $source = Template\Source::load(null, $this, $resource_name); + return $source->exists; + } + /** + * Loads security class and enables security + * + * @param string|\Smarty\Security $security_class if a string is used, it must be class-name + * + * @return Smarty current Smarty instance for chaining + * @throws \Smarty\Exception + */ + public function enableSecurity($security_class = null) { + \Smarty\Security::enableSecurity($this, $security_class); + return $this; + } - /** - * Check if a template resource exists - * - * @param string $resource_name template name - * - * @return bool status - * @throws \Smarty\Exception - */ - public function templateExists($resource_name) - { - // create source object - $source = Template\Source::load(null, $this, $resource_name); - return $source->exists; - } + /** + * Disable security + * + * @return Smarty current Smarty instance for chaining + */ + public function disableSecurity() { + $this->security_policy = null; + return $this; + } - /** - * Loads security class and enables security - * - * @param string|\Smarty\Security $security_class if a string is used, it must be class-name - * - * @return Smarty current Smarty instance for chaining - * @throws \Smarty\Exception - */ - public function enableSecurity($security_class = null) - { - \Smarty\Security::enableSecurity($this, $security_class); - return $this; - } + /** + * Add template directory(s) + * + * @param string|array $template_dir directory(s) of template sources + * @param string $key of the array element to assign the template dir to + * @param bool $isConfig true for config_dir + * + * @return Smarty current Smarty instance for chaining + */ + public function addTemplateDir($template_dir, $key = null, $isConfig = false) { + if ($isConfig) { + $processed = &$this->_processedConfigDir; + $dir = &$this->config_dir; + $this->_configDirNormalized = false; + } else { + $processed = &$this->_processedTemplateDir; + $dir = &$this->template_dir; + $this->_templateDirNormalized = false; + } + if (is_array($template_dir)) { + foreach ($template_dir as $k => $v) { + if (is_int($k)) { + // indexes are not merged but appended + $dir[] = $v; + } else { + // string indexes are overridden + $dir[$k] = $v; + unset($processed[$key]); + } + } + } else { + if ($key !== null) { + // override directory at specified index + $dir[$key] = $template_dir; + unset($processed[$key]); + } else { + // append new directory + $dir[] = $template_dir; + } + } + return $this; + } - /** - * Disable security - * - * @return Smarty current Smarty instance for chaining - */ - public function disableSecurity() - { - $this->security_policy = null; - return $this; - } + /** + * Get template directories + * + * @param mixed $index index of directory to get, null to get all + * @param bool $isConfig true for config_dir + * + * @return array|string list of template directories, or directory of $index + */ + public function getTemplateDir($index = null, $isConfig = false) { + if ($isConfig) { + $dir = &$this->config_dir; + } else { + $dir = &$this->template_dir; + } + if ($isConfig ? !$this->_configDirNormalized : !$this->_templateDirNormalized) { + $this->_normalizeTemplateConfig($isConfig); + } + if ($index !== null) { + return isset($dir[$index]) ? $dir[$index] : null; + } + return $dir; + } - /** - * Add template directory(s) - * - * @param string|array $template_dir directory(s) of template sources - * @param string $key of the array element to assign the template dir to - * @param bool $isConfig true for config_dir - * - * @return Smarty current Smarty instance for chaining - */ - public function addTemplateDir($template_dir, $key = null, $isConfig = false) - { - if ($isConfig) { - $processed = &$this->_processedConfigDir; - $dir = &$this->config_dir; - $this->_configDirNormalized = false; - } else { - $processed = &$this->_processedTemplateDir; - $dir = &$this->template_dir; - $this->_templateDirNormalized = false; - } - if (is_array($template_dir)) { - foreach ($template_dir as $k => $v) { - if (is_int($k)) { - // indexes are not merged but appended - $dir[] = $v; - } else { - // string indexes are overridden - $dir[ $k ] = $v; - unset($processed[ $key ]); - } - } - } else { - if ($key !== null) { - // override directory at specified index - $dir[ $key ] = $template_dir; - unset($processed[ $key ]); - } else { - // append new directory - $dir[] = $template_dir; - } - } - return $this; - } + /** + * Set template directory + * + * @param string|array $template_dir directory(s) of template sources + * @param bool $isConfig true for config_dir + * + * @return Smarty current Smarty instance for chaining + */ + public function setTemplateDir($template_dir, $isConfig = false) { + if ($isConfig) { + $this->config_dir = []; + $this->_processedConfigDir = []; + } else { + $this->template_dir = []; + $this->_processedTemplateDir = []; + } + $this->addTemplateDir($template_dir, null, $isConfig); + return $this; + } - /** - * Get template directories - * - * @param mixed $index index of directory to get, null to get all - * @param bool $isConfig true for config_dir - * - * @return array|string list of template directories, or directory of $index - */ - public function getTemplateDir($index = null, $isConfig = false) - { - if ($isConfig) { - $dir = &$this->config_dir; - } else { - $dir = &$this->template_dir; - } - if ($isConfig ? !$this->_configDirNormalized : !$this->_templateDirNormalized) { - $this->_normalizeTemplateConfig($isConfig); - } - if ($index !== null) { - return isset($dir[ $index ]) ? $dir[ $index ] : null; - } - return $dir; - } + /** + * Add config directory(s) + * + * @param string|array $config_dir directory(s) of config sources + * @param mixed $key key of the array element to assign the config dir to + * + * @return Smarty current Smarty instance for chaining + */ + public function addConfigDir($config_dir, $key = null) { + return $this->addTemplateDir($config_dir, $key, true); + } - /** - * Set template directory - * - * @param string|array $template_dir directory(s) of template sources - * @param bool $isConfig true for config_dir - * - * @return Smarty current Smarty instance for chaining - */ - public function setTemplateDir($template_dir, $isConfig = false) - { - if ($isConfig) { - $this->config_dir = array(); - $this->_processedConfigDir = array(); - } else { - $this->template_dir = array(); - $this->_processedTemplateDir = array(); - } - $this->addTemplateDir($template_dir, null, $isConfig); - return $this; - } - - /** - * Add config directory(s) - * - * @param string|array $config_dir directory(s) of config sources - * @param mixed $key key of the array element to assign the config dir to - * - * @return Smarty current Smarty instance for chaining - */ - public function addConfigDir($config_dir, $key = null) - { - return $this->addTemplateDir($config_dir, $key, true); - } - - /** - * Get config directory - * - * @param mixed $index index of directory to get, null to get all - * - * @return array configuration directory - */ - public function getConfigDir($index = null) - { - return $this->getTemplateDir($index, true); - } - - /** - * Set config directory - * - * @param $config_dir - * - * @return Smarty current Smarty instance for chaining - */ - public function setConfigDir($config_dir) - { - return $this->setTemplateDir($config_dir, true); - } + /** + * Get config directory + * + * @param mixed $index index of directory to get, null to get all + * + * @return array configuration directory + */ + public function getConfigDir($index = null) { + return $this->getTemplateDir($index, true); + } + /** + * Set config directory + * + * @param $config_dir + * + * @return Smarty current Smarty instance for chaining + */ + public function setConfigDir($config_dir) { + return $this->setTemplateDir($config_dir, true); + } /** * Registers plugin to be used in templates @@ -804,26 +781,25 @@ class Smarty extends \Smarty\TemplateBase } /** - * Adds directory of plugin files - * - * @param null|array|string $plugins_dir - * - * @return Smarty current Smarty instance for chaining - * @deprecated since 5.0 - */ - public function addPluginsDir($plugins_dir) - { - trigger_error('Using Smarty::addPluginsDir() to load plugins is deprecated and will be ' . - 'removed in a future release. Use Smarty::addExtension() to add an extension or Smarty::registerPlugin to ' . - 'quickly register a plugin using a callback function.', E_USER_DEPRECATED); + * Adds directory of plugin files + * + * @param null|array|string $plugins_dir + * + * @return Smarty current Smarty instance for chaining + * @deprecated since 5.0 + */ + public function addPluginsDir($plugins_dir) { + trigger_error('Using Smarty::addPluginsDir() to load plugins is deprecated and will be ' . + 'removed in a future release. Use Smarty::addExtension() to add an extension or Smarty::registerPlugin to ' . + 'quickly register a plugin using a callback function.', E_USER_DEPRECATED); - foreach ((array) $plugins_dir as $v) { + foreach ((array)$plugins_dir as $v) { $path = $this->_realpath(rtrim($v ?? '', '/\\') . DIRECTORY_SEPARATOR, true); $this->BCPluginsAdapter->loadPluginsFromDir($path); } - return $this; - } + return $this; + } /** * Get plugin directories @@ -831,27 +807,24 @@ class Smarty extends \Smarty\TemplateBase * @return array list of plugin directories * @deprecated since 5.0 */ - public function getPluginsDir() - { + public function getPluginsDir() { trigger_error('Using Smarty::getPluginsDir() is deprecated and will be ' . 'removed in a future release. It will always return an empty array.', E_USER_DEPRECATED); return []; } - /** - * Set plugins directory - * - * @param string|array $plugins_dir directory(s) of plugins - * - * @return Smarty current Smarty instance for chaining + * Set plugins directory + * + * @param string|array $plugins_dir directory(s) of plugins + * + * @return Smarty current Smarty instance for chaining * @deprecated since 5.0 - */ - public function setPluginsDir($plugins_dir) - { - trigger_error('Using Smarty::getPluginsDir() is deprecated and will be ' . - 'removed in a future release. For now, it will remove the DefaultExtension from the extensions list and ' . - 'proceed to call Smartyy::addPluginsDir..', E_USER_DEPRECATED); + */ + public function setPluginsDir($plugins_dir) { + trigger_error('Using Smarty::getPluginsDir() is deprecated and will be ' . + 'removed in a future release. For now, it will remove the DefaultExtension from the extensions list and ' . + 'proceed to call Smartyy::addPluginsDir..', E_USER_DEPRECATED); $this->extensions = array_filter( $this->extensions, @@ -861,7 +834,7 @@ class Smarty extends \Smarty\TemplateBase ); return $this->addPluginsDir($plugins_dir); - } + } /** * Registers a default plugin handler @@ -890,468 +863,387 @@ class Smarty extends \Smarty\TemplateBase return $this; } + /** + * Get compiled directory + * + * @return string path to compiled templates + */ + public function getCompileDir() { + if (!$this->_compileDirNormalized) { + $this->_normalizeDir('compile_dir', $this->compile_dir); + $this->_compileDirNormalized = true; + } + return $this->compile_dir; + } - /** - * Get compiled directory - * - * @return string path to compiled templates - */ - public function getCompileDir() - { - if (!$this->_compileDirNormalized) { - $this->_normalizeDir('compile_dir', $this->compile_dir); - $this->_compileDirNormalized = true; - } - return $this->compile_dir; - } + /** + * + * @param string $compile_dir directory to store compiled templates in + * + * @return Smarty current Smarty instance for chaining + */ + public function setCompileDir($compile_dir) { + $this->_normalizeDir('compile_dir', $compile_dir); + $this->_compileDirNormalized = true; + return $this; + } - /** - * - * @param string $compile_dir directory to store compiled templates in - * - * @return Smarty current Smarty instance for chaining - */ - public function setCompileDir($compile_dir) - { - $this->_normalizeDir('compile_dir', $compile_dir); - $this->_compileDirNormalized = true; - return $this; - } + /** + * Get cache directory + * + * @return string path of cache directory + */ + public function getCacheDir() { + if (!$this->_cacheDirNormalized) { + $this->_normalizeDir('cache_dir', $this->cache_dir); + $this->_cacheDirNormalized = true; + } + return $this->cache_dir; + } - /** - * Get cache directory - * - * @return string path of cache directory - */ - public function getCacheDir() - { - if (!$this->_cacheDirNormalized) { - $this->_normalizeDir('cache_dir', $this->cache_dir); - $this->_cacheDirNormalized = true; - } - return $this->cache_dir; - } - - /** - * Set cache directory - * - * @param string $cache_dir directory to store cached templates in - * - * @return Smarty current Smarty instance for chaining - */ - public function setCacheDir($cache_dir) - { - $this->_normalizeDir('cache_dir', $cache_dir); - $this->_cacheDirNormalized = true; - return $this; - } + /** + * Set cache directory + * + * @param string $cache_dir directory to store cached templates in + * + * @return Smarty current Smarty instance for chaining + */ + public function setCacheDir($cache_dir) { + $this->_normalizeDir('cache_dir', $cache_dir); + $this->_cacheDirNormalized = true; + return $this; + } private $templates = []; /** * Creates a template object * - * @param Template|null $template_name + * @param string $template_name * @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 null $parent next higher level of Smarty variables - * @param null $caching - * @param null $cache_lifetime - * @param string|null $baseFilePath - * @param bool $isConfig * * @return Template template object * @throws Exception */ - public function createTemplate($template_name, $cache_id = null, $compile_id = null, $parent = null, $caching = null, - $cache_lifetime = null, string $baseFilePath = null, bool $isConfig = false) - { + public function createTemplate($template_name, $cache_id = null, $compile_id = null, $parent = null): Template { - $data = null; + $data = []; // Shuffle params for backward compatibility: if 2nd param is an object, it's the parent if (is_object($cache_id)) { - $parent = $cache_id; - $cache_id = null; - } - - // Shuffle params for backward compatibility: if 2nd param is an array, it's data - if (is_array($cache_id)) { - $data = $cache_id; - $cache_id = null; - } - - if (!$this->_templateDirNormalized) { - $this->_normalizeTemplateConfig(false); - } - - $_templateId = $this->generateUniqueTemplateId($template_name, $cache_id, $compile_id, $caching, $baseFilePath); - - if (!isset($this->templates[$_templateId])) { - $newTemplate = new Template($template_name, $this, $parent ?: $this, $cache_id, $compile_id, $caching, $isConfig); - $newTemplate->templateId = $_templateId; // @TODO this could go in constructor ^? - $this->templates[$_templateId] = $newTemplate; - } - - $tpl = clone $this->templates[$_templateId]; - - // If $this->allow_ambiguous_resources, the context of the section is different each time - if ($this->allow_ambiguous_resources || $tpl->getParent() !== ($parent ?: $this)) { - $tpl->setParent($parent ?: $this); + $parent = $cache_id; + $cache_id = null; } - if ($cache_lifetime) { - $tpl->setCacheLifetime($cache_lifetime); + // Shuffle params for backward compatibility: if 2nd param is an array, it's data + if (is_array($cache_id)) { + $data = $cache_id; + $cache_id = null; } - // fill data if present - if (!empty($data) && is_array($data)) { - // set up variable values - foreach ($data as $_key => $_val) { - $tpl->assign($_key, $_val); - } - } - - $tpl->tplFunctions = array_merge($parent->tplFunctions ?? [], $tpl->tplFunctions ?? []); - - if (!$this->debugging && $this->debugging_ctrl === 'URL') { - $tpl->getSmarty()->getDebug()->debugUrl($tpl->getSmarty()); - } - return $tpl; - } + return $this->doCreateTemplate($template_name, $cache_id, $compile_id, $parent, null, null, false, $data); + } /** * Get unique template id * - * @param string $template_name + * @param string $resource_name * @param null|mixed $cache_id * @param null|mixed $compile_id * @param null $caching - * @param string|null $baseFilePath * * @return string */ - private function generateUniqueTemplateId( - $template_name, - $cache_id = null, - $compile_id = null, - $caching = null, - string $baseFilePath = null - ): string { + private function generateUniqueTemplateId( + $resource_name, + $cache_id = null, + $compile_id = null, + $caching = null + ): string { // defaults for optional params - $cache_id = $cache_id ?? $this->cache_id; - $compile_id = $compile_id ?? $this->compile_id; - $caching = (int) $caching ?? $this->caching; + $cache_id = $cache_id ?? $this->cache_id; + $compile_id = $compile_id ?? $this->compile_id; + $caching = (int)$caching ?? $this->caching; - if (strpos($template_name, ':') === false) { - $template_name = "{$this->default_resource_type}:{$template_name}"; - } + // Add default resource type to resource name if it is missing + if (strpos($resource_name, ':') === false) { + $resource_name = "{$this->default_resource_type}:{$resource_name}"; + } - $id_parts = []; - - [$name, $type] = BasePlugin::parseResourceName($template_name, $this->default_resource_type); - $nameIsDotted = !empty($name) && $name[0] === '.' && ($name[1] === '.' || $name[1] === '/'); - - $id_parts[] = $type; - $id_parts[] = $this->getSmarty()->_joined_template_dir; - - // handle relative template names - if ($baseFilePath && $nameIsDotted) { - // go relative to a given template? - $id_parts[] = $this->_realpath($baseFilePath); - } - - $id_parts[] = $name; - $id_parts[] = (string) $cache_id; - $id_parts[] = (string) $compile_id; - $id_parts[] = (string) $caching; - - $_templateId = implode('#', $id_parts); + $_templateId = $resource_name . '#' . $cache_id . '#' . $compile_id . '#' . $caching; // hash very long IDs to prevent problems with filename length - // do not hash shorter IDs so they remain recognizable - if (strlen($_templateId) > 150) { - $_templateId = sha1($_templateId); - } - return $_templateId; - } + // do not hash shorter IDs, so they remain recognizable + if (strlen($_templateId) > 150) { + $_templateId = sha1($_templateId); + } - /** - * Normalize path - * - remove /./ and /../ - * - make it absolute if required - * - * @param string $path file path - * @param bool $realpath if true - convert to absolute - * false - convert to relative - * null - keep as it is but - * remove /./ /../ - * - * @return string - */ - public function _realpath($path, $realpath = null) - { - $nds = array('/' => '\\', '\\' => '/'); - preg_match( - '%^(?(?:[[:alpha:]]:[\\\\/]|/|[\\\\]{2}[[:alpha:]]+|[[:print:]]{2,}:[/]{2}|[\\\\])?)(?(.*))$%u', - $path, - $parts - ); - $path = $parts[ 'path' ]; - if ($parts[ 'root' ] === '\\') { - $parts[ 'root' ] = substr(getcwd(), 0, 2) . $parts[ 'root' ]; - } else { - if ($realpath !== null && !$parts[ 'root' ]) { - $path = getcwd() . DIRECTORY_SEPARATOR . $path; - } - } - // normalize DIRECTORY_SEPARATOR - $path = str_replace($nds[ DIRECTORY_SEPARATOR ], DIRECTORY_SEPARATOR, $path); - $parts[ 'root' ] = str_replace($nds[ DIRECTORY_SEPARATOR ], DIRECTORY_SEPARATOR, $parts[ 'root' ]); - do { - $path = preg_replace( - array('#[\\\\/]{2}#', '#[\\\\/][.][\\\\/]#', '#[\\\\/]([^\\\\/.]+)[\\\\/][.][.][\\\\/]#'), - DIRECTORY_SEPARATOR, - $path, - -1, - $count - ); - } while ($count > 0); - return $realpath !== false ? $parts[ 'root' ] . $path : str_ireplace(getcwd(), '.', $parts[ 'root' ] . $path); - } + return $_templateId; + } - /** - * @param boolean $use_sub_dirs - */ - public function setUseSubDirs($use_sub_dirs) - { - $this->use_sub_dirs = $use_sub_dirs; - } + /** + * Normalize path + * - remove /./ and /../ + * - make it absolute if required + * + * @param string $path file path + * @param bool $realpath if true - convert to absolute + * false - convert to relative + * null - keep as it is but + * remove /./ /../ + * + * @return string + */ + public function _realpath($path, $realpath = null) { + $nds = ['/' => '\\', '\\' => '/']; + preg_match( + '%^(?(?:[[:alpha:]]:[\\\\/]|/|[\\\\]{2}[[:alpha:]]+|[[:print:]]{2,}:[/]{2}|[\\\\])?)(?(.*))$%u', + $path, + $parts + ); + $path = $parts['path']; + if ($parts['root'] === '\\') { + $parts['root'] = substr(getcwd(), 0, 2) . $parts['root']; + } else { + if ($realpath !== null && !$parts['root']) { + $path = getcwd() . DIRECTORY_SEPARATOR . $path; + } + } + // normalize DIRECTORY_SEPARATOR + $path = str_replace($nds[DIRECTORY_SEPARATOR], DIRECTORY_SEPARATOR, $path); + $parts['root'] = str_replace($nds[DIRECTORY_SEPARATOR], DIRECTORY_SEPARATOR, $parts['root']); + do { + $path = preg_replace( + ['#[\\\\/]{2}#', '#[\\\\/][.][\\\\/]#', '#[\\\\/]([^\\\\/.]+)[\\\\/][.][.][\\\\/]#'], + DIRECTORY_SEPARATOR, + $path, + -1, + $count + ); + } while ($count > 0); + return $realpath !== false ? $parts['root'] . $path : str_ireplace(getcwd(), '.', $parts['root'] . $path); + } - /** - * @param int $error_reporting - */ - public function setErrorReporting($error_reporting) - { - $this->error_reporting = $error_reporting; - } + /** + * @param boolean $use_sub_dirs + */ + public function setUseSubDirs($use_sub_dirs) { + $this->use_sub_dirs = $use_sub_dirs; + } - /** - * @param boolean $escape_html - */ - public function setEscapeHtml($escape_html) - { - $this->escape_html = $escape_html; - } + /** + * @param int $error_reporting + */ + public function setErrorReporting($error_reporting) { + $this->error_reporting = $error_reporting; + } - /** - * Return auto_literal flag - * - * @return boolean - */ - public function getAutoLiteral() - { - return $this->auto_literal; - } + /** + * @param boolean $escape_html + */ + public function setEscapeHtml($escape_html) { + $this->escape_html = $escape_html; + } - /** - * Set auto_literal flag - * - * @param boolean $auto_literal - */ - public function setAutoLiteral($auto_literal = true) - { - $this->auto_literal = $auto_literal; - } + /** + * Return auto_literal flag + * + * @return boolean + */ + public function getAutoLiteral() { + return $this->auto_literal; + } - /** - * @param boolean $force_compile - */ - public function setForceCompile($force_compile) - { - $this->force_compile = $force_compile; - } + /** + * Set auto_literal flag + * + * @param boolean $auto_literal + */ + public function setAutoLiteral($auto_literal = true) { + $this->auto_literal = $auto_literal; + } - /** - * @param boolean $merge_compiled_includes - */ - public function setMergeCompiledIncludes($merge_compiled_includes) - { - $this->merge_compiled_includes = $merge_compiled_includes; - } + /** + * @param boolean $force_compile + */ + public function setForceCompile($force_compile) { + $this->force_compile = $force_compile; + } - /** - * Get left delimiter - * - * @return string - */ - public function getLeftDelimiter() - { - return $this->left_delimiter; - } + /** + * @param boolean $merge_compiled_includes + */ + public function setMergeCompiledIncludes($merge_compiled_includes) { + $this->merge_compiled_includes = $merge_compiled_includes; + } - /** - * Set left delimiter - * - * @param string $left_delimiter - */ - public function setLeftDelimiter($left_delimiter) - { - $this->left_delimiter = $left_delimiter; - } + /** + * Get left delimiter + * + * @return string + */ + public function getLeftDelimiter() { + return $this->left_delimiter; + } - /** - * Get right delimiter - * - * @return string $right_delimiter - */ - public function getRightDelimiter() - { - return $this->right_delimiter; - } + /** + * Set left delimiter + * + * @param string $left_delimiter + */ + public function setLeftDelimiter($left_delimiter) { + $this->left_delimiter = $left_delimiter; + } - /** - * Set right delimiter - * - * @param string - */ - public function setRightDelimiter($right_delimiter) - { - $this->right_delimiter = $right_delimiter; - } + /** + * Get right delimiter + * + * @return string $right_delimiter + */ + public function getRightDelimiter() { + return $this->right_delimiter; + } - /** - * @param boolean $debugging - */ - public function setDebugging($debugging) - { - $this->debugging = $debugging; - } + /** + * Set right delimiter + * + * @param string + */ + public function setRightDelimiter($right_delimiter) { + $this->right_delimiter = $right_delimiter; + } - /** - * @param boolean $config_overwrite - */ - public function setConfigOverwrite($config_overwrite) - { - $this->config_overwrite = $config_overwrite; - } + /** + * @param boolean $debugging + */ + public function setDebugging($debugging) { + $this->debugging = $debugging; + } - /** - * @param boolean $config_booleanize - */ - public function setConfigBooleanize($config_booleanize) - { - $this->config_booleanize = $config_booleanize; - } + /** + * @param boolean $config_overwrite + */ + public function setConfigOverwrite($config_overwrite) { + $this->config_overwrite = $config_overwrite; + } - /** - * @param boolean $config_read_hidden - */ - public function setConfigReadHidden($config_read_hidden) - { - $this->config_read_hidden = $config_read_hidden; - } + /** + * @param boolean $config_booleanize + */ + public function setConfigBooleanize($config_booleanize) { + $this->config_booleanize = $config_booleanize; + } - /** - * @param boolean $compile_locking - */ - public function setCompileLocking($compile_locking) - { - $this->compile_locking = $compile_locking; - } + /** + * @param boolean $config_read_hidden + */ + public function setConfigReadHidden($config_read_hidden) { + $this->config_read_hidden = $config_read_hidden; + } - /** - * @param string $default_resource_type - */ - public function setDefaultResourceType($default_resource_type) - { - $this->default_resource_type = $default_resource_type; - } + /** + * @param boolean $compile_locking + */ + public function setCompileLocking($compile_locking) { + $this->compile_locking = $compile_locking; + } - /** - * Test install - * - * @param null $errors - */ - public function testInstall(&$errors = null) - { - \Smarty\TestInstall::testInstall($this, $errors); - } + /** + * @param string $default_resource_type + */ + public function setDefaultResourceType($default_resource_type) { + $this->default_resource_type = $default_resource_type; + } - /** - * Get Smarty object - * // @TODO this is silly, remove? - * @return Smarty - */ - public function getSmarty() - { - return $this; - } + /** + * Test install + * + * @param null $errors + */ + public function testInstall(&$errors = null) { + \Smarty\TestInstall::testInstall($this, $errors); + } - /** - * Normalize and set directory string - * - * @param string $dirName cache_dir or compile_dir - * @param string $dir filepath of folder - */ - private function _normalizeDir($dirName, $dir) - { - $this->{$dirName} = $this->_realpath(rtrim($dir ?? '', "/\\") . DIRECTORY_SEPARATOR, true); - } + /** + * Get Smarty object + * + * @return Smarty + */ + public function getSmarty() { + return $this; + } - /** - * Normalize template_dir or config_dir - * - * @param bool $isConfig true for config_dir - */ - private function _normalizeTemplateConfig($isConfig) - { - if ($isConfig) { - $processed = &$this->_processedConfigDir; - $dir = &$this->config_dir; - } else { - $processed = &$this->_processedTemplateDir; - $dir = &$this->template_dir; - } - if (!is_array($dir)) { - $dir = (array)$dir; - } - foreach ($dir as $k => $v) { - if (!isset($processed[ $k ])) { - $dir[ $k ] = $v = $this->_realpath(rtrim($v ?? '', "/\\") . DIRECTORY_SEPARATOR, true); - $processed[ $k ] = true; - } - } - $isConfig ? $this->_configDirNormalized = true : $this->_templateDirNormalized = true; - $isConfig ? $this->_joined_config_dir = join('#', $this->config_dir) : - $this->_joined_template_dir = join('#', $this->template_dir); - } + /** + * Normalize and set directory string + * + * @param string $dirName cache_dir or compile_dir + * @param string $dir filepath of folder + */ + private function _normalizeDir($dirName, $dir) { + $this->{$dirName} = $this->_realpath(rtrim($dir ?? '', "/\\") . DIRECTORY_SEPARATOR, true); + } - /** - * Mutes errors for "undefined index", "undefined array key" and "trying to read property of null". - * - * @void - */ - public function muteUndefinedOrNullWarnings(): void { - $this->isMutingUndefinedOrNullWarnings = true; - } + /** + * Normalize template_dir or config_dir + * + * @param bool $isConfig true for config_dir + */ + private function _normalizeTemplateConfig($isConfig) { + if ($isConfig) { + $processed = &$this->_processedConfigDir; + $dir = &$this->config_dir; + } else { + $processed = &$this->_processedTemplateDir; + $dir = &$this->template_dir; + } + if (!is_array($dir)) { + $dir = (array)$dir; + } + foreach ($dir as $k => $v) { + if (!isset($processed[$k])) { + $dir[$k] = $this->_realpath(rtrim($v ?? '', "/\\") . DIRECTORY_SEPARATOR, true); + $processed[$k] = true; + } + } - /** - * Indicates if Smarty will mute errors for "undefined index", "undefined array key" and "trying to read property of null". - * @return bool - */ - public function isMutingUndefinedOrNullWarnings(): bool { - return $this->isMutingUndefinedOrNullWarnings; - } + if ($isConfig) { + $this->_configDirNormalized = true; + $this->_joined_config_dir = join('#', $this->config_dir); + } else { + $this->_templateDirNormalized = true; + $this->_joined_template_dir = join('#', $this->template_dir); + } + + } + + /** + * Mutes errors for "undefined index", "undefined array key" and "trying to read property of null". + * + * @void + */ + public function muteUndefinedOrNullWarnings(): void { + $this->isMutingUndefinedOrNullWarnings = true; + } + + /** + * Indicates if Smarty will mute errors for "undefined index", "undefined array key" and "trying to read property of null". + * + * @return bool + */ + public function isMutingUndefinedOrNullWarnings(): bool { + return $this->isMutingUndefinedOrNullWarnings; + } /** * Empty cache for a specific template * - * @param string $template_name template name - * @param string $cache_id cache id - * @param string $compile_id compile id - * @param integer $exp_time expiration time - * @param string $type resource type + * @param string $template_name template name + * @param string $cache_id cache id + * @param string $compile_id compile id + * @param integer $exp_time expiration time + * @param string $type resource type * * @return int number of cache files deleted * @throws \Smarty\Exception @@ -1360,10 +1252,10 @@ class Smarty extends \Smarty\TemplateBase * @api Smarty::clearCache() */ public function clearCache( - $template_name, - $cache_id = null, - $compile_id = null, - $exp_time = null + $template_name, + $cache_id = null, + $compile_id = null, + $exp_time = null ) { return $this->getCacheResource()->clear($this, $template_name, $cache_id, $compile_id, $exp_time); } @@ -1371,34 +1263,32 @@ class Smarty extends \Smarty\TemplateBase /** * Empty cache folder * - * @api Smarty::clearAllCache() - * @link https://www.smarty.net/docs/en/api.clear.all.cache.tpl - * * @param integer $exp_time expiration time - * @param string $type resource type + * @param string $type resource type * * @return int number of cache files deleted + * @link https://www.smarty.net/docs/en/api.clear.all.cache.tpl + * + * @api Smarty::clearAllCache() */ - public function clearAllCache($exp_time = null) - { + public function clearAllCache($exp_time = null) { return $this->getCacheResource()->clearAll($this, $exp_time); } /** * Delete compiled template file * - * @param string $resource_name template name - * @param string $compile_id compile id - * @param integer $exp_time expiration time + * @param string $resource_name template name + * @param string $compile_id compile id + * @param integer $exp_time expiration time * * @return int number of template files deleted * @throws \Smarty\Exception - *@link https://www.smarty.net/docs/en/api.clear.compiled.template.tpl + * @link https://www.smarty.net/docs/en/api.clear.compiled.template.tpl * * @api Smarty::clearCompiledTemplate() */ - public function clearCompiledTemplate($resource_name = null, $compile_id = null, $exp_time = null) - { + public function clearCompiledTemplate($resource_name = null, $compile_id = null, $exp_time = null) { $_compile_dir = $this->getCompileDir(); if ($_compile_dir === '/') { //We should never want to delete this! return 0; @@ -1409,7 +1299,7 @@ class Smarty extends \Smarty\TemplateBase $_save_stat = $this->caching; $this->caching = \Smarty\Smarty::CACHING_OFF; /* @var Template $tpl */ - $tpl = $this->createTemplate($resource_name); + $tpl = $this->doCreateTemplate($resource_name); $this->caching = $_save_stat; if (!$tpl->getSource()->handler->recompiled && $tpl->getSource()->exists) { $_resource_part_1 = basename(str_replace('^', DIRECTORY_SEPARATOR, $tpl->getCompiled()->filepath)); @@ -1453,15 +1343,15 @@ class Smarty extends \Smarty\TemplateBase } $unlink = false; if ((!isset($_compile_id) || - (isset($_filepath[ $_compile_id_part_length ]) && + (isset($_filepath[$_compile_id_part_length]) && $a = !strncmp($_filepath, $_compile_id_part, $_compile_id_part_length))) - && (!isset($resource_name) || (isset($_filepath[ $_resource_part_1_length ]) + && (!isset($resource_name) || (isset($_filepath[$_resource_part_1_length]) && substr_compare( $_filepath, $_resource_part_1, -$_resource_part_1_length, $_resource_part_1_length - ) === 0) || (isset($_filepath[ $_resource_part_2_length ]) + ) === 0) || (isset($_filepath[$_resource_part_2_length]) && substr_compare( $_filepath, $_resource_part_2, @@ -1495,20 +1385,20 @@ class Smarty extends \Smarty\TemplateBase /** * Compile all template files * - * @api Smarty::compileAllTemplates() - * - * @param string $extension file extension - * @param bool $force_compile force all to recompile - * @param int $time_limit - * @param int $max_errors + * @param string $extension file extension + * @param bool $force_compile force all to recompile + * @param int $time_limit + * @param int $max_errors * * @return integer number of template files recompiled + * @api Smarty::compileAllTemplates() + * */ public function compileAllTemplates( - $extension = '.tpl', - $force_compile = false, - $time_limit = 0, - $max_errors = null + $extension = '.tpl', + $force_compile = false, + $time_limit = 0, + $max_errors = null ) { return $this->compileAll($extension, $force_compile, $time_limit, $max_errors); } @@ -1516,20 +1406,20 @@ class Smarty extends \Smarty\TemplateBase /** * Compile all config files * - * @api Smarty::compileAllConfig() - * - * @param string $extension file extension - * @param bool $force_compile force all to recompile - * @param int $time_limit - * @param int $max_errors + * @param string $extension file extension + * @param bool $force_compile force all to recompile + * @param int $time_limit + * @param int $max_errors * * @return int number of template files recompiled + * @api Smarty::compileAllConfig() + * */ public function compileAllConfig( - $extension = '.conf', - $force_compile = false, - $time_limit = 0, - $max_errors = null + $extension = '.conf', + $force_compile = false, + $time_limit = 0, + $max_errors = null ) { return $this->compileAll($extension, $force_compile, $time_limit, $max_errors, true); } @@ -1537,20 +1427,20 @@ class Smarty extends \Smarty\TemplateBase /** * Compile all template or config files * - * @param string $extension template file name extension - * @param bool $force_compile force all to recompile - * @param int $time_limit set maximum execution time - * @param int $max_errors set maximum allowed errors - * @param bool $isConfig flag true if called for config files + * @param string $extension template file name extension + * @param bool $force_compile force all to recompile + * @param int $time_limit set maximum execution time + * @param int $max_errors set maximum allowed errors + * @param bool $isConfig flag true if called for config files * * @return int number of template files compiled */ protected function compileAll( - $extension, - $force_compile, - $time_limit, - $max_errors, - $isConfig = false + $extension, + $force_compile, + $time_limit, + $max_errors, + $isConfig = false ) { // switch off time limit if (function_exists('set_time_limit')) { @@ -1585,7 +1475,7 @@ class Smarty extends \Smarty\TemplateBase // $_smarty->force_compile = $force_compile; try { - $_tpl = $this->createTemplate($_file); + $_tpl = $this->doCreateTemplate($_file); $_tpl->caching = self::CACHING_OFF; $_tpl->setSource( $isConfig ? \Smarty\Template\Config::load($_tpl) : \Smarty\Template\Source::load($_tpl) @@ -1618,18 +1508,17 @@ class Smarty extends \Smarty\TemplateBase /** * check client side cache * - * @param \Smarty\Template\Cached $cached + * @param \Smarty\Template\Cached $cached * @param Template $_template - * @param string $content + * @param string $content * * @throws \Exception * @throws \Smarty\Exception */ - public function cacheModifiedCheck(Template\Cached $cached, Template $_template, $content) - { + public function cacheModifiedCheck(Template\Cached $cached, Template $_template, $content) { $_isCached = $_template->isCached() && !$_template->getCompiled()->getNocacheCode(); $_last_modified_date = - @substr($_SERVER[ 'HTTP_IF_MODIFIED_SINCE' ], 0, strpos($_SERVER[ 'HTTP_IF_MODIFIED_SINCE' ], 'GMT') + 3); + @substr($_SERVER['HTTP_IF_MODIFIED_SINCE'], 0, strpos($_SERVER['HTTP_IF_MODIFIED_SINCE'], 'GMT') + 3); if ($_isCached && $cached->timestamp <= strtotime($_last_modified_date)) { switch (PHP_SAPI) { case 'cgi': // php-cgi < 5.3 @@ -1639,18 +1528,18 @@ class Smarty extends \Smarty\TemplateBase break; case 'cli': if (/* ^phpunit */ - !empty($_SERVER[ 'SMARTY_PHPUNIT_DISABLE_HEADERS' ]) /* phpunit$ */ + !empty($_SERVER['SMARTY_PHPUNIT_DISABLE_HEADERS']) /* phpunit$ */ ) { - $_SERVER[ 'SMARTY_PHPUNIT_HEADERS' ][] = '304 Not Modified'; + $_SERVER['SMARTY_PHPUNIT_HEADERS'][] = '304 Not Modified'; } break; default: if (/* ^phpunit */ - !empty($_SERVER[ 'SMARTY_PHPUNIT_DISABLE_HEADERS' ]) /* phpunit$ */ + !empty($_SERVER['SMARTY_PHPUNIT_DISABLE_HEADERS']) /* phpunit$ */ ) { - $_SERVER[ 'SMARTY_PHPUNIT_HEADERS' ][] = '304 Not Modified'; + $_SERVER['SMARTY_PHPUNIT_HEADERS'][] = '304 Not Modified'; } else { - header($_SERVER[ 'SERVER_PROTOCOL' ] . ' 304 Not Modified'); + header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified'); } break; } @@ -1658,9 +1547,9 @@ class Smarty extends \Smarty\TemplateBase switch (PHP_SAPI) { case 'cli': if (/* ^phpunit */ - !empty($_SERVER[ 'SMARTY_PHPUNIT_DISABLE_HEADERS' ]) /* phpunit$ */ + !empty($_SERVER['SMARTY_PHPUNIT_DISABLE_HEADERS']) /* phpunit$ */ ) { - $_SERVER[ 'SMARTY_PHPUNIT_HEADERS' ][] = + $_SERVER['SMARTY_PHPUNIT_HEADERS'][] = 'Last-Modified: ' . gmdate('D, d M Y H:i:s', $cached->timestamp) . ' GMT'; } break; @@ -1711,13 +1600,12 @@ class Smarty extends \Smarty\TemplateBase /** * Run pre-filters over template source * - * @param string $source the content which shall be processed by the filters + * @param string $source the content which shall be processed by the filters * @param Template $template template object * * @return string the filtered source */ - public function runPreFilters($source, Template $template) - { + public function runPreFilters($source, Template $template) { foreach ($this->getExtensions() as $extension) { /** @var \Smarty\Filter\FilterInterface $filter */ @@ -1733,13 +1621,12 @@ class Smarty extends \Smarty\TemplateBase /** * Run post-filters over template's compiled code * - * @param string $code the content which shall be processed by the filters + * @param string $code the content which shall be processed by the filters * @param Template $template template object * * @return string the filtered code */ - public function runPostFilters($code, Template $template) - { + public function runPostFilters($code, Template $template) { foreach ($this->getExtensions() as $extension) { /** @var \Smarty\Filter\FilterInterface $filter */ @@ -1755,13 +1642,12 @@ class Smarty extends \Smarty\TemplateBase /** * Run filters over template output * - * @param string $content the content which shall be processed by the filters + * @param string $content the content which shall be processed by the filters * @param Template $template template object * * @return string the filtered (modified) output */ - public function runOutputFilters($content, Template $template) - { + public function runOutputFilters($content, Template $template) { foreach ($this->getExtensions() as $extension) { /** @var \Smarty\Filter\FilterInterface $filter */ @@ -1781,10 +1667,9 @@ class Smarty extends \Smarty\TemplateBase * @param string $_contents file content * * @return boolean true - *@throws Exception + * @throws Exception */ - public function writeFile($_filepath, $_contents) - { + public function writeFile($_filepath, $_contents) { $_error_reporting = error_reporting(); error_reporting($_error_reporting & ~E_NOTICE & ~E_WARNING); $_dirpath = dirname($_filepath); @@ -1806,7 +1691,7 @@ class Smarty extends \Smarty\TemplateBase } } // write to tmp file, then move to overt file lock race condition - $_tmp_file = $_dirpath . DIRECTORY_SEPARATOR . str_replace(array('.', ','), '_', uniqid('wrt', true)); + $_tmp_file = $_dirpath . DIRECTORY_SEPARATOR . str_replace(['.', ','], '_', uniqid('wrt', true)); if (!file_put_contents($_tmp_file, $_contents)) { error_reporting($_error_reporting); throw new Exception("unable to write file {$_tmp_file}"); @@ -1847,11 +1732,11 @@ class Smarty extends \Smarty\TemplateBase return true; } - private $runtimes = []; /** * Loads and returns a runtime extension or null if not found + * * @param string $type * * @return object|null @@ -1919,8 +1804,6 @@ class Smarty extends \Smarty\TemplateBase */ public function loadFilter($type, $name) { - - if ($type == \Smarty\Smarty::FILTER_VARIABLE) { foreach ($this->getExtensions() as $extension) { if ($extension->getModifierCallback($name)) { @@ -1993,6 +1876,7 @@ class Smarty extends \Smarty\TemplateBase $this->_caching_type = $type; $this->activateBCCacheResource(); } + /** * @return string * @deprecated since 5.0 @@ -2108,8 +1992,7 @@ class Smarty extends \Smarty\TemplateBase * * @return string|null internal filter name or null if callable cannot be serialized */ - private function _getFilterName($callable) - { + private function _getFilterName($callable) { if (is_array($callable)) { $_class_name = is_object($callable[0]) ? get_class($callable[0]) : $callable[0]; return $_class_name . '_' . $callable[1]; @@ -2158,7 +2041,6 @@ class Smarty extends \Smarty\TemplateBase return $this; } - /** * Add default modifiers * @@ -2178,7 +2060,6 @@ class Smarty extends \Smarty\TemplateBase return $this; } - /** * Get default modifiers * @@ -2205,10 +2086,6 @@ class Smarty extends \Smarty\TemplateBase return $this; } - public function setAllowAmbiguousResources(bool $allow) { - $this->allow_ambiguous_resources = $allow; - } - /** * @return Cacheresource\Base */ @@ -2252,6 +2129,62 @@ class Smarty extends \Smarty\TemplateBase return $this->returnOrCreateTemplate($template, $cache_id, $compile_id)->display(); } + /** + * @param $resource_name + * @param $cache_id + * @param $compile_id + * @param $parent + * @param $caching + * @param $cache_lifetime + * @param bool $isConfig + * @param array $data + * + * @return Template + * @throws Exception + */ + public function doCreateTemplate( + $resource_name, + $cache_id = null, + $compile_id = null, + $parent = null, + $caching = null, + $cache_lifetime = null, + bool $isConfig = false, + array $data = []): Template { + + if (!$this->_templateDirNormalized) { + $this->_normalizeTemplateConfig(false); + } + + $_templateId = $this->generateUniqueTemplateId($resource_name, $cache_id, $compile_id, $caching); + + if (!isset($this->templates[$_templateId])) { + $newTemplate = new Template($resource_name, $this, $parent ?: $this, $cache_id, $compile_id, $caching, $isConfig); + $newTemplate->templateId = $_templateId; // @TODO this could go in constructor ^? + $this->templates[$_templateId] = $newTemplate; + } + + $tpl = clone $this->templates[$_templateId]; + + $tpl->setParent($parent ?: $this); + + if ($cache_lifetime) { + $tpl->setCacheLifetime($cache_lifetime); + } + + // fill data if present + foreach ($data as $_key => $_val) { + $tpl->assign($_key, $_val); + } + + $tpl->tplFunctions = array_merge($parent->tplFunctions ?? [], $tpl->tplFunctions ?? []); + + if (!$this->debugging && $this->debugging_ctrl === 'URL') { + $tpl->getSmarty()->getDebug()->debugUrl($tpl->getSmarty()); + } + return $tpl; + } + /** * test if cache is valid * diff --git a/src/Template.php b/src/Template.php index 596b07ed..0d0018db 100644 --- a/src/Template.php +++ b/src/Template.php @@ -10,6 +10,7 @@ namespace Smarty; +use Smarty\Resource\BasePlugin; use Smarty\Runtime\InheritanceRuntime; use Smarty\Template\Source; use Smarty\Template\Cached; @@ -154,9 +155,9 @@ class Template extends TemplateBase { $this->smarty->getDebug()->start_template($this, $display); } // checks if template exists - if (!$this->getSource()->exists) { + if ($this->compile_check && !$this->getSource()->exists) { throw new Exception( - "Unable to load template '{$this->getSource()->type}:{$this->getSource()->name}'" . + "Unable to load '{$this->getSource()->type}:{$this->getSource()->name}'" . ($this->_isSubTpl() ? " in '{$this->parent->template_resource}'" : '') ); } @@ -174,16 +175,9 @@ class Template extends TemplateBase { // read from cache or render if ($this->caching === \Smarty\Smarty::CACHING_LIFETIME_CURRENT || $this->caching === \Smarty\Smarty::CACHING_LIFETIME_SAVED) { - if ($this->getCached()->cache_id !== $this->cache_id || $this->getCached()->compile_id !== $this->compile_id) { - $this->getCached(true); - } $this->getCached()->render($this, $no_output_filter); } else { - $compiled = $this->getCompiled(); - if ($compiled->compile_id !== $this->compile_id) { - $compiled = $this->getCompiled(true); - } - $compiled->render($this); + $this->getCompiled()->render($this); } } finally { @@ -254,29 +248,34 @@ class Template extends TemplateBase { $caching, $cache_lifetime, array $extra_vars = [], - int $scope = null + int $scope = null, + ?string $currentDir = null ) { - $baseFilePath = $this->source && $this->getSource()->filepath ? dirname($this->getSource()->filepath) : null; + $name = $this->parseResourceName($template_name); + if ($currentDir && preg_match('/^\.{1,2}\//', $name)) { + // relative template resource name, append it to current template name + $template_name = $currentDir . DIRECTORY_SEPARATOR . $name; + } - $tpl = $this->getSmarty()->createTemplate($template_name, $cache_id, $compile_id, $this, $caching, $cache_lifetime, $baseFilePath); - $tpl->setCached($this->getCached()); // re-use the same Cache object across subtemplates to gather hashes and file dependencies. - $tpl->setInheritance($this->getInheritance()); // re-use the same Inheritance object inside the inheritance tree + $tpl = $this->smarty->doCreateTemplate($template_name, $cache_id, $compile_id, $this, $caching, $cache_lifetime); + + $tpl->inheritance = $this->getInheritance(); // re-use the same Inheritance object inside the inheritance tree if ($scope) { - $tpl->setDefaultScope($scope); + $tpl->defaultScope = $scope; } // recursive call ? - if ($tpl->getTemplateId() !== $this->getTemplateId() && $caching !== \Smarty\Template::CACHING_NOCACHE_CODE) { + if ($tpl->templateId !== $this->templateId && $caching !== \Smarty\Template::CACHING_NOCACHE_CODE) { $tpl->getCached(true); + } else { + // re-use the same Cache object across subtemplates to gather hashes and file dependencies. + $tpl->setCached($this->getCached()); } - if (!empty($extra_vars)) { - // set up variable values - foreach ($extra_vars as $_key => $_val) { - $tpl->assign($_key, $_val); - } + foreach ($extra_vars as $_key => $_val) { + $tpl->assign($_key, $_val); } if ($tpl->caching === \Smarty\Template::CACHING_NOCACHE_CODE) { if ($tpl->getCompiled()->getNocacheCode()) { @@ -287,9 +286,21 @@ class Template extends TemplateBase { $tpl->render(); } - public function setParent($parent): void { - parent::setParent($parent); - $this->setSource($this->source->isConfig ? Config::load($this) : Source::load($this)); + /** + * Remove type indicator from resource name if present. + * E.g. $this->parseResourceName('file:template.tpl') returns 'template.tpl' + * + * @note "C:/foo.tpl" was forced to file resource up till Smarty 3.1.3 (including). + * + * @param string $resource_name template_resource or config_resource to parse + * + * @return string + */ + private function parseResourceName($resource_name): string { + if (preg_match('/^([A-Za-z0-9_\-]{2,}):/', $resource_name, $match)) { + return substr($resource_name, strlen($match[0])); + } + return $resource_name; } /** @@ -392,8 +403,9 @@ class Template extends TemplateBase { $this->compile_id, $this->cache_id ); - $cacheResource->populate($this->cached, $this); - if (!$this->isCachingEnabled()) { + if ($this->isCachingEnabled()) { + $cacheResource->populate($this->cached, $this); + } else { $this->cached->setValid(false); } } @@ -477,7 +489,7 @@ class Template extends TemplateBase { } else { $parent_resource = ''; } - throw new Exception("Unable to load template {$this->getSource()->type} '{$this->getSource()->name}'{$parent_resource}"); + throw new Exception("Unable to load {$this->getSource()->type} '{$this->getSource()->name}'{$parent_resource}"); } // @TODO move this logic to Compiled @@ -564,7 +576,7 @@ class Template extends TemplateBase { $confObj = parent::configLoad($config_file, $sections); $this->getCompiled()->file_dependency[ $confObj->getSource()->uid ] = - array($confObj->getSource()->filepath, $confObj->getSource()->getTimeStamp(), $confObj->getSource()->type); + array($confObj->getSource()->getResourceName(), $confObj->getSource()->getTimeStamp(), $confObj->getSource()->type); return $confObj; } @@ -693,4 +705,25 @@ class Template extends TemplateBase { $this->cached = $cached; } + /** + * @param string $compile_id + * + * @throws Exception + */ + public function setCompileId($compile_id) { + parent::setCompileId($compile_id); + $this->getCompiled(true); + $this->getCached(true); + } + + /** + * @param string $cache_id + * + * @throws Exception + */ + public function setCacheId($cache_id) { + parent::setCacheId($cache_id); + $this->getCached(true); + } + } diff --git a/src/Template/Cached.php b/src/Template/Cached.php index 888858a2..78635db0 100644 --- a/src/Template/Cached.php +++ b/src/Template/Cached.php @@ -210,10 +210,9 @@ class Cached extends GeneratedPhpFile { * Process cached template * * @param Template $_template template object - * @param bool $update flag if called because cache update */ - private function process(Template $_template, $update = false) { - if ($this->handler->process($_template, $this, $update) === false) { + private function process(Template $_template) { + if ($this->handler->process($_template, $this) === false) { $this->valid = false; } $this->processed = $this->valid; @@ -282,15 +281,7 @@ class Cached extends GeneratedPhpFile { } $this->removeNoCacheHash($_template, $no_output_filter); - - if ($_template->_isSubTpl()) { - // @TODO why is this needed? - $_template->getCompiled()->unifunc = $_template->parent->getCompiled()->unifunc; - } - - if (!$this->processed) { - $this->process($_template, true); - } + $this->process($_template); if ($_template->getSmarty()->debugging) { $_template->getSmarty()->getDebug()->end_cache($_template); diff --git a/src/Template/Compiled.php b/src/Template/Compiled.php index 753bae76..c5647422 100644 --- a/src/Template/Compiled.php +++ b/src/Template/Compiled.php @@ -72,11 +72,8 @@ class Compiled extends GeneratedPhpFile { } else { $this->filepath .= (int)$smarty->escape_html * 2; } - $this->filepath .= '.' . $source->type; - $basename = $source->getBasename(); - if (!empty($basename)) { - $this->filepath .= '.' . $basename; - } + $this->filepath .= '.' . $source->type . '_' . $source->getBasename(); + if ($_template->caching) { $this->filepath .= '.cache'; } @@ -96,11 +93,7 @@ class Compiled extends GeneratedPhpFile { * @throws \Smarty\Exception */ public function render(Template $_template) { - // checks if template exists - if (!$_template->getSource()->exists) { - $type = $_template->getSource()->isConfig ? 'config' : 'template'; - throw new \Smarty\Exception("Unable to load {$type} '{$_template->getSource()->type}:{$_template->getSource()->name}'"); - } + if ($_template->getSmarty()->debugging) { $_template->getSmarty()->getDebug()->start_render($_template); } @@ -109,8 +102,10 @@ class Compiled extends GeneratedPhpFile { } // @TODO Can't Cached handle this? Maybe introduce an event to decouple. - $_template->getCached()->file_dependency = - array_merge($_template->getCached()->file_dependency, $this->file_dependency); + if ($_template->caching) { + $_template->getCached()->file_dependency = + array_merge($_template->getCached()->file_dependency, $this->file_dependency); + } $this->getRenderedTemplateCode($_template, $this->unifunc); diff --git a/src/Template/Config.php b/src/Template/Config.php index 7d55e7eb..b2fcbf81 100644 --- a/src/Template/Config.php +++ b/src/Template/Config.php @@ -8,7 +8,7 @@ use Smarty\Exception; /** * Smarty Config Resource Data Object - * Meta Data Container for Config Files + * Metadata Container for Config Files * * @author Uwe Tews */ @@ -22,45 +22,15 @@ class Config extends Source { public $isConfig = true; /** - * initialize Source Object for given resource - * Either [$_template] or [$smarty, $template_resource] must be specified - * - * @param Template $_template template object - * @param Smarty $smarty smarty object - * @param string $template_resource resource identifier - * - * @return Config Source Object - * @throws Exception + * @var array */ - public static function load( - Template $_template = null, - Smarty $smarty = null, - $template_resource = null - ) { - static $_incompatible_resources = ['extends' => true, 'php' => true]; - if ($_template) { - $smarty = $_template->getSmarty(); - $template_resource = $_template->template_resource; - } - if (empty($template_resource)) { - throw new Exception('Source: Missing name'); - } - // parse resource_name, load resource handler - [$name, $type] = \Smarty\Resource\BasePlugin::parseResourceName($template_resource, $smarty->default_config_type); - // make sure configs are not loaded via anything smarty can't handle - if (isset($_incompatible_resources[$type])) { - throw new Exception("Unable to use resource '{$type}' for config"); - } - $source = new Config($smarty, $template_resource, $type, $name); - $source->handler->populate($source, $_template); - if (!$source->exists && isset($smarty->default_config_handler_func)) { - $source->_getDefaultTemplate($smarty->default_config_handler_func); - $source->handler->populate($source, $_template); - } - return $source; - } + static protected $_incompatible_resources = ['extends' => true]; public function createCompiler(): \Smarty\Compiler\BaseCompiler { return new \Smarty\Compiler\Configfile($this->smarty); } + + protected static function getDefaultHandlerFunc(Smarty $smarty) { + return $smarty->default_config_handler_func; + } } diff --git a/src/Template/GeneratedPhpFile.php b/src/Template/GeneratedPhpFile.php index 6a9c2a51..f436e976 100644 --- a/src/Template/GeneratedPhpFile.php +++ b/src/Template/GeneratedPhpFile.php @@ -3,6 +3,7 @@ namespace Smarty\Template; use Smarty\Exception; +use Smarty\Resource\FilePlugin; use Smarty\Template; /** @@ -127,22 +128,27 @@ abstract class GeneratedPhpFile { protected function checkFileDependencies($file_dependency, Template $_template): bool { // check file dependencies at compiled code foreach ($file_dependency as $_file_to_check) { - if ($_file_to_check[2] === 'file') { - if ($_template->getSource()->filepath === $_file_to_check[0]) { + + $handler = \Smarty\Resource\BasePlugin::load($_template->getSmarty(), $_file_to_check[2]); + + if ($handler instanceof FilePlugin) { + if ($_template->getSource()->getResourceName() === $_file_to_check[0]) { // do not recheck current template continue; } - // file and php types can be checked without loading the respective resource handlers - $mtime = is_file($_file_to_check[0]) ? filemtime($_file_to_check[0]) : false; + $mtime = $handler->getResourceNameTimestamp($_file_to_check[0], $_template->getSmarty(), $_template->getSource()->isConfig); } else { - $handler = \Smarty\Resource\BasePlugin::load($_template->getSmarty(), $_file_to_check[2]); + if ($handler->checkTimestamps()) { - $source = Source::load($_template, $_template->getSmarty(), $_file_to_check[0]); + // @TODO this doesn't actually check any dependencies, but only the main source file + // and that might to be irrelevant, as the comment "do not recheck current template" above suggests + $source = Source::load($_template, $_template->getSmarty()); $mtime = $source->getTimeStamp(); } else { continue; } } + if ($mtime === false || $mtime > $_file_to_check[1]) { return false; } diff --git a/src/Template/Source.php b/src/Template/Source.php index 4d5621ff..cba8106f 100644 --- a/src/Template/Source.php +++ b/src/Template/Source.php @@ -2,6 +2,7 @@ namespace Smarty\Template; +use Smarty\Resource\FilePlugin; use Smarty\Smarty; use Smarty\Template; use Smarty\Exception; @@ -15,7 +16,7 @@ class Source { /** * Unique Template ID * - * @var string + * @var string|null */ public $uid = null; @@ -40,13 +41,6 @@ class Source { */ public $name = null; - /** - * Source Filepath - * - * @var string - */ - public $filepath = null; - /** * Source Timestamp * @@ -103,6 +97,11 @@ class Source { */ public $content = null; + /** + * @var array + */ + static protected $_incompatible_resources = []; + /** * create Source Object container * @@ -114,11 +113,11 @@ class Source { * @throws \Smarty\Exception * @internal param \Smarty\Resource\Base $handler Resource Handler this source object communicates with */ - public function __construct(Smarty $smarty, $resource, $type, $name) { + public function __construct(Smarty $smarty, $type, $name) { $this->handler = \Smarty\Resource\BasePlugin::load($smarty, $type); $this->smarty = $smarty; - $this->resource = $resource; + $this->resource = $type . ':' . $name; $this->type = $type; $this->name = $name; } @@ -147,7 +146,7 @@ class Source { throw new Exception('Source: Missing name'); } // parse resource_name, load resource handler, identify unique resource name - if (preg_match('/^([A-Za-z0-9_\-]{2,})[:]([\s\S]*)$/', $template_resource, $match)) { + if (preg_match('/^([A-Za-z0-9_\-]{2,}):([\s\S]*)$/', $template_resource, $match)) { $type = $match[1]; $name = $match[2]; } else { @@ -156,16 +155,25 @@ class Source { $type = $smarty->default_resource_type; $name = $template_resource; } - // create new source object - $source = new Source($smarty, $template_resource, $type, $name); + + if (isset(self::$_incompatible_resources[$type])) { + throw new Exception("Unable to use resource '{$type}' for " . __METHOD__); + } + + // create new source object + $source = new static($smarty, $type, $name); $source->handler->populate($source, $_template); - if (!$source->exists && $_template && isset($_template->getSmarty()->default_template_handler_func)) { - $source->_getDefaultTemplate($_template->getSmarty()->default_template_handler_func); + if (!$source->exists && static::getDefaultHandlerFunc($smarty)) { + $source->_getDefaultTemplate(static::getDefaultHandlerFunc($smarty)); $source->handler->populate($source, $_template); } return $source; } + protected static function getDefaultHandlerFunc(Smarty $smarty) { + return $smarty->default_template_handler_func; + } + /** * Get source time stamp * @@ -206,12 +214,11 @@ class Source { } else { throw new Exception( 'Default handler: Unable to load ' . - ($this->isConfig ? 'config' : 'template') . - " default file '{$_return}' for '{$this->type}:{$this->name}'" + "default file '{$_return}' for '{$this->type}:{$this->name}'" ); } - $this->name = $this->filepath = $_return; - $this->uid = sha1($this->filepath); + $this->name = $_return; + $this->uid = sha1($_return); } elseif ($_return === true) { $this->content = $_content; $this->exists = true; @@ -244,4 +251,35 @@ class Source { return $this->handler->getBasename($this); } + /** + * Return source name + * e.g.: 'sub/index.tpl' + * + * @return string + */ + public function getResourceName(): string { + return (string) $this->name; + } + + /** + * Return source name, including the type prefix. + * e.g.: 'file:sub/index.tpl' + * + * @return string + */ + public function getFullResourceName(): string { + return $this->type . ':' . $this->name; + } + + public function getFilepath(): string { + if ($this->handler instanceof FilePlugin) { + return $this->handler->getFilePath($this->name, $this->smarty, $this->isConfig); + } + return '.'; + } + + public function isConfig(): bool { + return $this->isConfig; + } + } diff --git a/tests/PHPUnit_Smarty.php b/tests/PHPUnit_Smarty.php index c75a8232..98042db5 100644 --- a/tests/PHPUnit_Smarty.php +++ b/tests/PHPUnit_Smarty.php @@ -398,7 +398,7 @@ KEY `name` (`name`) return sha1($this->normalizePath($this->smarty->getTemplateDir(0) . $name) . $this->smarty->_joined_template_dir); } - return sha1($tpl->getSource()->filepath . $this->smarty->_joined_template_dir); + return sha1($tpl->getSource()->uid . $this->smarty->_joined_template_dir); case 'mysqltest': case 'mysql': return sha1($type . ':' . $name); @@ -564,7 +564,7 @@ KEY `name` (`name`) $_cache_id = isset($cache_id) ? preg_replace('![^\w\|]+!', '_', $cache_id) : null; $sp = $this->buildSourcePath($tpl, $name, $type, $dir); $uid = $this->buildUid($tpl, $sp, $name, $type); - $_filepath = sha1($uid . $this->smarty->_joined_template_dir); + $_filepath = $uid; // if use_sub_dirs, break file into directories if ($sub) { $_filepath = diff --git a/tests/UnitTests/CacheResourceTests/File/CacheResourceFileTest.php b/tests/UnitTests/CacheResourceTests/File/CacheResourceFileTest.php index d009f7cf..4d08afcd 100644 --- a/tests/UnitTests/CacheResourceTests/File/CacheResourceFileTest.php +++ b/tests/UnitTests/CacheResourceTests/File/CacheResourceFileTest.php @@ -10,10 +10,6 @@ include_once __DIR__ . '/../_shared/CacheResourceTestCommon.php'; /** * class for cache resource file tests - * - * - * - * */ class CacheResourceFileTest extends CacheResourceTestCommon { @@ -41,8 +37,8 @@ class CacheResourceFileTest extends CacheResourceTestCommon $this->smarty->cache_lifetime = 1000; $this->smarty->setUseSubDirs(true); $tpl = $this->smarty->createTemplate('helloworld.tpl'); - $this->assertEquals($this->buildCachedPath($tpl, true, null, null, 'helloworld.tpl', $type = 'file', $this->smarty->getTemplateDir(0), 'file') - , $tpl->getCached()->filepath); + + $this->assertRegExp('/.*\/([a-f0-9]{2}\/){3}.*.php/', $tpl->getCached()->filepath); } /** @@ -54,8 +50,8 @@ class CacheResourceFileTest extends CacheResourceTestCommon $this->smarty->cache_lifetime = 1000; $this->smarty->setUseSubDirs(true); $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar'); - $this->assertEquals($this->buildCachedPath($tpl, true, 'foo|bar', null, 'helloworld.tpl', $type = 'file', $this->smarty->getTemplateDir(0), 'file') - , $tpl->getCached()->filepath); + + $this->assertRegExp('/.*\/foo\/bar\/([a-f0-9]{2}\/){3}.*.php/', $tpl->getCached()->filepath); } /** @@ -67,8 +63,7 @@ class CacheResourceFileTest extends CacheResourceTestCommon $this->smarty->cache_lifetime = 1000; $this->smarty->setUseSubDirs(true); $tpl = $this->smarty->createTemplate('helloworld.tpl', null, 'blar'); - $this->assertEquals($this->buildCachedPath($tpl, true, null, 'blar', 'helloworld.tpl', $type = 'file', $this->smarty->getTemplateDir(0), 'file') - , $tpl->getCached()->filepath); + $this->assertRegExp('/.*\/blar\/([a-f0-9]{2}\/){3}.*.php/', $tpl->getCached()->filepath); } /** @@ -80,8 +75,7 @@ class CacheResourceFileTest extends CacheResourceTestCommon $this->smarty->cache_lifetime = 1000; $this->smarty->setUseSubDirs(true); $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); - $this->assertEquals($this->buildCachedPath($tpl, true, 'foo|bar', 'blar', 'helloworld.tpl', $type = 'file', $this->smarty->getTemplateDir(0), 'file') - , $tpl->getCached()->filepath); + $this->assertRegExp('/.*\/foo\/bar\/blar\\/([a-f0-9]{2}\/){3}.*.php/', $tpl->getCached()->filepath); } /** diff --git a/tests/UnitTests/CacheResourceTests/_shared/CacheResourceTestCommon.php b/tests/UnitTests/CacheResourceTests/_shared/CacheResourceTestCommon.php index 42e5ba8b..222f1ad2 100644 --- a/tests/UnitTests/CacheResourceTests/_shared/CacheResourceTestCommon.php +++ b/tests/UnitTests/CacheResourceTests/_shared/CacheResourceTestCommon.php @@ -362,12 +362,12 @@ abstract class CacheResourceTestCommon extends PHPUnit_Smarty $this->assertEquals('something else 1', $tpl->getCachedContent()); $this->assertEquals('something else 2', $tpl2->getCachedContent()); $this->assertEquals('something else 3', $tpl3->getCachedContent()); - sleep(10); + sleep(4); $tpl4 = $this->smarty->createTemplate('helloworld2.tpl'); $tpl4->writeCachedContent('something else 4'); // test number of deleted caches - $this->doClearCacheAssertion(3,$this->smarty->clearAllCache(5)); + $this->doClearCacheAssertion(3,$this->smarty->clearAllCache(2)); $tpl = $this->smarty->createTemplate('helloworld.tpl'); $tpl2 = $this->smarty->createTemplate('helloworld.tpl', null, 'bar'); @@ -422,7 +422,7 @@ abstract class CacheResourceTestCommon extends PHPUnit_Smarty $this->smarty->cache_locking = true; $this->smarty->locking_timeout = $lockTimeout; } - $this->smarty->compile_id = $compile_id; + $this->smarty->setCompileId($compile_id); $this->smarty->cache_id = $cache_id; $this->smarty->force_compile = $forceCompile; $this->smarty->force_cache = $forceCache; diff --git a/tests/UnitTests/CacheResourceTests/_shared/PHPunitplugins/resource.filetest.php b/tests/UnitTests/CacheResourceTests/_shared/PHPunitplugins/resource.filetest.php index 8d5b4271..0aa280c4 100644 --- a/tests/UnitTests/CacheResourceTests/_shared/PHPunitplugins/resource.filetest.php +++ b/tests/UnitTests/CacheResourceTests/_shared/PHPunitplugins/resource.filetest.php @@ -16,8 +16,8 @@ class Smarty_Resource_FiletestPlugin extends FilePlugin { parent::populate($source, $_template); if ($source->exists) { - if (isset(CacheResourceTestCommon::$touchResource[$source->filepath])) { - $source->timestamp = CacheResourceTestCommon::$touchResource[$source->filepath]; + if (isset(CacheResourceTestCommon::$touchResource[$source->getResourceName()])) { + $source->timestamp = CacheResourceTestCommon::$touchResource[$source->getResourceName()]; } } } diff --git a/tests/UnitTests/Compiler/CompilerPlugin/CompileCompilerPluginTest.php b/tests/UnitTests/Compiler/CompilerPlugin/CompileCompilerPluginTest.php index d894b8c9..ba747981 100644 --- a/tests/UnitTests/Compiler/CompilerPlugin/CompileCompilerPluginTest.php +++ b/tests/UnitTests/Compiler/CompilerPlugin/CompileCompilerPluginTest.php @@ -31,7 +31,7 @@ class CompileCompilerPluginTest extends PHPUnit_Smarty public function testCompilerPluginFunction() { $this->smarty->registerPlugin(\Smarty\Smarty::PLUGIN_COMPILER, 'compilerplugin', 'mycompilerplugin'); - $this->smarty->compile_id = 'function'; + $this->smarty->setCompileId('function'); $this->assertEquals("Hello World", $this->smarty->fetch('compilerplugintest.tpl')); } /** @@ -40,7 +40,7 @@ class CompileCompilerPluginTest extends PHPUnit_Smarty public function testCompilerPluginClassStatic() { $this->smarty->registerPlugin(\Smarty\Smarty::PLUGIN_COMPILER, 'compilerplugin', array('CompilerPluginClass', 'statCompile')); - $this->smarty->compile_id = 'static'; + $this->smarty->setCompileId('static'); $this->assertEquals("Static World", $this->smarty->fetch('compilerplugintest.tpl')); } /** @@ -50,7 +50,7 @@ class CompileCompilerPluginTest extends PHPUnit_Smarty { $plugin = new CompilerPluginClass; $this->smarty->registerPlugin(\Smarty\Smarty::PLUGIN_COMPILER, 'compilerplugin', array($plugin, 'compile')); - $this->smarty->compile_id = 'object'; + $this->smarty->setCompileId('object'); $this->assertEquals("Public World", $this->smarty->fetch('compilerplugintest.tpl')); } } diff --git a/tests/UnitTests/ConfigFileTests/defaultHandler/DefaultConfigHandlerTest.php b/tests/UnitTests/ConfigFileTests/defaultHandler/DefaultConfigHandlerTest.php index faa88c0e..ab5ecdc6 100644 --- a/tests/UnitTests/ConfigFileTests/defaultHandler/DefaultConfigHandlerTest.php +++ b/tests/UnitTests/ConfigFileTests/defaultHandler/DefaultConfigHandlerTest.php @@ -35,7 +35,7 @@ class DefaultConfigHandlerTest extends PHPUnit_Smarty public function testUnknownConfigFile() { $this->expectException(\Smarty\Exception::class); - $this->expectExceptionMessage('Unable to load config \'file:foo.conf\''); + $this->expectExceptionMessage('Unable to load \'file:foo.conf\''); $this->smarty->configLoad('foo.conf'); } @@ -79,7 +79,7 @@ class DefaultConfigHandlerTest extends PHPUnit_Smarty public function testDefaultConfigHandlerReplacementByConfigFileFail() { $this->expectException(\Smarty\Exception::class); - $this->expectExceptionMessage("Unable to load config default file 'no.conf' for 'file:fo.conf'"); + $this->expectExceptionMessage("Unable to load default file 'no.conf' for 'file:fo.conf'"); $this->smarty->registerDefaultConfigHandler('configHandlerFile'); $this->smarty->configLoad('fo.conf'); $this->assertEquals("123.4", $this->smarty->fetch('number.tpl')); @@ -91,7 +91,7 @@ class DefaultConfigHandlerTest extends PHPUnit_Smarty public function testDefaultConfigHandlerReplacementReturningFalse() { $this->expectException(\Smarty\Exception::class); - $this->expectExceptionMessage('Unable to load config \'file:foo.conf\''); + $this->expectExceptionMessage('Unable to load \'file:foo.conf\''); $this->smarty->configLoad('foo.conf'); } diff --git a/tests/UnitTests/ResourceTests/Custom/Ambiguous/CustomResourceAmbiguousTest.php b/tests/UnitTests/ResourceTests/Custom/Ambiguous/CustomResourceAmbiguousTest.php index 571b3d87..610d8de3 100644 --- a/tests/UnitTests/ResourceTests/Custom/Ambiguous/CustomResourceAmbiguousTest.php +++ b/tests/UnitTests/ResourceTests/Custom/Ambiguous/CustomResourceAmbiguousTest.php @@ -45,7 +45,7 @@ class CustomResourceAmbiguousTest extends PHPUnit_Smarty $resource_handler = new Smarty_Resource_AmbiguousPlugin(__DIR__ . '/templates/ambiguous/'); $this->smarty->registerResource('ambiguous', $resource_handler); $this->smarty->setDefaultResourceType('ambiguous'); - $this->smarty->setAllowAmbiguousResources(true); +// $this->smarty->setAllowAmbiguousResources(true); $tpl = $this->smarty->createTemplate('foobar.tpl'); $this->assertFalse($tpl->getSource()->exists); @@ -56,7 +56,7 @@ class CustomResourceAmbiguousTest extends PHPUnit_Smarty $resource_handler = new Smarty_Resource_AmbiguousPlugin(__DIR__ . '/templates/ambiguous/'); $this->smarty->registerResource('ambiguous', $resource_handler); $this->smarty->setDefaultResourceType('ambiguous'); - $this->smarty->setAllowAmbiguousResources(true); +// $this->smarty->setAllowAmbiguousResources(true); $resource_handler->setSegment('case1'); @@ -70,7 +70,7 @@ class CustomResourceAmbiguousTest extends PHPUnit_Smarty $resource_handler = new Smarty_Resource_AmbiguousPlugin(__DIR__ . '/templates/ambiguous/'); $this->smarty->registerResource('ambiguous', $resource_handler); $this->smarty->setDefaultResourceType('ambiguous'); - $this->smarty->setAllowAmbiguousResources(true); +// $this->smarty->setAllowAmbiguousResources(true); $resource_handler->setSegment('case2'); @@ -85,7 +85,7 @@ class CustomResourceAmbiguousTest extends PHPUnit_Smarty $resource_handler = new Smarty_Resource_AmbiguousPlugin(__DIR__ . '/templates/ambiguous/'); $this->smarty->registerResource('ambiguous', $resource_handler); $this->smarty->setDefaultResourceType('ambiguous'); - $this->smarty->setAllowAmbiguousResources(true); +// $this->smarty->setAllowAmbiguousResources(true); $resource_handler->setSegment('case1'); $tpl = $this->smarty->createTemplate('foobar.tpl'); diff --git a/tests/UnitTests/ResourceTests/Custom/Ambiguous/PHPunitplugins/resource.ambiguous.php b/tests/UnitTests/ResourceTests/Custom/Ambiguous/PHPunitplugins/resource.ambiguous.php index e1a109a8..85ffadd5 100644 --- a/tests/UnitTests/ResourceTests/Custom/Ambiguous/PHPunitplugins/resource.ambiguous.php +++ b/tests/UnitTests/ResourceTests/Custom/Ambiguous/PHPunitplugins/resource.ambiguous.php @@ -1,5 +1,6 @@ segment, "/\\") . DIRECTORY_SEPARATOR; } - $source->filepath = $this->directory . $segment . $source->name; - $source->uid = sha1($source->filepath); + $source->uid = sha1($segment . '#' . $source->getResourceName()); if ($_template->getSmarty()->getCompileCheck() && !isset($source->timestamp)) { - $source->timestamp = @filemtime($source->filepath); + $source->timestamp = @filemtime($this->directory . $segment . $source->name); $source->exists = !!$source->timestamp; } } + + public function getContent(Source $source) { + + $segment = ''; + if ($this->segment) { + $segment = rtrim($this->segment, "/\\") . DIRECTORY_SEPARATOR; + } + + if ($source->exists) { + return file_get_contents($this->directory . $segment . $source->name); + } + throw new Exception( + 'Unable to read ' . ($source->isConfig ? 'config' : 'template') . + " {$source->type} '{$source->name}'" + ); + } } diff --git a/tests/UnitTests/ResourceTests/Custom/DemoPluginMysql/ResourceMysqlPluginTest.php b/tests/UnitTests/ResourceTests/Custom/DemoPluginMysql/ResourceMysqlPluginTest.php index 2a96cefc..16d85489 100644 --- a/tests/UnitTests/ResourceTests/Custom/DemoPluginMysql/ResourceMysqlPluginTest.php +++ b/tests/UnitTests/ResourceTests/Custom/DemoPluginMysql/ResourceMysqlPluginTest.php @@ -117,7 +117,7 @@ if (MysqlResourceEnable == true) { */ public function testUnknownTemplate() { $this->expectException(\Smarty\Exception::class); - $this->expectExceptionMessage('Unable to load template \'mysqlstest:foo.tpl\''); + $this->expectExceptionMessage('Unable to load \'mysqlstest:foo.tpl\''); $this->assertEquals('foo', $this->smarty->fetch('mysqlstest:foo.tpl')); } } diff --git a/tests/UnitTests/ResourceTests/DefaultHandler/DefaultTemplateHandlerTest.php b/tests/UnitTests/ResourceTests/DefaultHandler/DefaultTemplateHandlerTest.php index 1ee2176b..f2073507 100644 --- a/tests/UnitTests/ResourceTests/DefaultHandler/DefaultTemplateHandlerTest.php +++ b/tests/UnitTests/ResourceTests/DefaultHandler/DefaultTemplateHandlerTest.php @@ -36,7 +36,7 @@ class DefaultTemplateHandlerTest extends PHPUnit_Smarty $this->smarty->fetch('foo.tpl'); } catch (Exception $e) { - $this->assertStringContainsString('Unable to load template', $e->getMessage()); + $this->assertStringContainsString('Unable to load', $e->getMessage()); return; } diff --git a/tests/UnitTests/ResourceTests/Eval/EvalResourceTest.php b/tests/UnitTests/ResourceTests/Eval/EvalResourceTest.php index cbe7c549..f4bad162 100644 --- a/tests/UnitTests/ResourceTests/Eval/EvalResourceTest.php +++ b/tests/UnitTests/ResourceTests/Eval/EvalResourceTest.php @@ -39,18 +39,12 @@ class EvalResourceTest extends PHPUnit_Smarty $this->assertTrue($this->smarty->templateExists('eval:{$foo}')); } - /** - * test getTemplateFilepath - */ - public function testGetTemplateFilepath() + public function testGetTemplateResourceName() { $tpl = $this->smarty->createTemplate('eval:hello world'); - $this->assertEquals('2aae6c35c94fcfb415dbe95f408b9ce91ee846ed', $tpl->getSource()->filepath); + $this->assertEquals('hello world', $tpl->getSource()->getResourceName()); } - /** - * test getTemplateTimestamp - */ public function testGetTemplateTimestamp() { $tpl = $this->smarty->createTemplate('eval:hello world'); diff --git a/tests/UnitTests/ResourceTests/Extends/ExtendsResourceTest.php b/tests/UnitTests/ResourceTests/Extends/ExtendsResourceTest.php index 6368ffef..2ef17719 100644 --- a/tests/UnitTests/ResourceTests/Extends/ExtendsResourceTest.php +++ b/tests/UnitTests/ResourceTests/Extends/ExtendsResourceTest.php @@ -41,7 +41,7 @@ class ExtendsResourceTest extends PHPUnit_Smarty $this->smarty->caching = $caching; $this->smarty->merge_compiled_includes = $merge; if ($merge) { - $this->smarty->compile_id = 1; + $this->smarty->setCompileId(1); } $result = $this->smarty->fetch('extends:003_parent.tpl|003_child_prepend.tpl'); $this->assertStringContainsString( @@ -64,7 +64,7 @@ class ExtendsResourceTest extends PHPUnit_Smarty $this->smarty->caching = $caching; $this->smarty->merge_compiled_includes = $merge; if ($merge) { - $this->smarty->compile_id = 1; + $this->smarty->setCompileId(1); } $result = $this->smarty->fetch('extends:004_parent.tpl|004_child_append.tpl'); $this->assertStringContainsString("Default Title - append", $result, $testName . ' - content'); @@ -82,7 +82,7 @@ class ExtendsResourceTest extends PHPUnit_Smarty $this->smarty->caching = $caching; $this->smarty->merge_compiled_includes = $merge; if ($merge) { - $this->smarty->compile_id = 1; + $this->smarty->setCompileId(1); } $result = $this->smarty->fetch('extends:040_parent.tpl|040_child.tpl'); $this->assertStringContainsString("var-bar-var", $result, $testName . ' - content'); @@ -99,7 +99,7 @@ class ExtendsResourceTest extends PHPUnit_Smarty $this->smarty->caching = $caching; $this->smarty->merge_compiled_includes = $merge; if ($merge) { - $this->smarty->compile_id = 1; + $this->smarty->setCompileId(1); } $result = $this->smarty->fetch('extends:050_parent.tpl|050_child.tpl|050_grandchild.tpl'); $this->assertStringContainsString("var-bar-var", $result, $testName . ' - content'); diff --git a/tests/UnitTests/ResourceTests/File/FileResourceTest.php b/tests/UnitTests/ResourceTests/File/FileResourceTest.php index 17a1be3f..44201d4b 100644 --- a/tests/UnitTests/ResourceTests/File/FileResourceTest.php +++ b/tests/UnitTests/ResourceTests/File/FileResourceTest.php @@ -38,10 +38,10 @@ class FileResourceTest extends PHPUnit_Smarty /** * */ - public function testGetTemplateFilepath() + public function testGetTemplateResourceName() { $tpl = $this->smarty->createTemplate('helloworld.tpl'); - $this->assertEquals($this->normalizePath("./templates/helloworld.tpl"), $tpl->getSource()->filepath); + $this->assertEquals('helloworld.tpl', $tpl->getSource()->getResourceName()); } public function testTemplateFileExists1() @@ -102,14 +102,6 @@ class FileResourceTest extends PHPUnit_Smarty $this->assertFalse($tpl->getSource()->handler->recompiled); } - public function testGetCompiledFilepath() - { - $tpl = $this->smarty->createTemplate('helloworld.tpl'); - $this->assertEquals($this->buildCompiledPath($tpl, false, false, null, 'helloworld.tpl', 'file', $this->smarty->getTemplateDir(0)) - , $tpl->getCompiled()->filepath - ); - } - /** * @doesNotPerformAssertions */ @@ -152,8 +144,8 @@ class FileResourceTest extends PHPUnit_Smarty { // touch to prepare next test sleep(2); - $tpl = $this->smarty->createTemplate('helloworld.tpl'); - touch($tpl->getSource()->filepath); + $this->smarty->createTemplate('helloworld.tpl'); + touch(__DIR__ . '/templates/helloworld.tpl'); $this->setUp(); @@ -170,26 +162,23 @@ class FileResourceTest extends PHPUnit_Smarty $this->assertTrue(file_exists($tpl->getCompiled()->filepath)); } - public function testGetCachedFilepath() - { - $this->smarty->caching = true; - $this->smarty->cache_lifetime = 1000; - $tpl = $this->smarty->createTemplate('helloworld.tpl'); - $this->assertEquals($this->buildCachedPath($tpl, false, null, null, 'helloworld.tpl', 'file', $this->smarty->getTemplateDir(0), 'file') - , $tpl->getCached()->filepath - ); - } - public function testGetCachedTimestamp() { // create dummy cache file for the following test - file_put_contents($this->buildCachedPath($this->smarty, false, null, null, 'helloworld.tpl', 'file', $this->smarty->getTemplateDir(0), 'file') - , ''); - $this->smarty->caching = true; - $this->smarty->cache_lifetime = 1000; + $this->smarty->caching = true; + $this->smarty->cache_lifetime = 1000; + $tpl = $this->smarty->createTemplate('helloworld.tpl'); + $tpl->fetch(); + $timestamp = $tpl->getCached()->timestamp; + + + $this->smarty = new \Smarty\Smarty(); + $this->smarty->caching = true; + $this->smarty->cache_lifetime = 1000; + $tpl = $this->smarty->createTemplate('helloworld.tpl'); $this->assertTrue(is_integer($tpl->getCached()->timestamp)); - $this->assertEquals(10, strlen($tpl->getCached()->timestamp)); + $this->assertEquals($timestamp, $tpl->getCached()->timestamp); } diff --git a/tests/UnitTests/ResourceTests/FileIndexed/FileResourceIndexedTest.php b/tests/UnitTests/ResourceTests/FileIndexed/FileResourceIndexedTest.php index c85c8b95..9065c10d 100644 --- a/tests/UnitTests/ResourceTests/FileIndexed/FileResourceIndexedTest.php +++ b/tests/UnitTests/ResourceTests/FileIndexed/FileResourceIndexedTest.php @@ -25,30 +25,6 @@ class FileResourceIndexedTest extends PHPUnit_Smarty $this->cleanDirs(); } - public function testGetTemplateFilepath() - { - $tpl = $this->smarty->createTemplate('dirname.tpl'); - $this->assertEquals($this->normalizePath("./templates/dirname.tpl"), $tpl->getSource()->filepath); - } - - public function testGetTemplateFilepathNumber() - { - $tpl = $this->smarty->createTemplate('[1]dirname.tpl'); - $this->assertEquals($this->normalizePath('./templates_2/dirname.tpl'), $tpl->getSource()->filepath); - } - - public function testGetTemplateFilepathNumeric() - { - $tpl = $this->smarty->createTemplate('[10]dirname.tpl'); - $this->assertEquals($this->normalizePath('./templates_3/dirname.tpl'), $tpl->getSource()->filepath); - } - - public function testGetTemplateFilepathName() - { - $tpl = $this->smarty->createTemplate('[foo]dirname.tpl'); - $this->assertEquals($this->normalizePath('./templates_4/dirname.tpl'), $tpl->getSource()->filepath); - } - public function testFetch() { $tpl = $this->smarty->createTemplate('dirname.tpl'); @@ -101,15 +77,18 @@ class FileResourceIndexedTest extends PHPUnit_Smarty public function testGetCompiledFilepath() { $tpl = $this->smarty->createTemplate('[foo]dirname.tpl'); - $this->assertEquals($this->buildCompiledPath($tpl, false, false, null, 'dirname.tpl', 'file', $this->smarty->getTemplateDir('foo')), $tpl->getCompiled()->filepath); + $tpl2 = $this->smarty->createTemplate('dirname.tpl'); + + $this->assertNotEquals($tpl->getCompiled()->filepath, $tpl2->getCompiled()->filepath); } public function testGetCachedFilepath() { $this->smarty->caching = true; $this->smarty->cache_lifetime = 1000; - $tpl = $this->smarty->createTemplate('[foo]dirname.tpl'); - $this->assertEquals($this->buildCachedPath($tpl, false, null, null, 'dirname.tpl', 'file', $this->smarty->getTemplateDir('foo')) - , $tpl->getCached()->filepath); + $tpl = $this->smarty->createTemplate('[foo]dirname.tpl'); + $tpl2 = $this->smarty->createTemplate('dirname.tpl'); + + $this->assertNotEquals($tpl->getCached()->filepath, $tpl2->getCached()->filepath); } } diff --git a/tests/UnitTests/ResourceTests/Registered/RegisteredResourceTest.php b/tests/UnitTests/ResourceTests/Registered/RegisteredResourceTest.php index c171b263..407aa461 100644 --- a/tests/UnitTests/ResourceTests/Registered/RegisteredResourceTest.php +++ b/tests/UnitTests/ResourceTests/Registered/RegisteredResourceTest.php @@ -59,10 +59,10 @@ class RegisteredResourceTest extends PHPUnit_Smarty public function testResourceCompileIdChange() { $this->smarty->registerResource('myresource', new RegisteredResourceTest_Resource2Plugin()); - $this->smarty->compile_id = 'a'; + $this->smarty->setCompileId('a'); $this->assertEquals('this is template 1', $this->smarty->fetch('myresource:some')); $this->assertEquals('this is template 1', $this->smarty->fetch('myresource:some')); - $this->smarty->compile_id = 'b'; + $this->smarty->setCompileId('b'); $this->assertEquals('this is template 2', $this->smarty->fetch('myresource:some')); $this->assertEquals('this is template 2', $this->smarty->fetch('myresource:some')); } diff --git a/tests/UnitTests/ResourceTests/ResourcePlugins/PHPunitplugins/resource.db.php b/tests/UnitTests/ResourceTests/ResourcePlugins/PHPunitplugins/resource.db.php index ad758aa1..59315504 100644 --- a/tests/UnitTests/ResourceTests/ResourcePlugins/PHPunitplugins/resource.db.php +++ b/tests/UnitTests/ResourceTests/ResourcePlugins/PHPunitplugins/resource.db.php @@ -17,7 +17,6 @@ use Smarty\Template\Source; class Smarty_Resource_Db extends RecompiledPlugin { public function populate(Source $source, Template $_template = null) { - $source->filepath = 'db:'; $source->uid = sha1($source->resource); $source->timestamp = 1000000000; $source->exists = true; diff --git a/tests/UnitTests/ResourceTests/ResourcePlugins/PHPunitplugins/resource.db2.php b/tests/UnitTests/ResourceTests/ResourcePlugins/PHPunitplugins/resource.db2.php index d0293c5a..a4f65402 100644 --- a/tests/UnitTests/ResourceTests/ResourcePlugins/PHPunitplugins/resource.db2.php +++ b/tests/UnitTests/ResourceTests/ResourcePlugins/PHPunitplugins/resource.db2.php @@ -18,7 +18,6 @@ class Smarty_Resource_Db2 extends RecompiledPlugin { public function populate(Source $source, Template $_template = null) { - $source->filepath = 'db2:'; $source->uid = sha1($source->resource); $source->timestamp = 0; $source->exists = true; diff --git a/tests/UnitTests/ResourceTests/ResourcePlugins/PHPunitplugins/resource.db3.php b/tests/UnitTests/ResourceTests/ResourcePlugins/PHPunitplugins/resource.db3.php index 40e74d99..455255e2 100644 --- a/tests/UnitTests/ResourceTests/ResourcePlugins/PHPunitplugins/resource.db3.php +++ b/tests/UnitTests/ResourceTests/ResourcePlugins/PHPunitplugins/resource.db3.php @@ -17,7 +17,6 @@ class Smarty_Resource_Db3 extends Smarty\Resource\BasePlugin { public function populate(Source $source, Template $_template = null) { - $source->filepath = 'db3:'; $source->uid = sha1($source->resource); $source->timestamp = 0; $source->exists = true; diff --git a/tests/UnitTests/ResourceTests/ResourcePlugins/PHPunitplugins/resource.db4.php b/tests/UnitTests/ResourceTests/ResourcePlugins/PHPunitplugins/resource.db4.php index 823c7e5e..571df0d8 100644 --- a/tests/UnitTests/ResourceTests/ResourcePlugins/PHPunitplugins/resource.db4.php +++ b/tests/UnitTests/ResourceTests/ResourcePlugins/PHPunitplugins/resource.db4.php @@ -18,7 +18,6 @@ class Smarty_Resource_Db4 extends Smarty\Resource\BasePlugin { public function populate(Source $source, Template $_template = null) { - $source->filepath = 'db4:'; $source->uid = sha1($source->resource); $source->timestamp = 0; $source->exists = true; diff --git a/tests/UnitTests/ResourceTests/Stream/StreamResourceTest.php b/tests/UnitTests/ResourceTests/Stream/StreamResourceTest.php index acaa8a31..e2a8ff70 100644 --- a/tests/UnitTests/ResourceTests/Stream/StreamResourceTest.php +++ b/tests/UnitTests/ResourceTests/Stream/StreamResourceTest.php @@ -40,10 +40,10 @@ class StreamResourceTest extends PHPUnit_Smarty /** * test getTemplateFilepath */ - public function testGetTemplateFilepath() + public function testGetFullResourceName() { $tpl = $this->smarty->createTemplate('global:mytest'); - $this->assertEquals('global://mytest', $tpl->getSource()->filepath); + $this->assertEquals('global:mytest', $tpl->getSource()->getFullResourceName()); } /** diff --git a/tests/UnitTests/ResourceTests/String/StringResourceTest.php b/tests/UnitTests/ResourceTests/String/StringResourceTest.php index 4e4cdd13..a048d8b8 100644 --- a/tests/UnitTests/ResourceTests/String/StringResourceTest.php +++ b/tests/UnitTests/ResourceTests/String/StringResourceTest.php @@ -56,7 +56,7 @@ class StringResourceTest extends PHPUnit_Smarty public function testGetTemplateFilepath() { $tpl = $this->smarty->createTemplate('string:hello world'); - $this->assertEquals($this->buildSourcePath($tpl), $tpl->getSource()->filepath); + $this->assertEquals('hello world', $tpl->getSource()->getResourceName()); } /** @@ -104,15 +104,6 @@ class StringResourceTest extends PHPUnit_Smarty $this->assertTrue($tpl->mustCompile()); } - /** - * test getCompiledFilepath - */ - public function testGetCompiledFilepath() - { - $tpl = $this->smarty->createTemplate('string:hello world'); - $this->assertEquals($this->buildCompiledPath($tpl, false, false, null, 'hello world', 'string', $this->smarty->getTemplateDir(0)), $tpl->getCompiled()->filepath); - } - /** * test getCompiledTimestamp */ diff --git a/tests/UnitTests/SecurityTests/SecurityTest.php b/tests/UnitTests/SecurityTests/SecurityTest.php index 6b54069a..5f896cc8 100644 --- a/tests/UnitTests/SecurityTests/SecurityTest.php +++ b/tests/UnitTests/SecurityTests/SecurityTest.php @@ -272,7 +272,7 @@ class SecurityTest extends PHPUnit_Smarty */ public function testTemplateTrustedStream() { - stream_wrapper_register("global", "ResourceStreamSecurity") + stream_wrapper_register("global", ResourceStreamSecurity::class) or die("Failed to register protocol"); $fp = fopen("global://mytest", "r+"); fwrite($fp, 'hello world {$foo}'); @@ -291,7 +291,7 @@ class SecurityTest extends PHPUnit_Smarty { $this->expectException(\Smarty\Exception::class); $this->expectExceptionMessage('stream \'global\' not allowed by security setting'); - stream_wrapper_register("global", "ResourceStreamSecurity") + stream_wrapper_register("global", ResourceStreamSecurity::class) or die("Failed to register protocol"); $fp = fopen("global://mytest", "r+"); fwrite($fp, 'hello world {$foo}'); diff --git a/tests/UnitTests/SmartyMethodsTests/ClearCompiledTemplate/ClearCompiledTest.php b/tests/UnitTests/SmartyMethodsTests/ClearCompiledTemplate/ClearCompiledTest.php index ed1c818c..8e638d98 100644 --- a/tests/UnitTests/SmartyMethodsTests/ClearCompiledTemplate/ClearCompiledTest.php +++ b/tests/UnitTests/SmartyMethodsTests/ClearCompiledTemplate/ClearCompiledTest.php @@ -16,12 +16,10 @@ */ class ClearCompiledTest extends PHPUnit_Smarty { - public $methodName = null; public function setUp(): void { $this->setUpSmarty(__DIR__); $this->smarty->addTemplateDir('./templates_2/'); - $this->methodName = 'clearCompiledTemplate'; } @@ -165,7 +163,7 @@ class ClearCompiledTest extends PHPUnit_Smarty $this->makeFiles(); $expected = array(); - $this->assertEquals(12, $this->getSmarty()->{$this->methodName}()); + $this->assertEquals(12, $this->getSmarty()->clearCompiledTemplate()); $this->assertEquals($this->expectFiles($expected), $this->getFiles()); $this->clearFiles(); @@ -203,7 +201,7 @@ class ClearCompiledTest extends PHPUnit_Smarty 'ambiguous/case1/foobar.tpl#', 'ambiguous/case1/foobar.tpl#compile1', 'ambiguous/case1/foobar.tpl#compile2', '[1]ambiguous/case1/foobar.tpl#', '[1]ambiguous/case1/foobar.tpl#compile1', '[1]ambiguous/case1/foobar.tpl#compile2', ); - $this->assertEquals(3, $this->getSmarty()->{$this->methodName}('helloworld.tpl')); + $this->assertEquals(3, $this->getSmarty()->clearCompiledTemplate('helloworld.tpl')); $this->assertEquals($this->expectFiles($expected), $this->getFiles()); $this->clearFiles(); @@ -216,7 +214,7 @@ class ClearCompiledTest extends PHPUnit_Smarty $this->makeFiles(); $expected = array_keys($this->_files); - $this->assertEquals(0, $this->getSmarty()->{$this->methodName}('foobar.tpl')); + $this->assertEquals(0, $this->getSmarty()->clearCompiledTemplate('foobar.tpl')); $this->assertEquals($this->expectFiles($expected), $this->getFiles()); $this->clearFiles(); @@ -255,7 +253,7 @@ class ClearCompiledTest extends PHPUnit_Smarty 'ambiguous/case1/foobar.tpl#', 'ambiguous/case1/foobar.tpl#compile2', '[1]ambiguous/case1/foobar.tpl#', '[1]ambiguous/case1/foobar.tpl#compile2', ); - $count = $this->getSmarty()->{$this->methodName}(null, 'compile1'); + $count = $this->getSmarty()->clearCompiledTemplate(null, 'compile1'); $this->assertEquals(4, $count); $this->assertEquals($this->expectFiles($expected), $this->getFiles()); @@ -269,7 +267,7 @@ class ClearCompiledTest extends PHPUnit_Smarty $this->makeFiles(); $expected = array_keys($this->_files); - $this->assertEquals(0, $this->getSmarty()->{$this->methodName}(null, 'other')); + $this->assertEquals(0, $this->getSmarty()->clearCompiledTemplate(null, 'other')); $this->assertEquals($this->expectFiles($expected), $this->getFiles()); $this->clearFiles(); @@ -294,7 +292,7 @@ class ClearCompiledTest extends PHPUnit_Smarty $expected = array('helloworld.tpl#', 'helloworld2.tpl#'); $this->touchFiles(array_diff(array_keys($this->_files), $expected), - 1000); - $this->assertEquals(10, $this->getSmarty()->{$this->methodName}(null, null, 500)); + $this->assertEquals(10, $this->getSmarty()->clearCompiledTemplate(null, null, 500)); $this->assertEquals($this->expectFiles($expected), $this->getFiles()); $this->clearFiles(); @@ -324,7 +322,7 @@ class ClearCompiledTest extends PHPUnit_Smarty '[1]ambiguous/case1/foobar.tpl#', '[1]ambiguous/case1/foobar.tpl#compile1', '[1]ambiguous/case1/foobar.tpl#compile2', ); $this->touchFiles(array('helloworld.tpl#compile1'), - 1000); - $this->assertEquals(1, $this->getSmarty()->{$this->methodName}("helloworld.tpl", null, 500)); + $this->assertEquals(1, $this->getSmarty()->clearCompiledTemplate("helloworld.tpl", null, 500)); $this->assertEquals($this->expectFiles($expected), $this->getFiles()); $this->clearFiles(); @@ -354,7 +352,7 @@ class ClearCompiledTest extends PHPUnit_Smarty '[1]ambiguous/case1/foobar.tpl#', '[1]ambiguous/case1/foobar.tpl#compile1', '[1]ambiguous/case1/foobar.tpl#compile2', ); $this->touchFiles(array('helloworld.tpl#compile1', 'helloworld.tpl#compile2'), - 1000); - $this->assertEquals(1, $this->getSmarty()->{$this->methodName}("helloworld.tpl", "compile1", 500)); + $this->assertEquals(1, $this->getSmarty()->clearCompiledTemplate("helloworld.tpl", "compile1", 500)); $this->assertEquals($this->expectFiles($expected), $this->getFiles()); $this->clearFiles(); @@ -384,7 +382,7 @@ class ClearCompiledTest extends PHPUnit_Smarty '[1]ambiguous/case1/foobar.tpl#', '[1]ambiguous/case1/foobar.tpl#compile1', '[1]ambiguous/case1/foobar.tpl#compile2', ); $this->touchFiles(array('helloworld.tpl#compile1'), - 1000); - $this->assertEquals(1, $this->getSmarty()->{$this->methodName}(null, "compile1", 500)); + $this->assertEquals(1, $this->getSmarty()->clearCompiledTemplate(null, "compile1", 500)); $this->assertEquals($this->expectFiles($expected), $this->getFiles()); $this->clearFiles(); @@ -413,7 +411,7 @@ class ClearCompiledTest extends PHPUnit_Smarty 'ambiguous/case1/foobar.tpl#', 'ambiguous/case1/foobar.tpl#compile1', 'ambiguous/case1/foobar.tpl#compile2', '[1]ambiguous/case1/foobar.tpl#', '[1]ambiguous/case1/foobar.tpl#compile1', '[1]ambiguous/case1/foobar.tpl#compile2', ); - $this->assertEquals(1, $this->getSmarty()->{$this->methodName}("helloworld.tpl", "compile1")); + $this->assertEquals(1, $this->getSmarty()->clearCompiledTemplate("helloworld.tpl", "compile1")); $this->assertEquals($this->expectFiles($expected), $this->getFiles()); $this->clearFiles(); @@ -443,7 +441,7 @@ class ClearCompiledTest extends PHPUnit_Smarty 'helloworld2.tpl#', 'helloworld2.tpl#compile1', 'helloworld2.tpl#compile2', '[1]ambiguous/case1/foobar.tpl#', '[1]ambiguous/case1/foobar.tpl#compile1', '[1]ambiguous/case1/foobar.tpl#compile2', ); - $this->assertEquals(3, $this->getSmarty()->{$this->methodName}("ambiguous/case1/foobar.tpl")); + $this->assertEquals(3, $this->getSmarty()->clearCompiledTemplate("ambiguous/case1/foobar.tpl")); $this->assertEquals($this->expectFiles($expected), $this->getFiles()); $this->clearFiles(); diff --git a/tests/UnitTests/SmartyMethodsTests/CompileCheck/CompileCheckTest.php b/tests/UnitTests/SmartyMethodsTests/CompileCheck/CompileCheckTest.php new file mode 100644 index 00000000..2c401b5e --- /dev/null +++ b/tests/UnitTests/SmartyMethodsTests/CompileCheck/CompileCheckTest.php @@ -0,0 +1,139 @@ +setUpSmarty(__DIR__); + $this->smarty->addTemplateDir('./templates_tmp'); + $this->cleanDirs(); + } + + /** + * generate templates + */ + protected function makeFiles() + { + file_put_contents('./templates_tmp/t1.tpl', 'TPL1'); + file_put_contents('./templates_tmp/t2.tpl', 'TPL2'); + file_put_contents('./templates_tmp/base.tpl', '{include file="t1.tpl"}{include file="t2.tpl"}'); + } + /** + * remove generated templates + */ + protected function removeFiles() + { + unlink('./templates_tmp/t1.tpl'); + unlink('./templates_tmp/t2.tpl'); + unlink('./templates_tmp/base.tpl'); + } + + /** + * reset, but leave the files alone + * @return void + */ + private function softResetSmarty() { + $this->smarty = new \Smarty\Smarty(); + $this->smarty->addTemplateDir('./templates_tmp'); + } + + /** + * @group slow + */ + public function testCompileCheckOn0() + { + $this->makeFiles(); + $this->assertEquals('TPL1TPL2', $this->smarty->fetch('base.tpl')); + + $this->softResetSmarty(); + $this->smarty->setCompileCheck(\Smarty\Smarty::COMPILECHECK_ON); + + $this->assertEquals('TPL1TPL2', $this->smarty->fetch('base.tpl')); + } + + /** + * @group slow + */ + public function testCompileCheckOn1() + { + $this->makeFiles(); + $this->assertEquals('TPL1TPL2', $this->smarty->fetch('base.tpl')); + + $this->softResetSmarty(); + $this->smarty->setCompileCheck(\Smarty\Smarty::COMPILECHECK_ON); + + unlink('./templates_tmp/base.tpl'); + sleep(1); + + $this->expectException(\Smarty\Exception::class); + $this->smarty->fetch('base.tpl'); + } + + /** + * @group slow + */ + public function testCompileCheckOn2() + { + $this->makeFiles(); + $this->assertEquals('TPL1TPL2', $this->smarty->fetch('base.tpl')); + + $this->softResetSmarty(); + $this->smarty->setCompileCheck(\Smarty\Smarty::COMPILECHECK_ON); + + sleep(1); + file_put_contents('./templates_tmp/base.tpl', 'hello'); + + $this->assertEquals('hello', $this->smarty->fetch('base.tpl')); + } + + /** + * @group slow + */ + public function testCompileCheckOff0() + { + $this->makeFiles(); + $this->assertEquals('TPL1TPL2', $this->smarty->fetch('base.tpl')); + + $this->softResetSmarty(); + $this->smarty->setCompileCheck(\Smarty\Smarty::COMPILECHECK_OFF); + + $this->assertEquals('TPL1TPL2', $this->smarty->fetch('base.tpl')); + } + + /** + * @group slow + */ + public function testCompileCheckOff1() + { + $this->makeFiles(); + $this->assertEquals('TPL1TPL2', $this->smarty->fetch('base.tpl')); + + $this->softResetSmarty(); + $this->smarty->setCompileCheck(\Smarty\Smarty::COMPILECHECK_OFF); + + unlink('./templates_tmp/base.tpl'); + sleep(1); + + $this->assertEquals('TPL1TPL2', $this->smarty->fetch('base.tpl')); + } + + /** + * @group slow + */ + public function testCompileCheckOff2() + { + $this->makeFiles(); + $this->assertEquals('TPL1TPL2', $this->smarty->fetch('base.tpl')); + + $this->softResetSmarty(); + $this->smarty->setCompileCheck(\Smarty\Smarty::COMPILECHECK_OFF); + + sleep(1); + file_put_contents('./templates_tmp/base.tpl', 'hello'); + + $this->assertEquals('TPL1TPL2', $this->smarty->fetch('base.tpl')); + } + +} diff --git a/tests/UnitTests/TemplateSource/TagTests/BlockPlugin/CompileBlockPluginTest.php b/tests/UnitTests/TemplateSource/TagTests/BlockPlugin/CompileBlockPluginTest.php index c2ad56ee..328cd4c1 100644 --- a/tests/UnitTests/TemplateSource/TagTests/BlockPlugin/CompileBlockPluginTest.php +++ b/tests/UnitTests/TemplateSource/TagTests/BlockPlugin/CompileBlockPluginTest.php @@ -209,7 +209,7 @@ class CompileBlockPluginTest extends PHPUnit_Smarty { $this->smarty->registerFilter('pre', array($this, 'prefilterTest')); $this->smarty->registerPlugin(\Smarty\Smarty::PLUGIN_BLOCK, 'cachetest', 'myblockplugintest2', $cachable); - $this->smarty->compile_id = $compileid; + $this->smarty->setCompileId($compileid); $this->smarty->caching = $caching; $this->smarty->cache_lifetime = 1000; $this->smarty->assign('test', $testNumber); @@ -292,7 +292,7 @@ class CompileBlockPluginTest extends PHPUnit_Smarty $this->makeTemplateFile($file, $code); $this->smarty->setTemplateDir('./templates_tmp'); $this->smarty->registerDefaultPluginHandler('my_block_plugin_handler'); - $this->smarty->compile_id='default'; + $this->smarty->setCompileId('default'); $this->smarty->assign('foo', 'bar'); $this->assertEquals($result, $this->smarty->fetch($file), diff --git a/tests/UnitTests/__shared/resources/resource.extendsall.php b/tests/UnitTests/__shared/resources/resource.extendsall.php index 55b7985b..9ffddc05 100644 --- a/tests/UnitTests/__shared/resources/resource.extendsall.php +++ b/tests/UnitTests/__shared/resources/resource.extendsall.php @@ -35,7 +35,7 @@ class My_Resource_Extendsall extends \Smarty\Resource\ExtendsPlugin continue; } $sources[ $s->uid ] = $s; - $uid .= $s->filepath; + $uid .= $s->uid; $timestamp = $s->timestamp > $timestamp ? $s->timestamp : $timestamp; } catch (Exception $e) { } @@ -48,7 +48,6 @@ class My_Resource_Extendsall extends \Smarty\Resource\ExtendsPlugin reset($sources); $s = current($sources); $source->components = $sources; - $source->filepath = $s->filepath; $source->uid = sha1($uid . $source->getSmarty()->_joined_template_dir); $source->exists = true; $source->timestamp = $timestamp;