From c201ccd3fdc4108691c17c70ff50dc44afcb33af Mon Sep 17 00:00:00 2001 From: Simon Wisselink Date: Sun, 29 Jan 2023 22:02:44 +0100 Subject: [PATCH] WIP --- CHANGELOG.md | 1 + TODO.txt | 7 +- src/Cacheresource/Base.php | 4 +- src/Cacheresource/Custom.php | 15 +- src/Cacheresource/File.php | 52 +-- src/Cacheresource/KeyValueStore.php | 13 +- src/CodeFrame/Base.php | 19 +- src/CodeFrame/Cached.php | 24 +- src/CodeFrame/Compiled.php | 7 + src/Compile/Tag/FunctionClose.php | 2 - src/Compiler/CodeFrame.php | 172 +++---- src/Compiler/CompactPrinter.php | 10 + src/Compiler/Configfile.php | 29 +- src/Compiler/Template.php | 20 +- src/Data.php | 2 +- src/Debug.php | 4 +- src/Runtime/TplFunctionRuntime.php | 62 --- src/Smarty.php | 398 ++++++++++++++-- src/Template.php | 233 +++------- src/Template/Cached.php | 312 +++++-------- src/Template/Compiled.php | 439 ++++++++++-------- src/Template/GeneratedPhpFile.php | 153 ------ src/TemplateBase.php | 344 -------------- tests/PHPUnit_Smarty.php | 32 +- .../templates_c/.gitignore | 2 - .../File/CacheResourceFileTest.php | 48 +- .../_shared/CacheResourceTestCommon.php | 249 +++++----- .../ResourceMysqlPluginTest.php | 4 +- .../ResourceTests/File/FileResourceTest.php | 6 +- .../FileIndexed/FileResourceIndexedTest.php | 4 +- .../Stream/StreamResourceTest.php | 6 +- .../String/StringResourceTest.php | 4 +- .../SmartyMethodsTests/Append/AppendTest.php | 4 - .../ClearCompiledTest.php | 22 +- 34 files changed, 1148 insertions(+), 1555 deletions(-) create mode 100644 src/CodeFrame/Compiled.php create mode 100644 src/Compiler/CompactPrinter.php delete mode 100644 src/Template/GeneratedPhpFile.php delete mode 100644 tests/UnitTests/A_2/UndefinedTemplateVar/templates_c/.gitignore diff --git a/CHANGELOG.md b/CHANGELOG.md index 06b5ebd3..e4d0cc96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,7 @@ 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->use_sub_dirs`. Cached files are now automatically stored in subdirs for maximum performance. ### 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 d01b2fdf..53c16f0a 100644 --- a/TODO.txt +++ b/TODO.txt @@ -7,9 +7,8 @@ - Re-introduce merge_compiled_includes and the {include inline} attribute? -## Output buffering -- Fix ob_ output buffering commands being scattered around the codebase - +## Beatify output +- strip tags from generated output ## Review public static vars - such as _CHARSET and _IS_WINDOWS @@ -28,8 +27,6 @@ ## Plugin system - fix template security checks in one place in compiler -## Beatify output -- compiled templates could be proper classes, possibly using [nette/php-generator](https://packagist.org/packages/nette/php-generator) ## Documentation - beautify and review docs, possibly using [ diff --git a/src/Cacheresource/Base.php b/src/Cacheresource/Base.php index 54a14192..5bcf843f 100644 --- a/src/Cacheresource/Base.php +++ b/src/Cacheresource/Base.php @@ -38,14 +38,12 @@ abstract class Base * * @param Template $_template template object * @param Cached|null $cached cached object - * @param boolean $update flag if called because cache update * * @return boolean true or false if the cached content does not exist */ abstract public function process( Template $_template, - Cached $cached = null, - $update = false + Cached $cached = null ); /** diff --git a/src/Cacheresource/Custom.php b/src/Cacheresource/Custom.php index c049246c..6081da87 100644 --- a/src/Cacheresource/Custom.php +++ b/src/Cacheresource/Custom.php @@ -9,6 +9,7 @@ namespace Smarty\Cacheresource; */ +use Smarty\Exception; use Smarty\Smarty; use Smarty\Template; use Smarty\Template\Cached; @@ -124,23 +125,13 @@ abstract class Custom extends Base $cached->content, $timestamp ); - $cached->timestamp = isset($timestamp) ? $timestamp : false; + $cached->timestamp = $timestamp ?? false; $cached->exists = !!$cached->timestamp; } - /** - * Read the cached template and process the header - * - * @param Template $_smarty_tpl do not change variable name, is used by compiled template - * @param Cached|null $cached cached object - * @param boolean $update flag if called because cache update - * - * @return boolean true or false if the cached content does not exist - */ public function process( Template $_smarty_tpl, - \Smarty\Template\Cached $cached = null, - $update = false + \Smarty\Template\Cached $cached = null ) { if (!$cached) { $cached = $_smarty_tpl->getCached(); diff --git a/src/Cacheresource/File.php b/src/Cacheresource/File.php index 54070013..a2cebee8 100644 --- a/src/Cacheresource/File.php +++ b/src/Cacheresource/File.php @@ -4,6 +4,7 @@ namespace Smarty\Cacheresource; use RecursiveDirectoryIterator; use RecursiveIteratorIterator; +use Smarty\Exception; use Smarty\Smarty; use Smarty\Template; use Smarty\Template\Cached; @@ -35,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); $cached->filepath = $smarty->getCacheDir(); if (isset($_template->cache_id)) { @@ -46,21 +47,17 @@ class File extends Base ), array( '_', - $_compile_dir_sep + DIRECTORY_SEPARATOR ), - $_template->cache_id - ) . $_compile_dir_sep; + $_template->cache_id + ) . DIRECTORY_SEPARATOR; } if (isset($_template->compile_id)) { - $cached->filepath .= preg_replace('![^\w]+!', '_', $_template->compile_id) . $_compile_dir_sep; - } - // if use_sub_dirs, break file into directories - if ($smarty->use_sub_dirs) { - $cached->filepath .= $_filepath[ 0 ] . $_filepath[ 1 ] . DIRECTORY_SEPARATOR . $_filepath[ 2 ] . - $_filepath[ 3 ] . - DIRECTORY_SEPARATOR . - $_filepath[ 4 ] . $_filepath[ 5 ] . DIRECTORY_SEPARATOR; + $cached->filepath .= preg_replace('![^\w]+!', '_', $_template->compile_id) . DIRECTORY_SEPARATOR; } + // break file into directories + $cached->filepath .= $_filepath[0] . $_filepath[1] . DIRECTORY_SEPARATOR; + $cached->filepath .= $_filepath; $basename = $source->getBasename(); if (!empty($basename)) { @@ -91,27 +88,11 @@ class File extends Base } } - /** - * Read the cached template and process its header - * - * @param Template $_smarty_tpl do not change variable name, is used by compiled template - * @param Cached|null $cached cached object - * @param bool $update flag if called because cache update - * - * @return boolean true or false if the cached content does not exist - */ public function process( Template $_smarty_tpl, - Cached $cached = null, - $update = false + Cached $cached = null ) { - $_smarty_tpl->getCached()->setValid(false); - if ($update && defined('HHVM_VERSION')) { - eval('?>' . file_get_contents($_smarty_tpl->getCached()->filepath)); - return true; - } else { - return @include $_smarty_tpl->getCached()->filepath; - } + return @include $_smarty_tpl->getCached()->filepath; } /** @@ -186,8 +167,7 @@ class File extends Base { $_cache_id = isset($cache_id) ? preg_replace('![^\w\|]+!', '_', $cache_id) : null; $_compile_id = isset($compile_id) ? preg_replace('![^\w]+!', '_', $compile_id) : null; - $_dir_sep = $smarty->use_sub_dirs ? '/' : '^'; - $_compile_id_offset = $smarty->use_sub_dirs ? 3 : 0; + $_compile_id_offset = 1; $_dir = $smarty->getCacheDir(); if ($_dir === '/') { //We should never want to delete this! return 0; @@ -196,10 +176,8 @@ class File extends Base if (isset($_cache_id)) { $_cache_id_parts = explode('|', $_cache_id); $_cache_id_parts_count = count($_cache_id_parts); - if ($smarty->use_sub_dirs) { - foreach ($_cache_id_parts as $id_part) { - $_dir .= $id_part . '/'; - } + foreach ($_cache_id_parts as $id_part) { + $_dir .= $id_part . DIRECTORY_SEPARATOR; } } if (isset($resource_name)) { @@ -235,7 +213,7 @@ class File extends Base if (substr($_filepath, -4) !== '.php') { continue; } - $_parts = explode($_dir_sep, str_replace('\\', '/', substr($_filepath, $_dir_length))); + $_parts = explode(DIRECTORY_SEPARATOR, str_replace('\\', '/', substr($_filepath, $_dir_length))); $_parts_count = count($_parts); // check name if (isset($resource_name)) { diff --git a/src/Cacheresource/KeyValueStore.php b/src/Cacheresource/KeyValueStore.php index 733d2776..3e85a583 100644 --- a/src/Cacheresource/KeyValueStore.php +++ b/src/Cacheresource/KeyValueStore.php @@ -2,6 +2,7 @@ namespace Smarty\Cacheresource; +use Smarty\Exception; use Smarty\Smarty; use Smarty\Template; use Smarty\Template\Cached; @@ -92,19 +93,9 @@ abstract class KeyValueStore extends Base $cached->exists = !!$cached->timestamp; } - /** - * Read the cached template and process the header - * - * @param Template $_smarty_tpl do not change variable name, is used by compiled template - * @param Cached|null $cached cached object - * @param boolean $update flag if called because cache update - * - * @return boolean true or false if the cached content does not exist - */ public function process( Template $_smarty_tpl, - Cached $cached = null, - $update = false + Cached $cached = null ) { if (!$cached) { $cached = $_smarty_tpl->getCached(); diff --git a/src/CodeFrame/Base.php b/src/CodeFrame/Base.php index 061244e5..d9acd471 100644 --- a/src/CodeFrame/Base.php +++ b/src/CodeFrame/Base.php @@ -4,22 +4,5 @@ namespace Smarty\CodeFrame; abstract class Base { - /** - * @var \Smarty\Smarty - */ - private $smarty; - - public function __construct(\Smarty\Smarty $smarty) { - $this->smarty = $smarty; - } - - public function isFresh(\Smarty\Template $template): bool { - return $template->isFresh($this->getProperties(), $this->isCache()); - } - - protected function isCache(): bool { - return false; - } - - abstract protected function getProperties(): array; + abstract public function renderContent(\Smarty\Template $_smarty_tpl): void; } \ No newline at end of file diff --git a/src/CodeFrame/Cached.php b/src/CodeFrame/Cached.php index d08b1001..1e40afb0 100644 --- a/src/CodeFrame/Cached.php +++ b/src/CodeFrame/Cached.php @@ -4,7 +4,29 @@ namespace Smarty\CodeFrame; abstract class Cached extends Base { - protected function isCache(): bool { + // @TODO move + public function isFresh(\Smarty\Template $template): bool { + + $properties = $this->getProperties(); + + // on cache resources other than file check version stored in cache code + if (\Smarty\Smarty::SMARTY_VERSION !== $properties['version']) { + return false; + } + + if ($template->getSmarty()->getCompileCheck() === \Smarty\Smarty::COMPILECHECK_ON) { + if (!$this->checkFileDependencies($properties['file_dependency'], $template)) { + return false; + } + } + + // CACHING_LIFETIME_SAVED cache expiry has to be validated here since otherwise we'd define the unifunc + if ($template->caching === \Smarty\Smarty::CACHING_LIFETIME_SAVED && $properties['cache_lifetime'] >= 0 + && (time() > ($this->timestamp + $properties['cache_lifetime'])) + ) { + return false; + } + return true; } } \ No newline at end of file diff --git a/src/CodeFrame/Compiled.php b/src/CodeFrame/Compiled.php new file mode 100644 index 00000000..0fa25989 --- /dev/null +++ b/src/CodeFrame/Compiled.php @@ -0,0 +1,7 @@ +getParentCompiler(); - $parentCompiler->tpl_function[$_name]['compiled_filepath'] = - $parentCompiler->getTemplate()->getCompiled()->filepath; $parentCompiler->tpl_function[$_name]['uid'] = $compiler->getTemplate()->getSource()->uid; $_parameter = $_attr; unset($_parameter['name']); diff --git a/src/Compiler/CodeFrame.php b/src/Compiler/CodeFrame.php index 10544752..73f11fd7 100644 --- a/src/Compiler/CodeFrame.php +++ b/src/Compiler/CodeFrame.php @@ -2,6 +2,7 @@ namespace Smarty\Compiler; +use Nette\PhpGenerator\Dumper; use Smarty\Exception; /** @@ -32,7 +33,6 @@ class CodeFrame * @param string $content optional template content * @param string $functions compiled template function and block code * @param bool $cache flag for cache file - * @param Template|null $compiler * * @return string * @throws Exception @@ -40,106 +40,122 @@ class CodeFrame public function create( $content = '', $functions = '', - $cache = false, - \Smarty\Compiler\Template $compiler = null + $cache = false ) { - $className = ($cache ? 'Cached' : 'Compiled') . str_replace(array('.', ','), '_', uniqid('', true)); $properties = []; $properties['version'] = \Smarty\Smarty::SMARTY_VERSION; + $properties['codeFrameClass'] = '__CodeFrame_' . str_replace(array('.', ','), '_', uniqid('', true)); + if (!$cache) { + $properties[ 'has_nocache_code' ] = $this->_template->getCompiled()->getNocacheCode(); + $properties[ 'file_dependency' ] = $this->_template->getCompiled()->file_dependency; + $properties[ 'includes' ] = $this->_template->getCompiled()->includes; + } else { + $properties[ 'file_dependency' ] = $this->_template->getCached()->file_dependency; + $properties[ 'cache_lifetime' ] = $this->_template->cache_lifetime; + } $file = new \Nette\PhpGenerator\PhpFile; $file->addComment('This file is auto-generated.'); - $class = $file->addClass($className); + $file->addComment($functions); //@TODO + $output = (string) $file; + $dumper = new Dumper; + + $output .= 'if (!class_exists(' . $dumper->dump($properties['codeFrameClass']) . ')) {' . "\n"; + $output .= $this->generateCodeFrameClass($properties['codeFrameClass'], $cache, $content); + $output .= "}\n"; + $output .= 'return ' . $dumper->dump($properties) . ";\n"; + + return $output; + } + + private function revertPHPTags(string $content) { + + static $PHPSTART = '<' . '?php'; + static $PHPEND = '?' . '>'; + + //\<\?\php echo "
hello world";\?\> + if (substr($content, 0, 5) === $PHPSTART + && substr($content, -3) === $PHPEND . "\n" + ) { + return substr($content, 5, -3); + } + + if (false) { + // remove unneeded PHP tags + if (preg_match('/\s*\?>[\n]?<\?php\s*/', $content)) { + $curr_split = preg_split( + '/\s*\?>[\n]?<\?php\s*/', + $content + ); + preg_match_all( + '/\s*\?>[\n]?<\?php\s*/', + $content, + $curr_parts + ); + $content = ''; + foreach ($curr_split as $idx => $curr_output) { + $content .= $curr_output; + if (isset($curr_parts[ 0 ][ $idx ])) { + $content .= "\n"; + } + } + } + if (preg_match('/\?>\s*$/', $content)) { + $curr_split = preg_split( + '/\?>\s*$/', + $content + ); + $content = ''; + foreach ($curr_split as $idx => $curr_output) { + $content .= $curr_output; + } + } + } + + return $PHPEND . $content . $PHPSTART; + } + + /** + * @param $codeFrameClass + * @param bool $cache + * @param string $content + * + * @return string + */ + private function generateCodeFrameClass($codeFrameClass, bool $cache, string $content): string { + $class = new \Nette\PhpGenerator\ClassType($codeFrameClass); $class - ->setFinal() - ->setExtends($cache ? \Smarty\CodeFrame\Cached::class : \Smarty\CodeFrame\Base::class) + ->setExtends($cache ? \Smarty\CodeFrame\Cached::class : \Smarty\CodeFrame\Compiled::class) ->addComment(sprintf( "Created on %s from '%s'", - $properties[ 'version' ], date("Y-m-d H:i:s"), str_replace('*/', '* /', $this->_template->getSource()->filepath) )); - $dumper = new \Nette\PhpGenerator\Dumper; - - // build property code - $properties[ 'unifunc' ] = 'content_' . str_replace(array('.', ','), '_', uniqid('', true)); - if (!$cache) { - $properties[ 'has_nocache_code' ] = $this->_template->getCompiled()->getNocacheCode(); - $properties[ 'file_dependency' ] = $this->_template->getCompiled()->file_dependency; - $properties[ 'includes' ] = $this->_template->getCompiled()->includes; - } else { - $properties[ 'has_nocache_code' ] = $this->_template->getCached()->getNocacheCode(); - $properties[ 'file_dependency' ] = $this->_template->getCached()->file_dependency; - $properties[ 'cache_lifetime' ] = $this->_template->cache_lifetime; - } - - $class->addMethod('getProperties') - ->setProtected() - ->setReturnType('array') // method return type - ->setBody('return ' . $dumper->dump($properties) . ';'); - - $output = (string) $file; - - $output .= sprintf( - "\n/* Created on %s\n from '%s' */\n\n", - $properties[ 'version' ], - date("Y-m-d H:i:s"), - str_replace('*/', '* /', $this->_template->getSource()->filepath) - ); - $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"; - if (!$cache && !empty($compiler->tpl_function)) { + /* @TODO + * if (!$cache && !empty($compiler->tpl_function)) { $output .= '$_smarty_tpl->getSmarty()->getRuntime(\'TplFunction\')->registerTplFunctions($_smarty_tpl, '; $output .= var_export($compiler->tpl_function, true); $output .= ");\n"; } - if ($cache && $this->_template->getSmarty()->hasRuntime('TplFunction')) { + if ($cache && $this->_template->getSmarty()->hasRuntime('TplFunction')) { if ($tplfunctions = $this->_template->getSmarty()->getRuntime('TplFunction')->getTplFunction($this->_template)) { $output .= "\$_smarty_tpl->getSmarty()->getRuntime('TplFunction')->registerTplFunctions(\$_smarty_tpl, " . var_export($tplfunctions, true) . ");\n"; } } - $output .= "?>"; - $output .= $content; - $output .= ""; - $output .= $functions; - $output .= "[\n]?<\?php\s*/', $output)) { - $curr_split = preg_split( - '/\s*\?>[\n]?<\?php\s*/', - $output - ); - preg_match_all( - '/\s*\?>[\n]?<\?php\s*/', - $output, - $curr_parts - ); - $output = ''; - foreach ($curr_split as $idx => $curr_output) { - $output .= $curr_output; - if (isset($curr_parts[ 0 ][ $idx ])) { - $output .= "\n"; - } - } - } - if (preg_match('/\?>\s*$/', $output)) { - $curr_split = preg_split( - '/\?>\s*$/', - $output - ); - $output = ''; - foreach ($curr_split as $idx => $curr_output) { - $output .= $curr_output; - } - } - return $output; - } +*/ + $method = $class->addMethod('renderContent'); + $method->setPublic() + ->addParameter('_smarty_tpl')->setType(\Smarty\Template::class); + + $method->setReturnType('void') // method return type + ->setBody($this->revertPHPTags($content)); + + return (new CompactPrinter())->printClass($class); + } + } diff --git a/src/Compiler/CompactPrinter.php b/src/Compiler/CompactPrinter.php new file mode 100644 index 00000000..ff32b057 --- /dev/null +++ b/src/Compiler/CompactPrinter.php @@ -0,0 +1,10 @@ +config_data['vars'] = []; } + /** + * Method to compile a Smarty template + * + * @param \Smarty\Template $template template object to compile + * + * @return string code + * @throws Exception + */ + public function compileTemplate(\Smarty\Template $template) { + return $template->createCodeFrame( + $this->compileTemplateSource($template), + '', + false + ); + } + /** * Method to compile Smarty config source. * @@ -80,7 +97,7 @@ class Configfile extends BaseCompiler { * @return bool true if compiling succeeded, false if it failed * @throws \Smarty\Exception */ - public function compileTemplate(Template $template) { + private function compileTemplateSource(Template $template) { $this->template = $template; $this->template->getCompiled()->file_dependency[$this->template->getSource()->uid] = [ @@ -133,16 +150,10 @@ class Configfile extends BaseCompiler { if ($this->smarty->debugging) { $this->smarty->getDebug()->end_compile($this->template); } - // template header code - $template_header = sprintf( - "\n", - \Smarty\Smarty::SMARTY_VERSION, - date("Y-m-d H:i:s"), - str_replace('*/', '* /', $this->template->getSource()->filepath) - ); + $code = 'parent->assignConfigVars(' . var_export($this->config_data, true) . ', $_smarty_tpl->getValue("sections")); ?>'; - return $template_header . $this->template->createCodeFrame($code); + return $code; } /** diff --git a/src/Compiler/Template.php b/src/Compiler/Template.php index 9bf22fc8..5ed20dff 100644 --- a/src/Compiler/Template.php +++ b/src/Compiler/Template.php @@ -93,20 +93,6 @@ class Template extends BaseCompiler { */ private $template = null; - /** - * merged included sub template data - * - * @var array - */ - public $mergedSubTemplatesData = []; - - /** - * merged sub template code - * - * @var array - */ - public $mergedSubTemplatesCode = []; - /** * source line offset for error messages * @@ -358,10 +344,8 @@ class Template extends BaseCompiler { public function compileTemplate(\Smarty\Template $template) { return $template->createCodeFrame( $this->compileTemplateSource($template), - $this->smarty->runPostFilters($this->blockOrFunctionCode, $this->template) . - join('', $this->mergedSubTemplatesCode), - false, - $this + $this->smarty->runPostFilters($this->blockOrFunctionCode, $this->template), + false ); } diff --git a/src/Data.php b/src/Data.php index cd4fa3e7..a809a591 100644 --- a/src/Data.php +++ b/src/Data.php @@ -459,7 +459,7 @@ class Data $template->caching = Smarty::CACHING_OFF; $template->assign('sections', (array) $sections ?? []); // trigger a call to $this->assignConfigVars - $template->getCompiled(true)->render($template); + $template->getCompiled()->fetch(); return $this; } diff --git a/src/Debug.php b/src/Debug.php index 4591ac46..bab05003 100644 --- a/src/Debug.php +++ b/src/Debug.php @@ -203,7 +203,6 @@ class Debug extends Data $debObj = new \Smarty\Smarty(); // copy the working dirs from application $debObj->setCompileDir($smarty->getCompileDir()); - $debObj->compile_check = \Smarty::COMPILECHECK_ON; $debObj->security_policy = null; $debObj->debugging = false; $debObj->debugging_ctrl = 'NONE'; @@ -213,8 +212,7 @@ 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; diff --git a/src/Runtime/TplFunctionRuntime.php b/src/Runtime/TplFunctionRuntime.php index 905defb8..93e7c6b6 100644 --- a/src/Runtime/TplFunctionRuntime.php +++ b/src/Runtime/TplFunctionRuntime.php @@ -42,13 +42,6 @@ class TplFunctionRuntime { $this->restoreTemplateVariables($tpl, $name); return; } - // try to load template function dynamically - if ($this->addTplFuncToCache($tpl, $name, $function)) { - $this->saveTemplateVariables($tpl, $name); - $function($tpl, $params); - $this->restoreTemplateVariables($tpl, $name); - return; - } } throw new \Smarty\Exception("Unable to find template function '{$name}'"); } @@ -91,61 +84,6 @@ class TplFunctionRuntime { } } - /** - * Add template function to cache file for nocache calls - * - * @param Template $tpl - * @param string $_name template function name - * @param string $_function PHP function name - * - * @return bool - * @throws Exception - */ - private function addTplFuncToCache(Template $tpl, $_name, $_function) { - $funcParam = $tpl->tplFunctions[$_name]; - if (is_file($funcParam['compiled_filepath'])) { - // read compiled file - $code = file_get_contents($funcParam['compiled_filepath']); - // grab template function - if (preg_match("/\/\* {$_function} \*\/([\S\s]*?)\/\*\/ {$_function} \*\//", $code, $match)) { - // grab source info from file dependency - preg_match("/\s*'{$funcParam['uid']}'([\S\s]*?)\),/", $code, $match1); - unset($code); - // make PHP function known - eval($match[0]); - if (function_exists($_function)) { - - // Some magic code existed here, testing if the cached property had been set - // and then bubbling up until it found a parent template that had the cached property. - // This is no longer possible, so somehow this might break. - - // add template function code to cache file - $content = $tpl->getCached()->readCache($tpl); - if ($content) { - // check if we must update file dependency - if (!preg_match("/'{$funcParam['uid']}'(.*?)'nocache_hash'/", $content, $match2)) { - $content = preg_replace("/('file_dependency'(.*?)\()/", "\\1{$match1[0]}", $content); - } - $tpl->getCached()->writeCache( - $tpl, - preg_replace('/\s*\?>\s*$/', "\n", $content) . - "\n" . preg_replace( - [ - '/^\s*<\?php\s+/', - '/\s*\?>\s*$/', - ], - "\n", - $match[0] - ) - ); - } - return true; - } - } - } - return false; - } - /** * Save current template variables on stack * diff --git a/src/Smarty.php b/src/Smarty.php index 48fb0d47..ed0b0089 100644 --- a/src/Smarty.php +++ b/src/Smarty.php @@ -191,12 +191,12 @@ class Smarty extends \Smarty\TemplateBase */ public $force_compile = false; - /** - * use sub dirs for compiled/cached files? - * - * @var boolean - */ - public $use_sub_dirs = false; + /** + * Check template for modifications? + * Set to Smarty::COMPILECHECK_OFF when templates won't change in production. + * @var int + */ + public $compile_check = self::COMPILECHECK_ON; /** * allow ambiguous resources (that are made unique by the resource handler) @@ -238,11 +238,11 @@ class Smarty extends \Smarty\TemplateBase * * @var array string */ - public $literals = array(); + private $literals = array(); /** * class name - * This should be instance of \Smarty\Security. + * This should be an instance of \Smarty\Security. * * @var string * @see \Smarty\Security @@ -579,7 +579,7 @@ class Smarty extends \Smarty\TemplateBase * @param string $resource_name template name * * @return bool status - * @throws \Smarty\Exception + * @throws Exception */ public function templateExists($resource_name) { @@ -594,7 +594,7 @@ class Smarty extends \Smarty\TemplateBase * @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 + * @throws Exception */ public function enableSecurity($security_class = null) { @@ -749,7 +749,7 @@ class Smarty extends \Smarty\TemplateBase * @param bool $cacheable if true (default) this function is cache able * * @return $this - * @throws \Smarty\Exception + * @throws Exception * @link https://www.smarty.net/docs/en/api.register.plugin.tpl * * @api Smarty::registerPlugin() @@ -854,7 +854,7 @@ class Smarty extends \Smarty\TemplateBase { 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); + 'proceed to call Smarty::addPluginsDir..', E_USER_DEPRECATED); $this->extensions = array_filter( $this->extensions, @@ -1044,7 +1044,7 @@ class Smarty extends \Smarty\TemplateBase $nameIsDotted = !empty($name) && $name[0] === '.' && ($name[1] === '.' || $name[1] === '/'); $id_parts[] = $type; - $id_parts[] = $this->getSmarty()->_joined_template_dir; + $id_parts[] = $this->_joined_template_dir; // handle relative template names if ($baseFilePath && $nameIsDotted) { @@ -1111,14 +1111,6 @@ class Smarty extends \Smarty\TemplateBase return $realpath !== false ? $parts[ 'root' ] . $path : str_ireplace(getcwd(), '.', $parts[ 'root' ] . $path); } - /** - * @param boolean $use_sub_dirs - */ - public function setUseSubDirs($use_sub_dirs) - { - $this->use_sub_dirs = $use_sub_dirs; - } - /** * @param int $error_reporting */ @@ -1271,7 +1263,7 @@ class Smarty extends \Smarty\TemplateBase /** * Get Smarty object - * // @TODO this is silly, remove? + * This is required for methods defined in base class Data trying to find Smarty * @return Smarty */ public function getSmarty() @@ -1345,7 +1337,7 @@ class Smarty extends \Smarty\TemplateBase * @param string $type resource type * * @return int number of cache files deleted - * @throws \Smarty\Exception + * @throws Exception * @link https://www.smarty.net/docs/en/api.clear.cache.tpl * * @api Smarty::clearCache() @@ -1383,10 +1375,12 @@ class Smarty extends \Smarty\TemplateBase * @param integer $exp_time expiration time * * @return int number of template files deleted - * @throws \Smarty\Exception + * @throws Exception *@link https://www.smarty.net/docs/en/api.clear.compiled.template.tpl * * @api Smarty::clearCompiledTemplate() + * + * @TODO can we remove this? It probably won't work anymore for specific files anyway */ public function clearCompiledTemplate($resource_name = null, $compile_id = null, $exp_time = null) { @@ -1395,7 +1389,6 @@ class Smarty extends \Smarty\TemplateBase return 0; } $_compile_id = isset($compile_id) ? preg_replace('![^\w]+!', '_', $compile_id) : null; - $_dir_sep = $this->use_sub_dirs ? DIRECTORY_SEPARATOR : '^'; if (isset($resource_name)) { $_save_stat = $this->caching; $this->caching = \Smarty\Smarty::CACHING_OFF; @@ -1412,11 +1405,11 @@ class Smarty extends \Smarty\TemplateBase $_resource_part_2_length = strlen($_resource_part_2); } $_dir = $_compile_dir; - if ($this->use_sub_dirs && isset($_compile_id)) { - $_dir .= $_compile_id . $_dir_sep; + if (isset($_compile_id)) { + $_dir .= $_compile_id . DIRECTORY_SEPARATOR; } if (isset($_compile_id)) { - $_compile_id_part = $_compile_dir . $_compile_id . $_dir_sep; + $_compile_id_part = $_compile_dir . $_compile_id . DIRECTORY_SEPARATOR; $_compile_id_part_length = strlen($_compile_id_part); } $_count = 0; @@ -1614,7 +1607,7 @@ class Smarty extends \Smarty\TemplateBase * @param string $content * * @throws \Exception - * @throws \Smarty\Exception + * @throws Exception */ public function cacheModifiedCheck(Template\Cached $cached, Template $_template, $content) { @@ -1832,8 +1825,18 @@ class Smarty extends \Smarty\TemplateBase error_reporting($_error_reporting); throw new Exception("unable to write file {$_filepath}"); } + // set file permissions @chmod($_filepath, 0666 & ~umask()); + + if (function_exists('opcache_invalidate') + && (!function_exists('ini_get') || strlen(ini_get("opcache.restrict_api")) < 1) + ) { + opcache_invalidate($_filepath, true); + } elseif (function_exists('apc_compile_file')) { + apc_compile_file($_filepath); + } + error_reporting($_error_reporting); return true; } @@ -1869,7 +1872,7 @@ class Smarty extends \Smarty\TemplateBase ); } - throw new \Smarty\Exception('Trying to load invalid runtime ' . $type); + throw new Exception('Trying to load invalid runtime ' . $type); } /** @@ -1883,7 +1886,7 @@ class Smarty extends \Smarty\TemplateBase try { $this->getRuntime($type); return true; - } catch (\Smarty\Exception $e) { + } catch (Exception $e) { return false; } } @@ -1902,7 +1905,7 @@ class Smarty extends \Smarty\TemplateBase * @param string $name filter name * * @return bool - * @throws \Smarty\Exception + * @throws Exception * @api Smarty::loadFilter() * @link https://www.smarty.net/docs/en/api.load.filter.tpl * @@ -1955,7 +1958,7 @@ class Smarty extends \Smarty\TemplateBase * @param string $name filter name * * @return TemplateBase - * @throws \Smarty\Exception + * @throws Exception * @api Smarty::unloadFilter() * * @link https://www.smarty.net/docs/en/api.unload.filter.tpl @@ -2057,7 +2060,7 @@ class Smarty extends \Smarty\TemplateBase * @param string|null $name optional filter name * * @return TemplateBase - * @throws \Smarty\Exception + * @throws Exception * @link https://www.smarty.net/docs/en/api.register.filter.tpl * * @api Smarty::registerFilter() @@ -2118,7 +2121,7 @@ class Smarty extends \Smarty\TemplateBase * @param callback|string $name the name previously used in ::registerFilter * * @return TemplateBase - * @throws \Smarty\Exception + * @throws Exception * @api Smarty::unregisterFilter() * * @link https://www.smarty.net/docs/en/api.unregister.filter.tpl @@ -2237,7 +2240,7 @@ class Smarty extends \Smarty\TemplateBase * @param mixed $compile_id compile id to be used with this template * * @throws \Exception - * @throws \Smarty\Exception + * @throws Exception */ public function display($template = null, $cache_id = null, $compile_id = null) { return $this->returnOrCreateTemplate($template, $cache_id, $compile_id)->display(); @@ -2253,7 +2256,7 @@ class Smarty extends \Smarty\TemplateBase * * @return bool cache status * @throws \Exception - * @throws \Smarty\Exception + * @throws Exception * @link https://www.smarty.net/docs/en/api.is.cached.tpl * * @api Smarty::isCached() @@ -2279,5 +2282,326 @@ class Smarty extends \Smarty\TemplateBase return $template; } + /** + * @return int + */ + public function getCompileCheck(): int { + return $this->compile_check; + } + + /** + * @param int $compile_check + */ + public function setCompileCheck($compile_check) { + $this->compile_check = (int)$compile_check; + } + + /** + * @var Debug + */ + private $debug; + + /** + * Registers object to be used in templates + * + * @param string $object_name + * @param object $object the referenced PHP object to register + * @param array $allowed_methods_properties list of allowed methods (empty = all) + * @param bool $format smarty argument format, else traditional + * @param array $block_methods list of block-methods + * + * @return Smarty + * @throws Exception + * @link https://www.smarty.net/docs/en/api.register.object.tpl + * + * @api Smarty::registerObject() + */ + public function registerObject( + $object_name, + $object, + $allowed_methods_properties = [], + $format = true, + $block_methods = [] + ): Smarty { + // test if allowed methods callable + if (!empty($allowed_methods_properties)) { + foreach ((array)$allowed_methods_properties as $method) { + if (!is_callable([$object, $method]) && !property_exists($object, $method)) { + throw new Exception("Undefined method or property '$method' in registered object"); + } + } + } + // test if block methods callable + if (!empty($block_methods)) { + foreach ((array)$block_methods as $method) { + if (!is_callable([$object, $method])) { + throw new Exception("Undefined method '$method' in registered object"); + } + } + } + // register the object + $this->registered_objects[$object_name] = + [$object, (array)$allowed_methods_properties, (boolean)$format, (array)$block_methods]; + return $this; + } + + /** + * Registers plugin to be used in templates + * + * @param string $object_name name of object + * + * @return Smarty + * @api Smarty::unregisterObject() + * @link https://www.smarty.net/docs/en/api.unregister.object.tpl + */ + public function unregisterObject($object_name): Smarty { + if (isset($this->registered_objects[$object_name])) { + unset($this->registered_objects[$object_name]); + } + return $this; + } + + + /** + * creates a data object + * + * @param Data|null $parent next higher level of Smarty variables + * @param null $name optional data block name + * + * @return Data data object + * @throws Exception + * @api Smarty::createData() + * @link https://www.smarty.net/docs/en/api.create.data.tpl + * + */ + public function createData(Data $parent = null, $name = null): Data { + $dataObj = new Data($this, $this, $name); + if ($this->debugging) { + $this->getDebug()->register_data($dataObj); + } + return $dataObj; + } + + /** + * return name of debugging template + * + * @return string|null + * @api Smarty::getDebugTemplate() + */ + public function getDebugTemplate(): ?string { + return $this->debug_tpl; + } + + /** + * @return Debug + */ + public function getDebug(): Debug { + if (!isset($this->debug)) { + $this->debug = new \Smarty\Debug(); + } + return $this->debug; + } + + + /** + * return a reference to a registered object + * + * @param string $object_name object name + * + * @return object + * @throws Exception if no such object is found + * @link https://www.smarty.net/docs/en/api.get.registered.object.tpl + * + * @api Smarty::getRegisteredObject() + */ + public function getRegisteredObject($object_name): object { + if (!isset($this->registered_objects[$object_name])) { + throw new Exception("'$object_name' is not a registered object"); + } + if (!is_object($this->registered_objects[$object_name][0])) { + throw new Exception("registered '$object_name' is not an object"); + } + return $this->registered_objects[$object_name][0]; + } + + /** + * Get literals + * + * @return array list of literals + * @api Smarty::getLiterals() + * + */ + public function getLiterals(): array { + return $this->literals; + } + + /** + * Add literals + * + * @param array|string $literals literal or list of literals + * to addto add + * + * @return Smarty + * @throws Exception + * @api Smarty::addLiterals() + * + */ + public function addLiterals($literals = null): Smarty { + if (isset($literals)) { + $this->_setLiterals((array)$literals); + } + return $this; + } + + /** + * Set literals + * + * @param array|string $literals literal or list of literals to set + * + * @return Smarty + * @throws Exception + * @api Smarty::setLiterals() + */ + public function setLiterals($literals = null): Smarty { + $this->literals = []; + if (!empty($literals)) { + $this->_setLiterals((array)$literals); + } + return $this; + } + + /** + * common setter for literals for easier handling of duplicates the + * Smarty::$literals array gets filled with identical key values + * + * @param array $literals + * + * @throws Exception + */ + private function _setLiterals(array $literals) { + $literals = array_combine($literals, $literals); + $error = isset($literals[$this->getLeftDelimiter()]) ? [$this->getLeftDelimiter()] : []; + $error = isset($literals[$this->getRightDelimiter()]) ? $error[] = $this->getRightDelimiter() : $error; + if (!empty($error)) { + throw new Exception( + 'User defined literal(s) "' . $error . + '" may not be identical with left or right delimiter' + ); + } + $this->literals = array_merge($this->literals, (array)$literals); + } + + /** + * Registers static classes to be used in templates + * + * @param string $class_name + * @param string $class_impl the referenced PHP class to + * register + * + * @return Smarty + * @throws Exception + * @api Smarty::registerClass() + * @link https://www.smarty.net/docs/en/api.register.class.tpl + * + */ + public function registerClass($class_name, $class_impl): Smarty { + // test if exists + if (!class_exists($class_impl)) { + throw new Exception("Undefined class '$class_impl' in register template class"); + } + // register the class + $this->registered_classes[$class_name] = $class_impl; + return $this; + } + + /** + * Register config default handler + * + * @param callable $callback class/method name + * + * @return Smarty + * @throws Exception if $callback is not callable + * @api Smarty::registerDefaultConfigHandler() + * + */ + public function registerDefaultConfigHandler($callback): Smarty { + if (is_callable($callback)) { + $this->default_config_handler_func = $callback; + } else { + throw new Exception('Default config handler not callable'); + } + return $this; + } + + /** + * Register template default handler + * + * @param callable $callback class/method name + * + * @return Smarty + * @throws Exception if $callback is not callable + * @api Smarty::registerDefaultTemplateHandler() + * + */ + public function registerDefaultTemplateHandler($callback): Smarty { + if (is_callable($callback)) { + $this->default_template_handler_func = $callback; + } else { + throw new Exception('Default template handler not callable'); + } + return $this; + } + + /** + * Registers a resource to fetch a template + * + * @param string $name name of resource type + * @param BasePlugin $resource_handler instance of Smarty\Resource\Base + * + * @return Smarty + * @link https://www.smarty.net/docs/en/api.register.resource.tpl + * + * @api Smarty::registerResource() + */ + public function registerResource($name, \Smarty\Resource\BasePlugin $resource_handler): Smarty { + $this->registered_resources[$name] = $resource_handler; + return $this; + } + + /** + * Unregisters a resource to fetch a template + * + * @param string $type name of resource type + * + * @return Smarty + * @api Smarty::unregisterResource() + * @link https://www.smarty.net/docs/en/api.unregister.resource.tpl + * + */ + public function unregisterResource($type): Smarty { + if (isset($this->registered_resources[$type])) { + unset($this->registered_resources[$type]); + } + return $this; + } + + /** + * set the debug template + * + * @param string $tpl_name + * + * @return Smarty + * @throws Exception if file is not readable + * @api Smarty::setDebugTemplate() + * + */ + public function setDebugTemplate($tpl_name): Smarty { + if (!is_readable($tpl_name)) { + throw new Exception("Unknown file '{$tpl_name}'"); + } + $this->debug_tpl = $tpl_name; + return $this; + } + } diff --git a/src/Template.php b/src/Template.php index 43006db5..31717112 100644 --- a/src/Template.php +++ b/src/Template.php @@ -126,7 +126,6 @@ class Template extends TemplateBase { $this->compile_id = $_compile_id === null ? $this->smarty->compile_id : $_compile_id; $this->caching = (int)($_caching === null ? $this->smarty->caching : $_caching); $this->cache_lifetime = $this->smarty->cache_lifetime; - $this->compile_check = (int)$smarty->compile_check; $this->parent = $_parent; // Template resource $this->template_resource = $template_resource; @@ -138,20 +137,18 @@ class Template extends TemplateBase { } /** - * render template - * - * @param bool $no_output_filter if true do not run output filter - * @param null|bool $display true: display, false: fetch null: sub-template + * render template and return result * * @return string * @throws \Exception * @throws \Smarty\Exception */ - private function render($no_output_filter = true, $display = null) { + private function getResult(): string { + if ($this->smarty->debugging) { - $this->smarty->getDebug()->start_template($this, $display); + $this->smarty->getDebug()->start_template($this, 0); } - // checks if template exists + if (!$this->getSource()->exists) { throw new Exception( "Unable to load template '{$this->getSource()->type}:{$this->getSource()->name}'" . @@ -168,68 +165,28 @@ class Template extends TemplateBase { call_user_func($callback, $this); } - try { - - // 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); + // read from cache or render + if ($this->isCachingEnabled()) { + // @TODO why would cache_id or compile_id differ. Is this because of re-using of Cached objects over subtemplates? + // If so, it seems error-prone to just throw that away here. + if ($this->getCached()->cache_id !== $this->cache_id || $this->getCached()->compile_id !== $this->compile_id) { + $this->getCached(true); } - - } finally { - foreach ($this->endRenderCallbacks as $callback) { - call_user_func($callback, $this); - } - } - - // display or fetch - if ($display) { - if ($this->caching && $this->smarty->cache_modified_check) { - $this->smarty->cacheModifiedCheck( - $this->getCached(), - $this, - isset($content) ? $content : ob_get_clean() - ); - } else { - if ((!$this->caching || $this->getCached()->getNocacheCode() || $this->getSource()->handler->recompiled) - && !$no_output_filter && isset($this->smarty->registered_filters['output']) - ) { - echo $this->smarty->runOutputFilters(ob_get_clean(), $this); - } else { - echo ob_get_clean(); - } - } - if ($this->smarty->debugging) { - $this->smarty->getDebug()->end_template($this); - // debug output - $this->smarty->getDebug()->display_debug($this, true); - } - return ''; + $result = $this->getCached()->fetch($this); } else { - if ($this->smarty->debugging) { - $this->smarty->getDebug()->end_template($this); - if ($this->smarty->debugging === 2 && $display === false) { - $this->smarty->getDebug()->display_debug($this, true); - } - } - if ( - !$no_output_filter - && (!$this->caching || $this->getCached()->getNocacheCode() || $this->getSource()->handler->recompiled) - ) { - - return $this->smarty->runOutputFilters(ob_get_clean(), $this); - } - // return cache content - return null; + $compiled = $this->getCompiled(); + $result = $compiled->fetch(); } + + foreach ($this->endRenderCallbacks as $callback) { + call_user_func($callback, $this); + } + + if ($this->smarty->debugging) { + $this->smarty->getDebug()->end_template($this); + } + + return $result; } /** @@ -286,7 +243,7 @@ class Template extends TemplateBase { } } - $tpl->render(); + $tpl->getResult(); } /** @@ -311,36 +268,7 @@ class Template extends TemplateBase { * @throws \Exception */ public function compileTemplateSource() { - return $this->getCompiled()->compileAndWrite($this); - } - - /** - * Return cached content - * - * @return null|string - * @throws Exception - */ - public function getCachedContent() { - return $this->getCached()->getContent($this); - } - - /** - * Writes the content to cache resource - * - * @param string $content - * - * @return bool - * - * @TODO this method is only used in unit tests that (mostly) try to test CacheResources. - */ - public function writeCachedContent($content) { - if ($this->getSource()->handler->recompiled || !$this->caching - ) { - // don't write cache file - return false; - } - $codeframe = $this->createCodeFrame($content, '', true); - return $this->getCached()->writeCache($this, $codeframe); + return $this->getCompiled()->compileAndWrite(); } /** @@ -369,7 +297,7 @@ class Template extends TemplateBase { */ public function getCompiled($forceNew = false) { if ($forceNew || !isset($this->compiled)) { - $this->compiled = Compiled::load($this); + $this->compiled = new Compiled($this); } return $this->compiled; } @@ -378,8 +306,7 @@ class Template extends TemplateBase { * Return Cached object * * @param bool $forceNew force new cached object - * - * @throws Exception + * @return Cached */ public function getCached($forceNew = false): Cached { if ($forceNew || !isset($this->cached)) { @@ -391,9 +318,6 @@ class Template extends TemplateBase { $this->cache_id ); $cacheResource->populate($this->cached, $this); - if (!$this->isCachingEnabled()) { - $this->cached->setValid(false); - } } return $this->cached; } @@ -442,13 +366,12 @@ class Template extends TemplateBase { * @param string $content optional template content * @param string $functions compiled template function and block code * @param bool $cache flag for cache file - * @param Compiler\Template|null $compiler * * @return string * @throws Exception */ - public function createCodeFrame($content = '', $functions = '', $cache = false, \Smarty\Compiler\Template $compiler = null) { - return $this->getCodeFrameCompiler()->create($content, $functions, $cache, $compiler); + public function createCodeFrame($content = '', $functions = '', $cache = false) { + return $this->getCodeFrameCompiler()->create($content, $functions, $cache); } /** @@ -482,7 +405,7 @@ class Template extends TemplateBase { return $this->smarty->force_compile || $this->getSource()->handler->recompiled || !$this->getCompiled()->exists - || ($this->compile_check && $this->getCompiled()->getTimeStamp() < $this->getSource()->getTimeStamp()); + || ($this->getSmarty()->getCompileCheck() && $this->getCompiled()->getTimeStamp() < $this->getSource()->getTimeStamp()); } private function getCodeFrameCompiler(): Compiler\CodeFrame { @@ -567,50 +490,12 @@ class Template extends TemplateBase { return $confObj; } - public function fetch() { - $result = $this->_execute(0); - return $result === null ? ob_get_clean() : $result; - } - - public function display() { - $this->_execute(1); - } - - /** - * test if cache is valid - * - * @param mixed $cache_id cache id to be used with this template - * @param mixed $compile_id compile id to be used with this template - * @param object $parent next higher level of Smarty variables - * - * @return bool cache status - * @throws \Exception - * @throws \Smarty\Exception - * @link https://www.smarty.net/docs/en/api.is.cached.tpl - * - * @api Smarty::isCached() - */ - public function isCached(): bool { - return (bool) $this->_execute(2); - } - - /** - * fetches a rendered Smarty template - * - * @param string $function function type 0 = fetch, 1 = display, 2 = isCache - * - * @return mixed - * @throws Exception - * @throws \Throwable - */ - private function _execute($function) { - + public function fetch(): ?string { $smarty = $this->getSmarty(); // make sure we have integer values $this->caching = (int)$this->caching; - // fetch template content - $level = ob_get_level(); + try { $_smarty_old_error_level = isset($smarty->error_reporting) ? error_reporting($smarty->error_reporting) : null; @@ -620,28 +505,15 @@ class Template extends TemplateBase { $errorHandler->activate(); } - if ($function === 2) { - if ($this->caching) { - // return cache status of template - $result = $this->getCached()->isCached($this); - } else { - return false; - } - } else { + // After rendering a template, the tpl/config variables are reset, so the template can be re-used. + $savedTplVars = $this->tpl_vars; + $savedConfigVars = $this->config_vars; - // After rendering a template, the tpl/config variables are reset, so the template can be re-used. - $savedTplVars = $this->tpl_vars; - $savedConfigVars = $this->config_vars; + $result = $this->getResult(); - // Start output-buffering. - ob_start(); - - $result = $this->render(false, $function); - - // Restore the template to its previous state - $this->tpl_vars = $savedTplVars; - $this->config_vars = $savedConfigVars; - } + // Restore the template to its previous state + $this->tpl_vars = $savedTplVars; + $this->config_vars = $savedConfigVars; if (isset($errorHandler)) { $errorHandler->deactivate(); @@ -650,11 +522,9 @@ class Template extends TemplateBase { if (isset($_smarty_old_error_level)) { error_reporting($_smarty_old_error_level); } - return $result; + } catch (\Throwable $e) { - while (ob_get_level() > $level) { - ob_end_clean(); - } + if (isset($errorHandler)) { $errorHandler->deactivate(); } @@ -664,6 +534,25 @@ class Template extends TemplateBase { } throw $e; } + + return $result; + } + + public function display() { + echo $this->fetch(); + } + + /** + * test if caching is enabled, a cache exists and it is still fresh + * + * @return bool cache status + * @throws Exception + * @link https://www.smarty.net/docs/en/api.is.cached.tpl + * + * @api Smarty::isCached() + */ + public function isCached(): bool { + return $this->isCachingEnabled() && $this->getCached()->isCached($this); } /** diff --git a/src/Template/Cached.php b/src/Template/Cached.php index 888858a2..8f0ffe8d 100644 --- a/src/Template/Cached.php +++ b/src/Template/Cached.php @@ -11,7 +11,14 @@ use Smarty\Template\Compiler\CodeFrame; * Represents a cached version of a template or config file. * @author Rodney Rehm */ -class Cached extends GeneratedPhpFile { +class Cached { + + /** + * Filepath of cached file + * + * @var string + */ + public $filepath = null; /** * Cache Is Valid @@ -21,11 +28,25 @@ class Cached extends GeneratedPhpFile { private $valid = null; /** - * @param bool|null $valid + * Indicates existence of cache in cacheresource + * + * @var boolean */ - public function setValid(?bool $valid): void { - $this->valid = $valid; - } + public $exists = false; + + /** + * Template Compile Id (\Smarty\Template::$compile_id) + * + * @var string + */ + public $compile_id = null; + + /** + * Compiled Timestamp + * + * @var int|bool + */ + public $timestamp = false; /** * CacheResource Handler @@ -67,7 +88,7 @@ class Cached extends GeneratedPhpFile { * * @var Source */ - public $source = null; + private $source = null; /** * Nocache hash codes of processed compiled templates @@ -83,6 +104,13 @@ class Cached extends GeneratedPhpFile { */ public $content = null; + /** + * resource file dependency + * + * @var array + */ + public $file_dependency = []; + /** * create Cached Object container * @@ -96,36 +124,69 @@ class Cached extends GeneratedPhpFile { $this->cache_id = $cache_id; $this->source = $source; $this->handler = $handler; + //@TODO we need $template here too. } /** - * Render cache template + * Return cached template contents * - * @param \Smarty\Template $_template - * @param bool $no_output_filter + * @param Template $_template * - * @throws \Exception + * @return string + * @throws Exception */ - public function render(Template $_template, $no_output_filter = true) { + public function fetch(Template $_template): string { if (!$this->isCached($_template)) { - $this->updateCache($_template, $no_output_filter); - } else { - if (!$this->processed) { - $this->process($_template); - } + $this->saveCache($_template); } if ($_template->getSmarty()->debugging) { $_template->getSmarty()->getDebug()->start_cache($_template); } - $this->getRenderedTemplateCode($_template, $this->unifunc); + $codeFrameClassname = $this->getCodeFrameClassname(); + if ($this->getCodeFrameClassname() && !class_exists($codeFrameClassname)) { + $this->runCodeFrame($_template, $this->readCache($_template)); + } + + /** @var \Smarty\CodeFrame\Cached $codeFrameClassname */ + $cachedTemplate = new $codeFrameClassname(); + ob_start(); + + $cachedTemplate->renderContent($_template); + + $result = ob_get_clean(); if ($_template->getSmarty()->debugging) { $_template->getSmarty()->getDebug()->end_cache($_template); } + return $result; + } + + /** + * Render cache template + * + * @param \Smarty\Template $_template + * + * @throws \Exception + */ + public function render(Template $_template): void { + echo $this->fetch($_template); + } + + /** + * Returns the codeframe for this cache, but only if it is loaded already. Will not load any data from + * the cacheresource. + * + * @return \Smarty\CodeFrame\Cached|null + */ + private function getCodeFrame(): ?\Smarty\CodeFrame\Cached { + if (!$this->getCodeFrameClassname() || !class_exists($classname = $this->getCodeFrameClassname())) { + return null; + } + return new $classname; } /** @@ -137,86 +198,7 @@ class Cached extends GeneratedPhpFile { * @throws Exception */ public function isCached(Template $_template) { - if ($this->valid !== null) { - return $this->valid; - } - while (true) { - while (true) { - if ($this->exists === false || $_template->getSmarty()->force_compile || $_template->getSmarty()->force_cache) { - $this->valid = false; - } else { - $this->valid = true; - } - if ($this->valid && $_template->caching === \Smarty\Smarty::CACHING_LIFETIME_CURRENT - && $_template->cache_lifetime >= 0 && time() > ($this->timestamp + $_template->cache_lifetime) - ) { - // lifetime expired - $this->valid = false; - } - if ($this->valid && $_template->compile_check === \Smarty\Smarty::COMPILECHECK_ON - && $_template->getSource()->getTimeStamp() > $this->timestamp - ) { - $this->valid = false; - } - if ($this->valid || !$_template->getSmarty()->cache_locking) { - break; - } - if (!$this->handler->locked($_template->getSmarty(), $this)) { - $this->handler->acquireLock($_template->getSmarty(), $this); - break 2; - } - $this->handler->populate($this, $_template); - } - if ($this->valid) { - if (!$_template->getSmarty()->cache_locking || $this->handler->locked($_template->getSmarty(), $this) === null) { - // load cache file for the following checks - if ($_template->getSmarty()->debugging) { - $_template->getSmarty()->getDebug()->start_cache($_template); - } - if ($this->handler->process($_template, $this) === false) { - $this->valid = false; - } else { - $this->processed = true; - } - if ($_template->getSmarty()->debugging) { - $_template->getSmarty()->getDebug()->end_cache($_template); - } - } else { - $this->is_locked = true; - continue; - } - } else { - return $this->valid; - } - if ($this->valid && $_template->caching === \Smarty\Smarty::CACHING_LIFETIME_SAVED - && $_template->getCached()->cache_lifetime >= 0 - && (time() > ($_template->getCached()->timestamp + $_template->getCached()->cache_lifetime)) - ) { - $this->valid = false; - } - if ($_template->getSmarty()->cache_locking) { - if (!$this->valid) { - $this->handler->acquireLock($_template->getSmarty(), $this); - } elseif ($this->is_locked) { - $this->handler->releaseLock($_template->getSmarty(), $this); - } - } - return $this->valid; - } - return $this->valid; - } - - /** - * 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) { - $this->valid = false; - } - $this->processed = $this->valid; + return $this->getCodeFrame() && $this->getCodeFrame()->isFresh($_template); } /** @@ -224,13 +206,13 @@ class Cached extends GeneratedPhpFile { * * @param Template $_template template object * - * @return string|false content - */ - public function readCache(Template $_template) { + * @return string content +s */ + private function readCache(Template $_template) { if (!$_template->getSource()->handler->recompiled) { return $this->handler->retrieveCachedContent($_template); } - return false; + return ''; } /** @@ -240,7 +222,7 @@ class Cached extends GeneratedPhpFile { * * @return bool success */ - public function writeCache(Template $_template, $content) { + private function writeCache(Template $_template, $content) { if (!$_template->getSource()->handler->recompiled) { if ($this->handler->storeCachedContent($_template, $content)) { $this->content = null; @@ -248,7 +230,6 @@ class Cached extends GeneratedPhpFile { $this->exists = true; $this->valid = true; $this->cache_lifetime = $_template->cache_lifetime; - $this->processed = false; if ($_template->getSmarty()->cache_locking) { $this->handler->releaseLock($_template->getSmarty(), $this); } @@ -258,7 +239,6 @@ class Cached extends GeneratedPhpFile { $this->timestamp = false; $this->exists = false; $this->valid = false; - $this->processed = false; } return false; } @@ -267,29 +247,29 @@ class Cached extends GeneratedPhpFile { * Cache was invalid , so render from compiled and write to cache * * @param Template $_template - * @param bool $no_output_filter * * @throws \Smarty\Exception */ - private function updateCache(Template $_template, $no_output_filter) { + private function saveCache(Template $_template) { - ob_start(); - - $_template->getCompiled()->render($_template); + $content = $_template->getCompiled()->fetch(); if ($_template->getSmarty()->debugging) { $_template->getSmarty()->getDebug()->start_cache($_template); } - $this->removeNoCacheHash($_template, $no_output_filter); + $content = $this->removeNoCacheHash($content, $_template); + + $codeframe = (new \Smarty\Compiler\CodeFrame($_template))->create( + $content, + '', + true + ); + $this->writeCache($_template, $codeframe); if ($_template->_isSubTpl()) { - // @TODO why is this needed? - $_template->getCompiled()->unifunc = $_template->parent->getCompiled()->unifunc; - } - - if (!$this->processed) { - $this->process($_template, true); + // @TODO why was this needed? unifunc is no longer used, so this won't work anymore. +// $_template->getCompiled()->unifunc = $_template->parent->getCompiled()->unifunc; } if ($_template->getSmarty()->debugging) { @@ -297,22 +277,41 @@ class Cached extends GeneratedPhpFile { } } + private function getCompiledUid(): string { + return hash( + \PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', + join('_', [ + $this->getSource()->uid, +// $this->template->compile_id, //@TODO + $this->getSource()->getSmarty()->config_overwrite ? '1' : '0', + $this->getSource()->getSmarty()->config_booleanize ? '1' : '0', + $this->getSource()->getSmarty()->config_read_hidden ? '1' : '0', + $this->getSource()->getSmarty()->caching ? '1' : '0', + ]) + ); + } + + private function getCodeFrameClassname() { + return '__Cache_' . $this->getCompiledUid(); //@TODO use value from properties + } + /** * Sanitize content and write it to cache resource * + * @param string $content * @param Template $_template - * @param bool $no_output_filter * - * @throws \Smarty\Exception + * @return string */ - private function removeNoCacheHash(Template $_template, $no_output_filter) { + private function removeNoCacheHash(string $content, Template $_template): string { + $php_pattern = '/(<%|%>|<\?php|<\?|\?>|)/'; - $content = ob_get_clean(); + $hash_array = $this->hashes; $hash_array[$_template->getCompiled()->nocache_hash] = true; $hash_array = array_keys($hash_array); $nocache_hash = '(' . implode('|', $hash_array) . ')'; - $_template->getCached()->setNocacheCode(false); + // get text between non-cached items $cache_split = preg_split( @@ -349,19 +348,11 @@ class Cached extends GeneratedPhpFile { $content .= $curr_split; } if (isset($cache_parts[0][$curr_idx])) { - $_template->getCached()->setNocacheCode(true); $content .= $cache_parts[2][$curr_idx]; } } - if ( - !$no_output_filter - && !$_template->getCached()->getNocacheCode() - ) { - $content = $_template->getSmarty()->runOutputFilters($content, $_template); - } - $codeframe = (new \Smarty\Compiler\CodeFrame($_template))->create($content, '', true); - $this->writeCache($_template, $codeframe); + return $content; } /** @@ -371,67 +362,12 @@ class Cached extends GeneratedPhpFile { return $this->source; } - /** - * @param Source|null $source - */ - public function setSource(?Source $source): void { - $this->source = $source; - } + private function runCodeFrame(Template $_smarty_tpl, string $code) { + - /** - * Returns the generated content - * - * @param Template $template - * - * @return string|null - * @throws \Exception - */ - public function getContent(Template $template) { ob_start(); - $this->render($template); + eval('?>' . $code); return ob_get_clean(); } - /** - * This function is executed automatically when a generated file is included - * - Decode saved properties - * - Check if file is valid - * - * @param Template $_template - * @param array $properties special template properties - * - * @return bool flag if compiled or cache file is valid - * @throws Exception - */ - public function isFresh(Template $_template, array $properties): bool { - - // on cache resources other than file check version stored in cache code - if (\Smarty\Smarty::SMARTY_VERSION !== $properties['version']) { - return false; - } - - $is_valid = true; - - if (!empty($properties['file_dependency']) && ($_template->compile_check === \Smarty\Smarty::COMPILECHECK_ON)) { - $is_valid = $this->checkFileDependencies($properties['file_dependency'], $_template); - } - - // CACHING_LIFETIME_SAVED cache expiry has to be validated here since otherwise we'd define the unifunc - if ($_template->caching === \Smarty\Smarty::CACHING_LIFETIME_SAVED && $properties['cache_lifetime'] >= 0 - && (time() > ($this->timestamp + $properties['cache_lifetime'])) - ) { - $is_valid = false; - } - - $this->cache_lifetime = $properties['cache_lifetime']; - $this->setValid($is_valid); - - if ($is_valid) { - $this->unifunc = $properties['unifunc']; - $this->setNocacheCode($properties['has_nocache_code']); - $this->file_dependency = $properties['file_dependency']; - } - return $is_valid && !function_exists($properties['unifunc']); - } - } diff --git a/src/Template/Compiled.php b/src/Template/Compiled.php index 753bae76..d38a3b4f 100644 --- a/src/Template/Compiled.php +++ b/src/Template/Compiled.php @@ -3,13 +3,14 @@ namespace Smarty\Template; use Smarty\Exception; +use Smarty\Resource\BasePlugin; +use Smarty\Smarty; use Smarty\Template; /** * Represents a compiled version of a template or config file. - * @author Rodney Rehm */ -class Compiled extends GeneratedPhpFile { +class Compiled { /** * nocache hash @@ -26,277 +27,305 @@ class Compiled extends GeneratedPhpFile { * @var int[] */ public $includes = []; + /** + * @var Template + */ + private $template; + + /** + * flag if template does contain nocache code sections + * * @var bool */ - private $isValid = false; + private $has_nocache_code = false; /** - * get a Compiled Object of this source - * - * @param Template $_template template object - * - * @return Compiled compiled object + * @var false|int */ - public static function load($_template) { - $compiled = new Compiled(); - if ($_template->getSource()->handler->supportsCompiledTemplates()) { - $compiled->populateCompiledFilepath($_template); - } - return $compiled; + private $timestamp = null; + + /** + * resource file dependency + * + * @var array + */ + public $file_dependency = []; + + /** + * @var null|\Smarty\CodeFrame\Compiled + */ + private $codeFrame = null; + + /** + * @return bool + */ + public function getNocacheCode(): bool { + return $this->has_nocache_code; } /** - * populate Compiled Object with compiled filepath - * - * @param Template $_template template object - **/ - private function populateCompiledFilepath(Template $_template) { - $source = $_template->getSource(); - $smarty = $_template->getSmarty(); - $this->filepath = $smarty->getCompileDir(); - if (isset($_template->compile_id)) { - $this->filepath .= preg_replace('![^\w]+!', '_', $_template->compile_id) . - ($smarty->use_sub_dirs ? DIRECTORY_SEPARATOR : '^'); - } - // if use_sub_dirs, break file into directories - if ($smarty->use_sub_dirs) { - $this->filepath .= $source->uid[0] . $source->uid[1] . DIRECTORY_SEPARATOR . $source->uid[2] . - $source->uid[3] . DIRECTORY_SEPARATOR . $source->uid[4] . $source->uid[5] . - DIRECTORY_SEPARATOR; - } - $this->filepath .= $source->uid . '_'; - if ($source->isConfig) { - $this->filepath .= (int)$smarty->config_read_hidden + (int)$smarty->config_booleanize * 2 + - (int)$smarty->config_overwrite * 4; - } else { - $this->filepath .= (int)$smarty->escape_html * 2; - } - $this->filepath .= '.' . $source->type; - $basename = $source->getBasename(); - if (!empty($basename)) { - $this->filepath .= '.' . $basename; - } - if ($_template->caching) { - $this->filepath .= '.cache'; - } - $this->filepath .= '.php'; - $this->timestamp = $this->exists = is_file($this->filepath); - if ($this->exists) { - $this->timestamp = filemtime($this->filepath); - } + * @param bool $has_nocache_code + */ + public function setNocacheCode(bool $has_nocache_code): void { + $this->has_nocache_code = $has_nocache_code; } /** - * render compiled template code - * - * @param Template $_template + * @param Template $template + */ + public function __construct(Template $template) { + $this->template = $template; + } + + /** + * Return compiled template code * * @return string - * @throws \Smarty\Exception + * @throws Exception + * @throws \Exception */ - public function render(Template $_template) { + public function fetch(): string { // 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}'"); + $source = $this->template->getSource(); + if (!$source->exists) { + $type = $source->isConfig ? 'config' : 'template'; + throw new Exception("Unable to load $type '$source->type:$source->name'"); } - if ($_template->getSmarty()->debugging) { - $_template->getSmarty()->getDebug()->start_render($_template); - } - if (!$this->processed) { - $this->compileAndLoad($_template); + if ($this->template->getSmarty()->debugging) { + $this->template->getSmarty()->getDebug()->start_render($this->template); } + $codeFrame = $this->getCodeFrame(); + // @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); + $this->template->getCached()->file_dependency = + array_merge($this->template->getCached()->file_dependency, $this->file_dependency); - $this->getRenderedTemplateCode($_template, $this->unifunc); - - // @TODO Can't Cached handle this? Maybe introduce an event to decouple and remove the $_template->caching property. - if ($_template->caching && $this->getNocacheCode()) { - $_template->getCached()->hashes[$this->nocache_hash] = true; - } - - if ($_template->getSmarty()->debugging) { - $_template->getSmarty()->getDebug()->end_render($_template); - } - } - - /** - * load compiled template or compile from source - * - * @param Template $_smarty_tpl do not change variable name, is used by compiled template - * - * @throws Exception - */ - private function compileAndLoad(Template $_smarty_tpl) { - - if ($_smarty_tpl->getSource()->handler->recompiled) { - $this->recompile($_smarty_tpl); - return; - } - - if ($this->exists && !$_smarty_tpl->getSmarty()->force_compile - && !($_smarty_tpl->compile_check && $_smarty_tpl->getSource()->getTimeStamp() > $this->getTimeStamp()) - ) { - $this->loadCompiledTemplate($_smarty_tpl); - } - - if (!$this->isValid) { - $this->compileAndWrite($_smarty_tpl); - $this->loadCompiledTemplate($_smarty_tpl); - } - - $this->processed = true; - } - - /** - * compile template from source - * - * @param Template $_smarty_tpl do not change variable name, is used by compiled template - * - * @throws Exception - */ - private function recompile(Template $_smarty_tpl) { $level = ob_get_level(); - ob_start(); - // call compiler + try { - eval('?>' . $this->doCompile($_smarty_tpl)); + + ob_start(); + + $codeFrame->renderContent($this->template); + + // @TODO Can't Cached handle this? Maybe introduce an event to decouple and remove the $this->caching property. + if ($this->template->caching && $this->getNocacheCode()) { + $this->template->getCached()->hashes[$this->nocache_hash] = true; + } + + if ($this->template->getSmarty()->debugging) { + $this->template->getSmarty()->getDebug()->end_render($this->template); + } + return $this->template->getSmarty()->runOutputFilters(ob_get_clean(), $this->template); + } catch (\Exception $e) { while (ob_get_level() > $level) { ob_end_clean(); } throw $e; } - ob_get_clean(); - $this->timestamp = time(); - $this->exists = true; } /** - * compile template from source - * - * @param Template $_template + * Loads compiled template (or compile from source and (usually) store the compiled version). + * Should only be called when code frame class doest NOT exist yet. * * @throws Exception */ - public function compileAndWrite(Template $_template) { - // compile locking - if ($saved_timestamp = (!$_template->getSource()->handler->recompiled && is_file($this->filepath))) { - $saved_timestamp = $this->getTimeStamp(); - touch($this->filepath); + private function getCodeFrame(): \Smarty\CodeFrame\Compiled { + + if ($this->codeFrame !== null) { + return $this->codeFrame; } - // compile locking - try { - // call compiler - $this->write($_template, $this->doCompile($_template)); - } catch (\Exception $e) { - // restore old timestamp in case of error - if ($saved_timestamp && is_file($this->filepath)) { - touch($this->filepath, $saved_timestamp); + + $properties = []; + + if ($this->template->getSource()->handler->recompiled) { + $properties = eval('?>' . $this->doCompile()); + } elseif (file_exists($this->getFilePath())) { + $properties = @include $this->getFilePath(); + } + + if (empty($properties) || !$this->isFresh($properties)) { + $content = $this->doCompile(); + $this->write($content); + return $this->getCodeFrame(); // recursion + } + + return new $properties['codeFrameClass'](); + } + + /** + * This function is executed automatically when a generated file is included + * - Decode saved properties + * - Check if file is valid + * + * @param array $properties + * + * @return bool flag if compiled or cache file is valid + * @throws Exception + */ + public function isFresh(array $properties): bool { + + if (Smarty::SMARTY_VERSION !== $properties['version']) { + return false; + } + + if ($this->template->getSmarty()->getCompileCheck()) { + if (!$this->checkFileDependencies($properties['file_dependency'])) { + return false; } - throw $e; } + + return true; } /** - * Do the actual compiling. + * @param array $file_dependency * - * @param Template $_smarty_tpl - * - * @return string + * @return bool * @throws Exception */ - private function doCompile(Template $_smarty_tpl): string { - $this->file_dependency = []; - $this->includes = []; - $this->nocache_hash = null; - $this->unifunc = null; - return $_smarty_tpl->getCompiler()->compileTemplate($_smarty_tpl); - } - - /** - * Write compiled code by handler - * - * @param Template $_template template object - * @param string $code compiled code - * - * @return bool success - * @throws \Smarty\Exception - */ - private function write(Template $_template, $code) { - if (!$_template->getSource()->handler->recompiled) { - if ($_template->getSmarty()->writeFile($this->filepath, $code) === true) { - $this->timestamp = $this->exists = is_file($this->filepath); - if ($this->exists) { - $this->timestamp = filemtime($this->filepath); - return true; + protected function checkFileDependencies(array $file_dependency): bool { + // check file dependencies at compiled code + foreach ($file_dependency as $_file_to_check) { + if ($_file_to_check[2] === 'file') { + if ($this->template->getSource()->filepath === $_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; + } else { + $handler = BasePlugin::load($this->template->getSmarty(), $_file_to_check[2]); + if ($handler->checkTimestamps()) { + $source = Source::load($this->template, $this->template->getSmarty(), $_file_to_check[0]); + $mtime = $source->getTimeStamp(); + } else { + continue; } } - return false; + if ($mtime === false || $mtime > $_file_to_check[1]) { + return false; + } } return true; } /** - * Load fresh compiled template by including the PHP file - * HHVM requires a workaround because of a PHP incompatibility - * - * @param Template $_smarty_tpl do not change/remove variable name, is used by compiled template + * compile template from source * + * @throws Exception */ - private function loadCompiledTemplate(Template $_smarty_tpl) { + public function compileAndWrite(): string { - if (function_exists('opcache_invalidate') - && (!function_exists('ini_get') || strlen(ini_get("opcache.restrict_api")) < 1) - ) { - opcache_invalidate($this->filepath, true); - } elseif (function_exists('apc_compile_file')) { - apc_compile_file($this->filepath); + $_template = $this->template; + + $filepath = $this->getFilePath(); + + // compile locking + if ($saved_timestamp = (!$_template->getSource()->handler->recompiled && is_file($filepath))) { + $saved_timestamp = $this->getTimeStamp(); + touch($filepath); } - if (defined('HHVM_VERSION')) { - eval('?>' . file_get_contents($this->filepath)); - } else { - include $this->filepath; + // compile locking + try { + // call compiler + $this->write($content = $this->doCompile()); + + } catch (\Exception $e) { + // restore old timestamp in case of error + if ($saved_timestamp && is_file($filepath)) { + touch($filepath, $saved_timestamp); + } + throw $e; } + return $content; } /** - * This function is executed automatically when a compiled or cached template file is included - * - Decode saved properties from compiled template and cache files - * - Check if compiled or cache file is valid + * Do the actual compiling. * - * @param Template $_template - * @param array $properties special template properties - * - * @return bool flag if compiled or cache file is valid + * @return string * @throws Exception */ - public function isFresh(Template $_template, array $properties): bool { + private function doCompile(): string { + $this->file_dependency = []; + $this->includes = []; + $this->nocache_hash = null; - // on cache resources other than file check version stored in cache code - if (\Smarty\Smarty::SMARTY_VERSION !== $properties['version']) { - return false; + $level = ob_get_level(); + + try { + $result = $this->template->getCompiler()->compileTemplate($this->template); + } catch (\Exception $e) { + // close output buffers that were left open because of the exception + while (ob_get_level() > $level) { + ob_end_clean(); + } + throw $e; } - $is_valid = true; - if (!empty($properties['file_dependency']) && $_template->compile_check) { - $is_valid = $this->checkFileDependencies($properties['file_dependency'], $_template); - } + $this->timestamp = time(); + return $result; + } - $this->isValid = $is_valid; - $this->includes = $properties['includes'] ?? []; - - if ($is_valid) { - $this->unifunc = $properties['unifunc']; - $this->setNocacheCode($properties['has_nocache_code']); - $this->file_dependency = $properties['file_dependency']; + /** + * Write compiled code by handler + * + * @param string $code compiled code + * + * @return void + * @throws Exception + */ + private function write(string $code) { + if (!$this->template->getSource()->handler->recompiled) { + $filePath = $this->getFilePath(); + if ($this->template->getSmarty()->writeFile($filePath, $code) === true) { + $this->timestamp = is_file($filePath) ? filemtime($filePath) : false; + } } - return $is_valid && !function_exists($properties['unifunc']); + } + + private function getFilePath(): string { + + $source = $this->template->getSource(); + $smarty = $this->template->getSmarty(); + + $prefix = $smarty->getCompileDir() . $source->uid[0] . $source->uid[1]; + + return $prefix . DIRECTORY_SEPARATOR . join('_', [ + $source->type, + $source->getBasename(), + $this->getCompiledUid() + ]) . '.php'; + } + + private function getCompiledUid(): string { + return hash( + PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', + join('_', [ + $this->template->getSource()->uid, + $this->template->compile_id, + $this->template->getSmarty()->escape_html ? '1' : '0', + $this->template->caching ? '1' : '0', + ]) + ); + } + + /** + * Get compiled time stamp or null if there is no compiled file + * + * @return int|null + */ + public function getTimeStamp(): ?int { + if ($this->timestamp === null && file_exists($this->getFilePath())) { + $this->timestamp = filemtime($this->getFilePath()); + } + return $this->timestamp; } } diff --git a/src/Template/GeneratedPhpFile.php b/src/Template/GeneratedPhpFile.php deleted file mode 100644 index 6a9c2a51..00000000 --- a/src/Template/GeneratedPhpFile.php +++ /dev/null @@ -1,153 +0,0 @@ -exists && !$this->timestamp) { - $this->timestamp = filemtime($this->filepath); - } - return $this->timestamp; - } - - /** - * @return bool - */ - public function getNocacheCode(): bool { - return $this->has_nocache_code; - } - - /** - * @param bool $has_nocache_code - */ - public function setNocacheCode(bool $has_nocache_code): void { - $this->has_nocache_code = $has_nocache_code; - } - - /** - * get rendered template content by calling compiled or cached template code - * - * @param string $unifunc function with template code - * - * @throws \Exception - */ - protected function getRenderedTemplateCode(\Smarty\Template $_template, $unifunc) { - $level = ob_get_level(); - try { - if (empty($unifunc) || !function_exists($unifunc)) { - throw new \Smarty\Exception("Invalid compiled template for '{$this->filepath}'"); - } - $unifunc($_template); - } catch (\Exception $e) { - while (ob_get_level() > $level) { - ob_end_clean(); - } - - throw $e; - } - } - - /** - * @param $file_dependency - * @param Template $_template - * - * @return bool - * @throws Exception - */ - 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]) { - // 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; - } 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]); - $mtime = $source->getTimeStamp(); - } else { - continue; - } - } - if ($mtime === false || $mtime > $_file_to_check[1]) { - return false; - } - } - return true; - } - -} diff --git a/src/TemplateBase.php b/src/TemplateBase.php index 11849c9a..1c400c15 100644 --- a/src/TemplateBase.php +++ b/src/TemplateBase.php @@ -38,13 +38,6 @@ abstract class TemplateBase extends Data { */ public $caching = \Smarty\Smarty::CACHING_OFF; - /** - * check template for modifications? - * - * @var int - */ - public $compile_check = \Smarty\Smarty::COMPILECHECK_ON; - /** * cache lifetime in seconds * @@ -66,87 +59,8 @@ abstract class TemplateBase extends Data { */ public $_var_stack = null; - /** - * @var Debug - */ - private $debug; - /** - * Registers object to be used in templates - * - * @param string $object_name - * @param object $object the referenced PHP object to register - * @param array $allowed_methods_properties list of allowed methods (empty = all) - * @param bool $format smarty argument format, else traditional - * @param array $block_methods list of block-methods - * - * @return \Smarty|\Smarty\Template - * @throws \Smarty\Exception - * @link https://www.smarty.net/docs/en/api.register.object.tpl - * - * @api Smarty::registerObject() - */ - public function registerObject( - $object_name, - $object, - $allowed_methods_properties = [], - $format = true, - $block_methods = [] - ) { - $smarty = $this->getSmarty(); - // test if allowed methods callable - if (!empty($allowed_methods_properties)) { - foreach ((array)$allowed_methods_properties as $method) { - if (!is_callable([$object, $method]) && !property_exists($object, $method)) { - throw new Exception("Undefined method or property '$method' in registered object"); - } - } - } - // test if block methods callable - if (!empty($block_methods)) { - foreach ((array)$block_methods as $method) { - if (!is_callable([$object, $method])) { - throw new Exception("Undefined method '$method' in registered object"); - } - } - } - // register the object - $smarty->registered_objects[$object_name] = - [$object, (array)$allowed_methods_properties, (boolean)$format, (array)$block_methods]; - return $this; - } - /** - * Registers plugin to be used in templates - * - * @param string $object_name name of object - * - * @return TemplateBase - * @api Smarty::unregisterObject() - * @link https://www.smarty.net/docs/en/api.unregister.object.tpl - * - */ - public function unregisterObject($object_name) { - $smarty = $this->getSmarty(); - if (isset($smarty->registered_objects[$object_name])) { - unset($smarty->registered_objects[$object_name]); - } - return $this; - } - - /** - * @return int - */ - public function getCompileCheck(): int { - return $this->compile_check; - } - - /** - * @param int $compile_check - */ - public function setCompileCheck($compile_check) { - $this->compile_check = (int)$compile_check; - } /** * @param int $caching @@ -176,264 +90,6 @@ abstract class TemplateBase extends Data { $this->cache_id = $cache_id; } - /** - * creates a data object - * - * @param Data|null $parent next higher level of Smarty - * variables - * @param null $name optional data block name - * - * @return Data data object - * @throws Exception - * @api Smarty::createData() - * @link https://www.smarty.net/docs/en/api.create.data.tpl - * - */ - public function createData(Data $parent = null, $name = null) { - /* @var Smarty $smarty */ - $smarty = $this->getSmarty(); - $dataObj = new Data($parent, $smarty, $name); - if ($smarty->debugging) { - $smarty->getDebug()->register_data($dataObj); - } - return $dataObj; - } - - /** - * return name of debugging template - * - * @return string - * @api Smarty::getDebugTemplate() - * - */ - public function getDebugTemplate() { - $smarty = $this->getSmarty(); - return $smarty->debug_tpl; - } - - /** - * @return Debug - */ - public function getDebug(): Debug { - if (!isset($this->debug)) { - $this->debug = new \Smarty\Debug(); - } - return $this->debug; - } - - - /** - * return a reference to a registered object - * - * @param string $object_name object name - * - * @return object - * @throws \Smarty\Exception if no such object is found - * @link https://www.smarty.net/docs/en/api.get.registered.object.tpl - * - * @api Smarty::getRegisteredObject() - */ - public function getRegisteredObject($object_name) { - $smarty = $this->getSmarty(); - if (!isset($smarty->registered_objects[$object_name])) { - throw new Exception("'$object_name' is not a registered object"); - } - if (!is_object($smarty->registered_objects[$object_name][0])) { - throw new Exception("registered '$object_name' is not an object"); - } - return $smarty->registered_objects[$object_name][0]; - } - - /** - * Get literals - * - * @return array list of literals - * @api Smarty::getLiterals() - * - */ - public function getLiterals() { - $smarty = $this->getSmarty(); - return (array)$smarty->literals; - } - - /** - * Add literals - * - * @param array|string $literals literal or list of literals - * to addto add - * - * @return TemplateBase - * @throws \Smarty\Exception - * @api Smarty::addLiterals() - * - */ - public function addLiterals($literals = null) { - if (isset($literals)) { - $this->_setLiterals($this->getSmarty(), (array)$literals); - } - return $this; - } - - /** - * Set literals - * - * @param array|string $literals literal or list of literals - * to setto set - * - * @return TemplateBase - * @throws \Smarty\Exception - * @api Smarty::setLiterals() - * - */ - public function setLiterals($literals = null) { - $smarty = $this->getSmarty(); - $smarty->literals = []; - if (!empty($literals)) { - $this->_setLiterals($smarty, (array)$literals); - } - return $this; - } - - /** - * common setter for literals for easier handling of duplicates the - * Smarty::$literals array gets filled with identical key values - * - * @param Smarty $smarty - * @param array $literals - * - * @throws \Smarty\Exception - */ - private function _setLiterals(Smarty $smarty, $literals) { - $literals = array_combine($literals, $literals); - $error = isset($literals[$smarty->getLeftDelimiter()]) ? [$smarty->getLeftDelimiter()] : []; - $error = isset($literals[$smarty->getRightDelimiter()]) ? $error[] = $smarty->getRightDelimiter() : $error; - if (!empty($error)) { - throw new Exception( - 'User defined literal(s) "' . $error . - '" may not be identical with left or right delimiter' - ); - } - $smarty->literals = array_merge((array)$smarty->literals, (array)$literals); - } - - /** - * Registers static classes to be used in templates - * - * @param string $class_name - * @param string $class_impl the referenced PHP class to - * register - * - * @return TemplateBase - * @throws \Smarty\Exception - * @api Smarty::registerClass() - * @link https://www.smarty.net/docs/en/api.register.class.tpl - * - */ - public function registerClass($class_name, $class_impl) { - $smarty = $this->getSmarty(); - // test if exists - if (!class_exists($class_impl)) { - throw new Exception("Undefined class '$class_impl' in register template class"); - } - // register the class - $smarty->registered_classes[$class_name] = $class_impl; - return $this; - } - - /** - * Register config default handler - * - * @param callable $callback class/method name - * - * @return TemplateBase - * @throws Exception if $callback is not callable - * @api Smarty::registerDefaultConfigHandler() - * - */ - public function registerDefaultConfigHandler($callback) { - $smarty = $this->getSmarty(); - if (is_callable($callback)) { - $smarty->default_config_handler_func = $callback; - } else { - throw new Exception('Default config handler not callable'); - } - return $this; - } - - /** - * Register template default handler - * - * @param callable $callback class/method name - * - * @return TemplateBase - * @throws Exception if $callback is not callable - * @api Smarty::registerDefaultTemplateHandler() - * - */ - public function registerDefaultTemplateHandler($callback) { - $smarty = $this->getSmarty(); - if (is_callable($callback)) { - $smarty->default_template_handler_func = $callback; - } else { - throw new Exception('Default template handler not callable'); - } - return $this; - } - - /** - * Registers a resource to fetch a template - * - * @param string $name name of resource type - * @param Smarty\Resource\Base $resource_handler instance of Smarty\Resource\Base - * - * @return \Smarty|\Smarty\Template - * @link https://www.smarty.net/docs/en/api.register.resource.tpl - * - * @api Smarty::registerResource() - */ - public function registerResource($name, \Smarty\Resource\BasePlugin $resource_handler) { - $smarty = $this->getSmarty(); - $smarty->registered_resources[$name] = $resource_handler; - return $this; - } - - /** - * Unregisters a resource to fetch a template - * - * @param string $type name of resource type - * - * @return TemplateBase - * @api Smarty::unregisterResource() - * @link https://www.smarty.net/docs/en/api.unregister.resource.tpl - * - */ - public function unregisterResource($type) { - $smarty = $this->getSmarty(); - if (isset($smarty->registered_resources[$type])) { - unset($smarty->registered_resources[$type]); - } - return $this; - } - - /** - * set the debug template - * - * @param string $tpl_name - * - * @return TemplateBase - * @throws Exception if file is not readable - * @api Smarty::setDebugTemplate() - * - */ - public function setDebugTemplate($tpl_name) { - $smarty = $this->getSmarty(); - if (!is_readable($tpl_name)) { - throw new Exception("Unknown file '{$tpl_name}'"); - } - $smarty->debug_tpl = $tpl_name; - return $this; - } - } diff --git a/tests/PHPUnit_Smarty.php b/tests/PHPUnit_Smarty.php index c75a8232..a98229d3 100644 --- a/tests/PHPUnit_Smarty.php +++ b/tests/PHPUnit_Smarty.php @@ -482,7 +482,6 @@ KEY `name` (`name`) * Return compiled file path * * @param \Smarty\Template|\Smarty\TemplateBase $tpl template object - * @param bool $sub use sub directory flag * @param bool $caching caching flag * @param null|string $compile_id optional compile id * @param null|string $name optional template name @@ -492,7 +491,7 @@ KEY `name` (`name`) * @return string * @throws \Exception */ - public function buildCompiledPath(Template $tpl, $sub = true, $caching = false, $compile_id = null, + public function buildCompiledPath(Template $tpl, $caching = false, $compile_id = null, $name = null, $type = null, $dir = null) { $sep = DIRECTORY_SEPARATOR; @@ -507,15 +506,12 @@ KEY `name` (`name`) $_flag = '_' . ((int) $tpl->getSmarty()->merge_compiled_includes + (int) $tpl->getSmarty()->escape_html * 2); } $_filepath = $uid . $_flag; - // if use_sub_dirs, break file into directories - if ($sub) { - $_filepath = - substr($_filepath, 0, 2) . $sep . substr($_filepath, 2, 2) . $sep . substr($_filepath, 4, 2) . $sep . - $_filepath; - } - $_compile_dir_sep = $sub ? $sep : '^'; + // break file into directories + $_filepath = + substr($_filepath, 0, 2) . $sep . $_filepath; + if (isset($_compile_id)) { - $_filepath = $_compile_id . $_compile_dir_sep . $_filepath; + $_filepath = $_compile_id . $sep . $_filepath; } // caching token if ($caching) { @@ -541,7 +537,6 @@ KEY `name` (`name`) * Return cache file path * * @param TemplateBase $tpl template object - * @param bool $sub use sub directory flag * @param null|string $cache_id optional cache id * @param null|string $compile_id optional compile id * @param null|string $name optional template name @@ -552,7 +547,7 @@ KEY `name` (`name`) * @return string * @throws \Exception */ - public function buildCachedPath(TemplateBase $tpl, $sub = true, $cache_id = null, $compile_id = null, $name = null, $type = null, + public function buildCachedPath(TemplateBase $tpl, $cache_id = null, $compile_id = null, $name = null, $type = null, $dir = null, $cacheType = null) { $cacheType = $cacheType ?? $tpl->getSmarty()->getCachingType(); @@ -565,13 +560,12 @@ KEY `name` (`name`) $sp = $this->buildSourcePath($tpl, $name, $type, $dir); $uid = $this->buildUid($tpl, $sp, $name, $type); $_filepath = sha1($uid . $this->smarty->_joined_template_dir); - // if use_sub_dirs, break file into directories - if ($sub) { - $_filepath = - substr($_filepath, 0, 2) . $sep . substr($_filepath, 2, 2) . $sep . substr($_filepath, 4, 2) . - $sep . $_filepath; - } - $_compile_dir_sep = $sub ? $sep : '^'; + // break file into directories + + $_filepath = + substr($_filepath, 0, 2) . $sep . $_filepath; + + $_compile_dir_sep = $sep; if (isset($_cache_id)) { $_cache_id = str_replace('|', $_compile_dir_sep, $_cache_id) . $_compile_dir_sep; } else { diff --git a/tests/UnitTests/A_2/UndefinedTemplateVar/templates_c/.gitignore b/tests/UnitTests/A_2/UndefinedTemplateVar/templates_c/.gitignore deleted file mode 100644 index 1d34e205..00000000 --- a/tests/UnitTests/A_2/UndefinedTemplateVar/templates_c/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Ignore anything in here, but keep this directory -* \ No newline at end of file diff --git a/tests/UnitTests/CacheResourceTests/File/CacheResourceFileTest.php b/tests/UnitTests/CacheResourceTests/File/CacheResourceFileTest.php index d009f7cf..5427fa98 100644 --- a/tests/UnitTests/CacheResourceTests/File/CacheResourceFileTest.php +++ b/tests/UnitTests/CacheResourceTests/File/CacheResourceFileTest.php @@ -39,9 +39,9 @@ class CacheResourceFileTest extends CacheResourceTestCommon { $this->smarty->caching = true; $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') + $this->assertEquals($this->buildCachedPath($tpl, null, null, 'helloworld.tpl', $type = 'file', $this->smarty->getTemplateDir(0), 'file') , $tpl->getCached()->filepath); } @@ -52,9 +52,9 @@ class CacheResourceFileTest extends CacheResourceTestCommon { $this->smarty->caching = true; $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') + $this->assertEquals($this->buildCachedPath($tpl, 'foo|bar', null, 'helloworld.tpl', $type = 'file', $this->smarty->getTemplateDir(0), 'file') , $tpl->getCached()->filepath); } @@ -65,9 +65,9 @@ class CacheResourceFileTest extends CacheResourceTestCommon { $this->smarty->caching = true; $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') + $this->assertEquals($this->buildCachedPath($tpl, null, 'blar', 'helloworld.tpl', $type = 'file', $this->smarty->getTemplateDir(0), 'file') , $tpl->getCached()->filepath); } @@ -78,9 +78,9 @@ class CacheResourceFileTest extends CacheResourceTestCommon { $this->smarty->caching = true; $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') + $this->assertEquals($this->buildCachedPath($tpl, 'foo|bar', 'blar', 'helloworld.tpl', $type = 'file', $this->smarty->getTemplateDir(0), 'file') , $tpl->getCached()->filepath); } @@ -92,7 +92,7 @@ class CacheResourceFileTest extends CacheResourceTestCommon $this->cleanCacheDir(); $this->smarty->caching = true; $this->smarty->cache_lifetime = 1000; - $this->smarty->setUseSubDirs(true); + $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); $this->writeCachedContent($tpl); $this->assertTrue(file_exists($tpl->getCached()->filepath)); @@ -100,14 +100,14 @@ class CacheResourceFileTest extends CacheResourceTestCommon } /** - * test cache->clear with cache_id and compile_id + * test cache->clear with cache_id */ - public function testClearCacheCacheIdCompileId() + public function testClearCacheCacheId() { $this->smarty->caching = true; $this->smarty->cache_lifetime = 1000; $this->cleanCacheDir(); - $this->smarty->setUseSubDirs(false); + $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); $this->writeCachedContent($tpl); $tpl2 = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar2', 'blar'); @@ -127,7 +127,7 @@ class CacheResourceFileTest extends CacheResourceTestCommon { $this->smarty->caching = true; $this->smarty->cache_lifetime = 1000; - $this->smarty->setUseSubDirs(false); + $this->cleanCacheDir(); $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); $this->writeCachedContent($tpl); @@ -148,7 +148,7 @@ class CacheResourceFileTest extends CacheResourceTestCommon { $this->smarty->caching = true; $this->smarty->cache_lifetime = 1000; - $this->smarty->setUseSubDirs(true); + $this->cleanCacheDir(); $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); $this->writeCachedContent($tpl); @@ -170,7 +170,7 @@ class CacheResourceFileTest extends CacheResourceTestCommon $this->smarty->caching = true; $this->smarty->cache_lifetime = 1000; $this->cleanCacheDir(); - $this->smarty->setUseSubDirs(false); + $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); $this->writeCachedContent($tpl); $tpl2 = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar2'); @@ -191,7 +191,7 @@ class CacheResourceFileTest extends CacheResourceTestCommon $this->smarty->caching = true; $this->smarty->cache_lifetime = 1000; $this->cleanCacheDir(); - $this->smarty->setUseSubDirs(true); + $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); $this->writeCachedContent($tpl); $tpl2 = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar2'); @@ -211,7 +211,7 @@ class CacheResourceFileTest extends CacheResourceTestCommon { $this->smarty->caching = true; $this->smarty->cache_lifetime = 1000; - $this->smarty->setUseSubDirs(false); + $this->cleanCacheDir(); $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); $this->writeCachedContent($tpl); @@ -232,7 +232,7 @@ class CacheResourceFileTest extends CacheResourceTestCommon { $this->smarty->caching = true; $this->smarty->cache_lifetime = 1000; - $this->smarty->setUseSubDirs(true); + $this->cleanCacheDir(); $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); $this->writeCachedContent($tpl); @@ -253,7 +253,7 @@ class CacheResourceFileTest extends CacheResourceTestCommon { $this->smarty->caching = true; $this->smarty->cache_lifetime = 1000; - $this->smarty->setUseSubDirs(false); + $this->cleanCacheDir(); $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); $this->writeCachedContent($tpl); @@ -274,7 +274,7 @@ class CacheResourceFileTest extends CacheResourceTestCommon { $this->smarty->caching = true; $this->smarty->cache_lifetime = 1000; - $this->smarty->setUseSubDirs(true); + $this->cleanCacheDir(); $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); $this->writeCachedContent($tpl); @@ -295,7 +295,7 @@ class CacheResourceFileTest extends CacheResourceTestCommon { $this->smarty->caching = true; $this->smarty->cache_lifetime = 1000; - $this->smarty->setUseSubDirs(false); + $this->cleanCacheDir(); $tpl = $this->smarty->createTemplate('helloworld.tpl'); $this->writeCachedContent($tpl); @@ -320,7 +320,7 @@ class CacheResourceFileTest extends CacheResourceTestCommon { $this->smarty->caching = true; $this->smarty->cache_lifetime = 1000; - $this->smarty->setUseSubDirs(true); + $this->cleanCacheDir(); $tpl = $this->smarty->createTemplate('helloworld.tpl'); $this->writeCachedContent($tpl); @@ -376,8 +376,8 @@ class CacheResourceFileTest extends CacheResourceTestCommon } - private function writeCachedContent($tpl) + protected function writeCachedContent($tpl, string $string = "echo 'hello world';\n") { - $tpl->writeCachedContent("echo 'hello world';\n"); + $this->smarty->getCacheResource()->storeCachedContent($tpl, $string); } } diff --git a/tests/UnitTests/CacheResourceTests/_shared/CacheResourceTestCommon.php b/tests/UnitTests/CacheResourceTests/_shared/CacheResourceTestCommon.php index 42e5ba8b..a0158653 100644 --- a/tests/UnitTests/CacheResourceTests/_shared/CacheResourceTestCommon.php +++ b/tests/UnitTests/CacheResourceTests/_shared/CacheResourceTestCommon.php @@ -43,7 +43,6 @@ abstract class CacheResourceTestCommon extends PHPUnit_Smarty { $this->smarty->caching = true; $this->smarty->cache_lifetime = 1000; - $this->smarty->setUseSubDirs(true); $tpl = $this->smarty->createTemplate('helloworld.tpl'); $this->assertEquals($this->buildCachedPath($tpl), $tpl->getCached()->filepath); } @@ -56,7 +55,7 @@ abstract class CacheResourceTestCommon extends PHPUnit_Smarty $this->smarty->caching = true; $this->smarty->cache_lifetime = 1000; $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar'); - $this->assertEquals($this->buildCachedPath($tpl, true, 'foo|bar'), $tpl->getCached()->filepath); + $this->assertEquals($this->buildCachedPath($tpl, 'foo|bar'), $tpl->getCached()->filepath); } /** @@ -67,7 +66,7 @@ abstract class CacheResourceTestCommon extends PHPUnit_Smarty $this->smarty->caching = true; $this->smarty->cache_lifetime = 1000; $tpl = $this->smarty->createTemplate('helloworld.tpl', null, 'blar'); - $this->assertEquals($this->buildCachedPath($tpl, true, null, 'blar'), $tpl->getCached()->filepath); + $this->assertEquals($this->buildCachedPath($tpl, null, 'blar'), $tpl->getCached()->filepath); } /** @@ -78,9 +77,15 @@ abstract class CacheResourceTestCommon extends PHPUnit_Smarty $this->smarty->caching = true; $this->smarty->cache_lifetime = 1000; $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); - $this->assertEquals($this->buildCachedPath($tpl, true, 'foo|bar', 'blar'), $tpl->getCached()->filepath); + $this->assertEquals($this->buildCachedPath($tpl, 'foo|bar', 'blar'), $tpl->getCached()->filepath); } + private function getCachedContent(Smarty\Template $tpl) { + ob_start(); + $this->smarty->getCacheResource()->process($tpl); + return ob_get_clean(); + } + /** * test cache->clear_all with cache_id and compile_id */ @@ -90,8 +95,8 @@ abstract class CacheResourceTestCommon extends PHPUnit_Smarty $this->smarty->caching = true; $this->smarty->cache_lifetime = 1000; $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); - $tpl->writeCachedContent('hello world'); - $this->assertEquals('hello world', $tpl->getCachedContent()); + $this->writeCachedContent($tpl, 'hello world'); + $this->assertEquals('hello world', $this->getCachedContent($tpl)); // Custom CacheResources may return -1 if they can't tell the number of deleted elements //$this->assertEquals(-1, $this->smarty->clearAllCache()); } @@ -106,21 +111,21 @@ abstract class CacheResourceTestCommon extends PHPUnit_Smarty $this->smarty->clearAllCache(); // create and cache templates $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); - $tpl->writeCachedContent('hello world 1'); + $this->writeCachedContent($tpl, 'hello world 1'); $tpl2 = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar2', 'blar'); - $tpl2->writeCachedContent('hello world 2'); + $this->writeCachedContent($tpl2, 'hello world 2'); $tpl3 = $this->smarty->createTemplate('helloworld2.tpl', 'foo|bar', 'blar'); - $tpl3->writeCachedContent('hello world 3'); + $this->writeCachedContent($tpl3, 'hello world 3'); // test cached content - $this->assertEquals('hello world 1', $tpl->getCachedContent()); - $this->assertEquals('hello world 2', $tpl2->getCachedContent()); - $this->assertEquals('hello world 3', $tpl3->getCachedContent()); + $this->assertEquals('hello world 1', $this->getCachedContent($tpl)); + $this->assertEquals('hello world 2', $this->getCachedContent($tpl2)); + $this->assertEquals('hello world 3', $this->getCachedContent($tpl3)); // test number of deleted caches $this->doClearCacheAssertion(2, $this->smarty->clearCache(null, 'foo|bar')); // test that caches are deleted properly - $this->assertNull($tpl->getCachedContent()); - $this->assertEquals('hello world 2', $tpl2->getCachedContent()); - $this->assertNull($tpl3->getCachedContent()); + $this->assertEquals('', $this->getCachedContent($tpl)); + $this->assertEquals('hello world 2', $this->getCachedContent($tpl2)); + $this->assertEquals('', $this->getCachedContent($tpl3)); } public function testClearCacheCacheIdCompileId2() @@ -130,21 +135,21 @@ abstract class CacheResourceTestCommon extends PHPUnit_Smarty $this->smarty->clearAllCache(); // create and cache templates $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); - $tpl->writeCachedContent('hello world'); + $this->writeCachedContent($tpl, 'hello world'); $tpl2 = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar2', 'blar'); - $tpl2->writeCachedContent('hello world'); + $this->writeCachedContent($tpl2, 'hello world'); $tpl3 = $this->smarty->createTemplate('helloworld2.tpl', 'foo|bar', 'blar'); - $tpl3->writeCachedContent('hello world'); + $this->writeCachedContent($tpl3, 'hello world'); // test cached content - $this->assertEquals('hello world', $tpl->getCachedContent()); - $this->assertEquals('hello world', $tpl2->getCachedContent()); - $this->assertEquals('hello world', $tpl3->getCachedContent()); + $this->assertEquals('hello world', $this->getCachedContent($tpl)); + $this->assertEquals('hello world', $this->getCachedContent($tpl2)); + $this->assertEquals('hello world', $this->getCachedContent($tpl3)); // test number of deleted caches $this->doClearCacheAssertion(2, $this->smarty->clearCache('helloworld.tpl')); // test that caches are deleted properly - $this->assertNull($tpl->getCachedContent()); - $this->assertNull($tpl2->getCachedContent()); - $this->assertEquals('hello world', $tpl3->getCachedContent()); + $this->assertNull($this->getCachedContent($tpl)); + $this->assertNull($this->getCachedContent($tpl2)); + $this->assertEquals('hello world', $this->getCachedContent($tpl3)); } public function testClearCacheCacheIdCompileId2Sub() @@ -154,21 +159,21 @@ abstract class CacheResourceTestCommon extends PHPUnit_Smarty $this->smarty->clearAllCache(); // create and cache templates $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); - $tpl->writeCachedContent('hello world'); + $this->writeCachedContent($tpl, 'hello world'); $tpl2 = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar2', 'blar'); - $tpl2->writeCachedContent('hello world'); + $this->writeCachedContent($tpl2, 'hello world'); $tpl3 = $this->smarty->createTemplate('helloworld2.tpl', 'foo|bar', 'blar'); - $tpl3->writeCachedContent('hello world'); + $this->writeCachedContent($tpl3, 'hello world'); // test cached content - $this->assertEquals('hello world', $tpl->getCachedContent()); - $this->assertEquals('hello world', $tpl2->getCachedContent()); - $this->assertEquals('hello world', $tpl3->getCachedContent()); + $this->assertEquals('hello world', $this->getCachedContent($tpl)); + $this->assertEquals('hello world', $this->getCachedContent($tpl2)); + $this->assertEquals('hello world', $this->getCachedContent($tpl3)); // test number of deleted caches $this->doClearCacheAssertion(2, $this->smarty->clearCache('helloworld.tpl')); // test that caches are deleted properly - $this->assertNull($tpl->getCachedContent()); - $this->assertNull($tpl2->getCachedContent()); - $this->assertEquals('hello world', $tpl3->getCachedContent()); + $this->assertNull($this->getCachedContent($tpl)); + $this->assertNull($this->getCachedContent($tpl2)); + $this->assertEquals('hello world', $this->getCachedContent($tpl3)); } public function testClearCacheCacheIdCompileId3() @@ -178,21 +183,21 @@ abstract class CacheResourceTestCommon extends PHPUnit_Smarty $this->smarty->clearAllCache(); // create and cache templates $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); - $tpl->writeCachedContent('hello world'); + $this->writeCachedContent($tpl, 'hello world'); $tpl2 = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar2'); - $tpl2->writeCachedContent('hello world'); + $this->writeCachedContent($tpl2, 'hello world'); $tpl3 = $this->smarty->createTemplate('helloworld2.tpl', 'foo|bar', 'blar'); - $tpl3->writeCachedContent('hello world'); + $this->writeCachedContent($tpl3, 'hello world'); // test cached content - $this->assertEquals('hello world', $tpl->getCachedContent()); - $this->assertEquals('hello world', $tpl2->getCachedContent()); - $this->assertEquals('hello world', $tpl3->getCachedContent()); + $this->assertEquals('hello world', $this->getCachedContent($tpl)); + $this->assertEquals('hello world', $this->getCachedContent($tpl2)); + $this->assertEquals('hello world', $this->getCachedContent($tpl3)); // test number of deleted caches $this->doClearCacheAssertion(1, $this->smarty->clearCache('helloworld.tpl', null, 'blar2')); // test that caches are deleted properly - $this->assertEquals('hello world', $tpl->getCachedContent()); - $this->assertNull($tpl2->getCachedContent()); - $this->assertEquals('hello world', $tpl3->getCachedContent()); + $this->assertEquals('hello world', $this->getCachedContent($tpl)); + $this->assertNull($this->getCachedContent($tpl2)); + $this->assertEquals('hello world', $this->getCachedContent($tpl3)); } public function testClearCacheCacheIdCompileId3Sub() @@ -202,21 +207,21 @@ abstract class CacheResourceTestCommon extends PHPUnit_Smarty $this->smarty->clearAllCache(); // create and cache templates $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); - $tpl->writeCachedContent('hello world'); + $this->writeCachedContent($tpl, 'hello world'); $tpl2 = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar2'); - $tpl2->writeCachedContent('hello world'); + $this->writeCachedContent($tpl2, 'hello world'); $tpl3 = $this->smarty->createTemplate('helloworld2.tpl', 'foo|bar', 'blar'); - $tpl3->writeCachedContent('hello world'); + $this->writeCachedContent($tpl3, 'hello world'); // test cached content - $this->assertEquals('hello world', $tpl->getCachedContent()); - $this->assertEquals('hello world', $tpl2->getCachedContent()); - $this->assertEquals('hello world', $tpl3->getCachedContent()); + $this->assertEquals('hello world', $this->getCachedContent($tpl)); + $this->assertEquals('hello world', $this->getCachedContent($tpl2)); + $this->assertEquals('hello world', $this->getCachedContent($tpl3)); // test number of deleted caches $this->doClearCacheAssertion(1, $this->smarty->clearCache('helloworld.tpl', null, 'blar2')); // test that caches are deleted properly - $this->assertEquals('hello world', $tpl->getCachedContent()); - $this->assertNull($tpl2->getCachedContent()); - $this->assertEquals('hello world', $tpl3->getCachedContent()); + $this->assertEquals('hello world', $this->getCachedContent($tpl)); + $this->assertNull($this->getCachedContent($tpl2)); + $this->assertEquals('hello world', $this->getCachedContent($tpl3)); } public function testClearCacheCacheIdCompileId4() @@ -226,21 +231,21 @@ abstract class CacheResourceTestCommon extends PHPUnit_Smarty $this->smarty->clearAllCache(); // create and cache templates $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); - $tpl->writeCachedContent('hello world'); + $this->writeCachedContent($tpl, 'hello world'); $tpl2 = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar2'); - $tpl2->writeCachedContent('hello world'); + $this->writeCachedContent($tpl2, 'hello world'); $tpl3 = $this->smarty->createTemplate('helloworld2.tpl', 'foo|bar', 'blar'); - $tpl3->writeCachedContent('hello world'); + $this->writeCachedContent($tpl3, 'hello world'); // test cached content - $this->assertEquals('hello world', $tpl->getCachedContent()); - $this->assertEquals('hello world', $tpl2->getCachedContent()); - $this->assertEquals('hello world', $tpl3->getCachedContent()); + $this->assertEquals('hello world', $this->getCachedContent($tpl)); + $this->assertEquals('hello world', $this->getCachedContent($tpl2)); + $this->assertEquals('hello world', $this->getCachedContent($tpl3)); // test number of deleted caches $this->doClearCacheAssertion(1, $this->smarty->clearCache('helloworld.tpl', null, 'blar2')); // test that caches are deleted properly - $this->assertEquals('hello world', $tpl->getCachedContent()); - $this->assertNull($tpl2->getCachedContent()); - $this->assertEquals('hello world', $tpl3->getCachedContent()); + $this->assertEquals('hello world', $this->getCachedContent($tpl)); + $this->assertNull($this->getCachedContent($tpl2)); + $this->assertEquals('hello world', $this->getCachedContent($tpl3)); } public function testClearCacheCacheIdCompileId4Sub() @@ -250,21 +255,21 @@ abstract class CacheResourceTestCommon extends PHPUnit_Smarty $this->smarty->clearAllCache(); // create and cache templates $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); - $tpl->writeCachedContent('hello world'); + $this->writeCachedContent($tpl, 'hello world'); $tpl2 = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar2'); - $tpl2->writeCachedContent('hello world'); + $this->writeCachedContent($tpl2, 'hello world'); $tpl3 = $this->smarty->createTemplate('helloworld2.tpl', 'foo|bar', 'blar'); - $tpl3->writeCachedContent('hello world'); + $this->writeCachedContent($tpl3, 'hello world'); // test cached content - $this->assertEquals('hello world', $tpl->getCachedContent()); - $this->assertEquals('hello world', $tpl2->getCachedContent()); - $this->assertEquals('hello world', $tpl3->getCachedContent()); + $this->assertEquals('hello world', $this->getCachedContent($tpl)); + $this->assertEquals('hello world', $this->getCachedContent($tpl2)); + $this->assertEquals('hello world', $this->getCachedContent($tpl3)); // test number of deleted caches $this->doClearCacheAssertion(1, $this->smarty->clearCache('helloworld.tpl', null, 'blar2')); // test that caches are deleted properly - $this->assertEquals('hello world', $tpl->getCachedContent()); - $this->assertNull($tpl2->getCachedContent()); - $this->assertEquals('hello world', $tpl3->getCachedContent()); + $this->assertEquals('hello world', $this->getCachedContent($tpl)); + $this->assertNull($this->getCachedContent($tpl2)); + $this->assertEquals('hello world', $this->getCachedContent($tpl3)); } public function testClearCacheCacheIdCompileId5() @@ -274,21 +279,21 @@ abstract class CacheResourceTestCommon extends PHPUnit_Smarty $this->smarty->clearAllCache(); // create and cache templates $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); - $tpl->writeCachedContent('hello world'); + $this->writeCachedContent($tpl, 'hello world'); $tpl2 = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar2'); - $tpl2->writeCachedContent('hello world'); + $this->writeCachedContent($tpl2, 'hello world'); $tpl3 = $this->smarty->createTemplate('helloworld2.tpl', 'foo|bar', 'blar'); - $tpl3->writeCachedContent('hello world'); + $this->writeCachedContent($tpl3, 'hello world'); // test cached content - $this->assertEquals('hello world', $tpl->getCachedContent()); - $this->assertEquals('hello world', $tpl2->getCachedContent()); - $this->assertEquals('hello world', $tpl3->getCachedContent()); + $this->assertEquals('hello world', $this->getCachedContent($tpl)); + $this->assertEquals('hello world', $this->getCachedContent($tpl2)); + $this->assertEquals('hello world', $this->getCachedContent($tpl3)); // test number of deleted caches $this->doClearCacheAssertion(2, $this->smarty->clearCache(null, null, 'blar')); // test that caches are deleted properly - $this->assertNull($tpl->getCachedContent()); - $this->assertEquals('hello world', $tpl2->getCachedContent()); - $this->assertNull($tpl3->getCachedContent()); + $this->assertNull($this->getCachedContent($tpl)); + $this->assertEquals('hello world', $this->getCachedContent($tpl2)); + $this->assertNull($this->getCachedContent($tpl3)); } public function testClearCacheCacheIdCompileId5Sub() @@ -298,21 +303,21 @@ abstract class CacheResourceTestCommon extends PHPUnit_Smarty $this->smarty->clearAllCache(); // create and cache templates $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); - $tpl->writeCachedContent('hello world'); + $this->writeCachedContent($tpl, 'hello world'); $tpl2 = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar2'); - $tpl2->writeCachedContent('hello world'); + $this->writeCachedContent($tpl2, 'hello world'); $tpl3 = $this->smarty->createTemplate('helloworld2.tpl', 'foo|bar', 'blar'); - $tpl3->writeCachedContent('hello world'); + $this->writeCachedContent($tpl3, 'hello world'); // test cached content - $this->assertEquals('hello world', $tpl->getCachedContent()); - $this->assertEquals('hello world', $tpl2->getCachedContent()); - $this->assertEquals('hello world', $tpl3->getCachedContent()); + $this->assertEquals('hello world', $this->getCachedContent($tpl)); + $this->assertEquals('hello world', $this->getCachedContent($tpl2)); + $this->assertEquals('hello world', $this->getCachedContent($tpl3)); // test number of deleted caches $this->doClearCacheAssertion(2, $this->smarty->clearCache(null, null, 'blar')); // test that caches are deleted properly - $this->assertNull($tpl->getCachedContent()); - $this->assertEquals('hello world', $tpl2->getCachedContent()); - $this->assertNull($tpl3->getCachedContent()); + $this->assertNull($this->getCachedContent($tpl)); + $this->assertEquals('hello world', $this->getCachedContent($tpl2)); + $this->assertNull($this->getCachedContent($tpl3)); } public function testClearCacheCacheFile() @@ -322,25 +327,25 @@ abstract class CacheResourceTestCommon extends PHPUnit_Smarty $this->smarty->clearAllCache(); // create and cache templates $tpl = $this->smarty->createTemplate('helloworld.tpl'); - $tpl->writeCachedContent('hello world'); + $this->writeCachedContent($tpl, 'hello world'); $tpl2 = $this->smarty->createTemplate('helloworld.tpl', null, 'bar'); - $tpl2->writeCachedContent('hello world'); + $this->writeCachedContent($tpl2, 'hello world'); $tpl3 = $this->smarty->createTemplate('helloworld.tpl', 'buh|blar'); - $tpl3->writeCachedContent('hello world'); + $this->writeCachedContent($tpl3, 'hello world'); $tpl4 = $this->smarty->createTemplate('helloworld2.tpl'); - $tpl4->writeCachedContent('hello world'); + $this->writeCachedContent($tpl4, 'hello world'); // test cached content - $this->assertEquals('hello world', $tpl->getCachedContent()); - $this->assertEquals('hello world', $tpl2->getCachedContent()); - $this->assertEquals('hello world', $tpl3->getCachedContent()); - $this->assertEquals('hello world', $tpl4->getCachedContent()); + $this->assertEquals('hello world', $this->getCachedContent($tpl)); + $this->assertEquals('hello world', $this->getCachedContent($tpl2)); + $this->assertEquals('hello world', $this->getCachedContent($tpl3)); + $this->assertEquals('hello world', $this->getCachedContent($tpl4)); // test number of deleted caches $this->doClearCacheAssertion(3, $this->smarty->clearCache('helloworld.tpl')); // test that caches are deleted properly - $this->assertNull($tpl->getCachedContent()); - $this->assertNull($tpl2->getCachedContent()); - $this->assertNull($tpl3->getCachedContent()); - $this->assertEquals('hello world', $tpl4->getCachedContent()); + $this->assertNull($this->getCachedContent($tpl)); + $this->assertNull($this->getCachedContent($tpl2)); + $this->assertNull($this->getCachedContent($tpl3)); + $this->assertEquals('hello world', $this->getCachedContent($tpl4)); } /** @@ -353,18 +358,18 @@ abstract class CacheResourceTestCommon extends PHPUnit_Smarty $this->smarty->clearAllCache(); // create and cache templates $tpl = $this->smarty->createTemplate('helloworld.tpl'); - $tpl->writeCachedContent('something else 1'); + $this->writeCachedContent($tpl, 'something else 1'); $tpl2 = $this->smarty->createTemplate('helloworld.tpl', null, 'bar'); - $tpl2->writeCachedContent('something else 2'); + $this->writeCachedContent($tpl2, 'something else 2'); $tpl3 = $this->smarty->createTemplate('helloworld.tpl', 'buh|blar'); - $tpl3->writeCachedContent('something else 3'); + $this->writeCachedContent($tpl3, 'something else 3'); // test cached content - $this->assertEquals('something else 1', $tpl->getCachedContent()); - $this->assertEquals('something else 2', $tpl2->getCachedContent()); - $this->assertEquals('something else 3', $tpl3->getCachedContent()); + $this->assertEquals('something else 1', $this->getCachedContent($tpl)); + $this->assertEquals('something else 2', $this->getCachedContent($tpl2)); + $this->assertEquals('something else 3', $this->getCachedContent($tpl3)); sleep(10); $tpl4 = $this->smarty->createTemplate('helloworld2.tpl'); - $tpl4->writeCachedContent('something else 4'); + $this->writeCachedContent($tpl4, 'something else 4'); // test number of deleted caches $this->doClearCacheAssertion(3,$this->smarty->clearAllCache(5)); @@ -375,10 +380,10 @@ abstract class CacheResourceTestCommon extends PHPUnit_Smarty $tpl4 = $this->smarty->createTemplate('helloworld2.tpl'); // test that caches are deleted properly - $this->assertEquals('hello world', $tpl->getCachedContent()); - $this->assertEquals('hello world', $tpl2->getCachedContent()); - $this->assertEquals('hello world', $tpl3->getCachedContent()); - $this->assertEquals('something else 4', $tpl4->getCachedContent()); + $this->assertEquals('hello world', $this->getCachedContent($tpl)); + $this->assertEquals('hello world', $this->getCachedContent($tpl2)); + $this->assertEquals('hello world', $this->getCachedContent($tpl3)); + $this->assertEquals('something else 4', $this->getCachedContent($tpl4)); } public function testClearCacheCacheFileSub() @@ -388,25 +393,25 @@ abstract class CacheResourceTestCommon extends PHPUnit_Smarty $this->smarty->clearAllCache(); // create and cache templates $tpl = $this->smarty->createTemplate('helloworld.tpl'); - $tpl->writeCachedContent('hello world'); + $this->writeCachedContent($tpl, 'hello world'); $tpl2 = $this->smarty->createTemplate('helloworld.tpl', null, 'bar'); - $tpl2->writeCachedContent('hello world'); + $this->writeCachedContent($tpl2, 'hello world'); $tpl3 = $this->smarty->createTemplate('helloworld.tpl', 'buh|blar'); - $tpl3->writeCachedContent('hello world'); + $this->writeCachedContent($tpl3, 'hello world'); $tpl4 = $this->smarty->createTemplate('helloworld2.tpl'); - $tpl4->writeCachedContent('hello world'); + $this->writeCachedContent($tpl4, 'hello world'); // test cached content - $this->assertEquals('hello world', $tpl->getCachedContent()); - $this->assertEquals('hello world', $tpl2->getCachedContent()); - $this->assertEquals('hello world', $tpl3->getCachedContent()); - $this->assertEquals('hello world', $tpl4->getCachedContent()); + $this->assertEquals('hello world', $this->getCachedContent($tpl)); + $this->assertEquals('hello world', $this->getCachedContent($tpl2)); + $this->assertEquals('hello world', $this->getCachedContent($tpl3)); + $this->assertEquals('hello world', $this->getCachedContent($tpl4)); // test number of deleted caches $this->doClearCacheAssertion(3, $this->smarty->clearCache('helloworld.tpl')); // test that caches are deleted properly - $this->assertNull($tpl->getCachedContent()); - $this->assertNull($tpl2->getCachedContent()); - $this->assertNull($tpl3->getCachedContent()); - $this->assertEquals('hello world', $tpl4->getCachedContent()); + $this->assertNull($this->getCachedContent($tpl)); + $this->assertNull($this->getCachedContent($tpl2)); + $this->assertNull($this->getCachedContent($tpl3)); + $this->assertEquals('hello world', $this->getCachedContent($tpl4)); } /** * Test caching diff --git a/tests/UnitTests/ResourceTests/Custom/DemoPluginMysql/ResourceMysqlPluginTest.php b/tests/UnitTests/ResourceTests/Custom/DemoPluginMysql/ResourceMysqlPluginTest.php index 2a96cefc..9de4a30e 100644 --- a/tests/UnitTests/ResourceTests/Custom/DemoPluginMysql/ResourceMysqlPluginTest.php +++ b/tests/UnitTests/ResourceTests/Custom/DemoPluginMysql/ResourceMysqlPluginTest.php @@ -98,7 +98,7 @@ if (MysqlResourceEnable == true) { { //$this->smarty->addPluginsDir("./PHPunitplugins/"); $tpl = $this->smarty->createTemplate('mysqltest:test.tpl'); - $this->assertEquals($this->buildCompiledPath($tpl, false, false, null, 'test.tpl', 'mysqltest', $this->smarty->getTemplateDir(0)), $tpl->getCompiled()->filepath); + $this->assertEquals($this->buildCompiledPath($tpl, false, null, 'test.tpl', 'mysqltest', $this->smarty->getTemplateDir(0)), $tpl->getCompiled()->filepath); } public function testResourcePluginMysqlCompiledFilepathCache() @@ -108,7 +108,7 @@ if (MysqlResourceEnable == true) { $this->smarty->setForceCompile(true); $this->smarty->fetch('mysqltest:test.tpl'); $tpl = $this->smarty->createTemplate('mysqltest:test.tpl'); - $this->assertEquals($this->buildCompiledPath($tpl, false, true, null, 'test.tpl', 'mysqltest', $this->smarty->getTemplateDir(0)), $tpl->getCompiled()->filepath); + $this->assertEquals($this->buildCompiledPath($tpl, true, null, 'test.tpl', 'mysqltest', $this->smarty->getTemplateDir(0)), $tpl->getCompiled()->filepath); $this->smarty->caching = false; } diff --git a/tests/UnitTests/ResourceTests/File/FileResourceTest.php b/tests/UnitTests/ResourceTests/File/FileResourceTest.php index 17a1be3f..458ea104 100644 --- a/tests/UnitTests/ResourceTests/File/FileResourceTest.php +++ b/tests/UnitTests/ResourceTests/File/FileResourceTest.php @@ -105,7 +105,7 @@ class FileResourceTest extends PHPUnit_Smarty public function testGetCompiledFilepath() { $tpl = $this->smarty->createTemplate('helloworld.tpl'); - $this->assertEquals($this->buildCompiledPath($tpl, false, false, null, 'helloworld.tpl', 'file', $this->smarty->getTemplateDir(0)) + $this->assertEquals($this->buildCompiledPath($tpl, false, null, 'helloworld.tpl', 'file', $this->smarty->getTemplateDir(0)) , $tpl->getCompiled()->filepath ); } @@ -175,7 +175,7 @@ class FileResourceTest extends PHPUnit_Smarty $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') + $this->assertEquals($this->buildCachedPath($tpl, null, null, 'helloworld.tpl', 'file', $this->smarty->getTemplateDir(0), 'file') , $tpl->getCached()->filepath ); } @@ -183,7 +183,7 @@ class FileResourceTest extends PHPUnit_Smarty 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') + file_put_contents($this->buildCachedPath($this->smarty, null, null, 'helloworld.tpl', 'file', $this->smarty->getTemplateDir(0), 'file') , ''); $this->smarty->caching = true; $this->smarty->cache_lifetime = 1000; diff --git a/tests/UnitTests/ResourceTests/FileIndexed/FileResourceIndexedTest.php b/tests/UnitTests/ResourceTests/FileIndexed/FileResourceIndexedTest.php index c85c8b95..fd57ebbc 100644 --- a/tests/UnitTests/ResourceTests/FileIndexed/FileResourceIndexedTest.php +++ b/tests/UnitTests/ResourceTests/FileIndexed/FileResourceIndexedTest.php @@ -101,7 +101,7 @@ 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); + $this->assertEquals($this->buildCompiledPath($tpl, false, null, 'dirname.tpl', 'file', $this->smarty->getTemplateDir('foo')), $tpl->getCompiled()->filepath); } public function testGetCachedFilepath() @@ -109,7 +109,7 @@ class FileResourceIndexedTest extends PHPUnit_Smarty $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')) + $this->assertEquals($this->buildCachedPath($tpl, null, null, 'dirname.tpl', 'file', $this->smarty->getTemplateDir('foo')) , $tpl->getCached()->filepath); } } diff --git a/tests/UnitTests/ResourceTests/Stream/StreamResourceTest.php b/tests/UnitTests/ResourceTests/Stream/StreamResourceTest.php index acaa8a31..8da91988 100644 --- a/tests/UnitTests/ResourceTests/Stream/StreamResourceTest.php +++ b/tests/UnitTests/ResourceTests/Stream/StreamResourceTest.php @@ -8,10 +8,6 @@ /** * class for stream resource tests - * - * - * - * */ class StreamResourceTest extends PHPUnit_Smarty { @@ -156,7 +152,7 @@ class StreamResourceTest extends PHPUnit_Smarty public function testWriteCachedContent() { $tpl = $this->smarty->createTemplate('global:mytest'); - $this->assertFalse($tpl->writeCachedContent('dummy')); + $this->assertFalse($tpl->getCached()->handler->storeCachedContent($tpl, 'dummy')); } /** diff --git a/tests/UnitTests/ResourceTests/String/StringResourceTest.php b/tests/UnitTests/ResourceTests/String/StringResourceTest.php index 4e4cdd13..c1e50981 100644 --- a/tests/UnitTests/ResourceTests/String/StringResourceTest.php +++ b/tests/UnitTests/ResourceTests/String/StringResourceTest.php @@ -110,7 +110,7 @@ class StringResourceTest extends PHPUnit_Smarty 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); + $this->assertEquals($this->buildCompiledPath($tpl, false, null, 'hello world', 'string', $this->smarty->getTemplateDir(0)), $tpl->getCompiled()->filepath); } /** @@ -146,7 +146,7 @@ class StringResourceTest extends PHPUnit_Smarty public function testWriteCachedContent() { $tpl = $this->smarty->createTemplate('string:hello world'); - $this->assertFalse($tpl->writeCachedContent('dummy')); + $this->assertFalse($this->writeCachedContent($tpl, 'dummy')); } /** diff --git a/tests/UnitTests/SmartyMethodsTests/Append/AppendTest.php b/tests/UnitTests/SmartyMethodsTests/Append/AppendTest.php index 43736d01..dd20c0f0 100644 --- a/tests/UnitTests/SmartyMethodsTests/Append/AppendTest.php +++ b/tests/UnitTests/SmartyMethodsTests/Append/AppendTest.php @@ -8,10 +8,6 @@ /** * class for append tests - * - * - * - * */ class AppendTest extends PHPUnit_Smarty { diff --git a/tests/UnitTests/SmartyMethodsTests/ClearCompiledTemplate/ClearCompiledTest.php b/tests/UnitTests/SmartyMethodsTests/ClearCompiledTemplate/ClearCompiledTest.php index ed1c818c..8c6dbf18 100644 --- a/tests/UnitTests/SmartyMethodsTests/ClearCompiledTemplate/ClearCompiledTest.php +++ b/tests/UnitTests/SmartyMethodsTests/ClearCompiledTemplate/ClearCompiledTest.php @@ -160,7 +160,7 @@ class ClearCompiledTest extends PHPUnit_Smarty public function runClearAll($useSubDirs) { - $this->getSmarty()->setUseSubDirs($useSubDirs); + $this->clearFiles(); $this->makeFiles(); @@ -194,7 +194,7 @@ class ClearCompiledTest extends PHPUnit_Smarty public function runClearTemplate($useSubDirs) { - $this->getSmarty()->setUseSubDirs($useSubDirs); + $this->clearFiles(); $this->makeFiles(); @@ -211,7 +211,7 @@ class ClearCompiledTest extends PHPUnit_Smarty public function runClearOtherTemplate($useSubDirs) { - $this->getSmarty()->setUseSubDirs($useSubDirs); + $this->clearFiles(); $this->makeFiles(); @@ -245,7 +245,7 @@ class ClearCompiledTest extends PHPUnit_Smarty public function runClearCompileid($useSubDirs) { - $this->getSmarty()->setUseSubDirs($useSubDirs); + $this->clearFiles(); $this->makeFiles(); @@ -264,7 +264,7 @@ class ClearCompiledTest extends PHPUnit_Smarty public function runClearOtherCompileid($useSubDirs) { - $this->getSmarty()->setUseSubDirs($useSubDirs); + $this->clearFiles(); $this->makeFiles(); @@ -288,7 +288,7 @@ class ClearCompiledTest extends PHPUnit_Smarty public function runClearExpired($useSubDirs) { - $this->getSmarty()->setUseSubDirs($useSubDirs); + $this->clearFiles(); $this->makeFiles(); @@ -313,7 +313,7 @@ class ClearCompiledTest extends PHPUnit_Smarty public function runClearTemplateExpired($useSubDirs) { - $this->getSmarty()->setUseSubDirs($useSubDirs); + $this->clearFiles(); $this->makeFiles(); @@ -343,7 +343,7 @@ class ClearCompiledTest extends PHPUnit_Smarty public function runClearTemplateCacheidExpired($useSubDirs) { - $this->getSmarty()->setUseSubDirs($useSubDirs); + $this->clearFiles(); $this->makeFiles(); @@ -373,7 +373,7 @@ class ClearCompiledTest extends PHPUnit_Smarty public function runClearCacheidExpired($useSubDirs) { - $this->getSmarty()->setUseSubDirs($useSubDirs); + $this->clearFiles(); $this->makeFiles(); @@ -403,7 +403,7 @@ class ClearCompiledTest extends PHPUnit_Smarty public function runClearTemplateCacheid($useSubDirs) { - $this->getSmarty()->setUseSubDirs($useSubDirs); + $this->clearFiles(); $this->makeFiles(); @@ -431,7 +431,7 @@ class ClearCompiledTest extends PHPUnit_Smarty public function runClearAmbiguousTemplate($useSubDirs) { - $this->getSmarty()->setUseSubDirs($useSubDirs); + $this->clearFiles(); $this->makeFiles();