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;