mirror of
https://github.com/smarty-php/smarty.git
synced 2025-08-03 09:54:27 +02:00
Re-organized rendering (read source / compile / cache) process to avoid circular dependencies.
This commit is contained in:
@@ -67,25 +67,6 @@ abstract class Base
|
||||
*/
|
||||
abstract public function retrieveCachedContent(Template $_template);
|
||||
|
||||
/**
|
||||
* Return cached content
|
||||
*
|
||||
* @param Template $_template template object
|
||||
*
|
||||
* @return null|string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getCachedContent(Template $_template)
|
||||
{
|
||||
if ($this->process($_template)) {
|
||||
ob_start();
|
||||
$unifunc = $_template->getCached()->unifunc;
|
||||
$unifunc($_template);
|
||||
return ob_get_clean();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty cache
|
||||
*
|
||||
|
@@ -186,69 +186,4 @@ class IncludeTag extends Base {
|
||||
return $_output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile inline sub template
|
||||
*
|
||||
* @param \Smarty\Compiler\Template $compiler
|
||||
* @param \Smarty\Template $tpl
|
||||
* @param string $t_hash
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
* @throws \Smarty\Exception
|
||||
*/
|
||||
private function compileInlineTemplate(
|
||||
Template $compiler,
|
||||
\Smarty\Template $tpl,
|
||||
$t_hash
|
||||
) {
|
||||
$tplSource = $tpl->getSource();
|
||||
$uid = $tplSource->type . $tplSource->uid;
|
||||
if ($tplSource->exists) {
|
||||
$compiler->getParentCompiler()->mergedSubTemplatesData[$uid][$t_hash]['uid'] = $tplSource->uid;
|
||||
$tpl->getCompiled(true)->nocache_hash = $compiler->getParentCompiler()->getTemplate()->getCompiled()->nocache_hash;
|
||||
// save unique function name
|
||||
$compiler->getParentCompiler()->mergedSubTemplatesData[$uid][$t_hash]['func'] =
|
||||
$tpl->getCompiled()->unifunc = 'content_' . str_replace(['.', ','], '_', uniqid('', true));
|
||||
// make sure whole chain gets compiled
|
||||
$tpl->mustCompile = true;
|
||||
$compiler->getParentCompiler()->mergedSubTemplatesData[$uid][$t_hash]['nocache_hash'] =
|
||||
$tpl->getCompiled()->nocache_hash;
|
||||
if ($tplSource->type === 'file') {
|
||||
$sourceInfo = $tplSource->filepath;
|
||||
} else {
|
||||
$basename = $tplSource->getBasename();
|
||||
$sourceInfo = $tplSource->type . ':' .
|
||||
($basename ? $basename : $tplSource->name);
|
||||
}
|
||||
// get compiled code
|
||||
$compiled_code = "<?php\n\n";
|
||||
$compiled_code .= $compiler->cStyleComment(" Start inline template \"{$sourceInfo}\" =============================") . "\n";
|
||||
$compiled_code .= "function {$tpl->getCompiled()->unifunc} (\\Smarty\\Template \$_smarty_tpl) {\n";
|
||||
$compiled_code .= "?>\n" . $tpl->getCompiler()->compileTemplateSource($tpl, $compiler->getParentCompiler());
|
||||
$compiled_code .= "<?php\n";
|
||||
$compiled_code .= "}\n?>\n";
|
||||
$compiled_code .= $tpl->getSmarty()->runPostFilters($tpl->getCompiler()->blockOrFunctionCode, $tpl);
|
||||
$compiled_code .= "<?php\n\n";
|
||||
$compiled_code .= $compiler->cStyleComment(" End inline template \"{$sourceInfo}\" =============================") . "\n";
|
||||
$compiled_code .= '?>';
|
||||
|
||||
// unset($tpl->compiler); // @TODO removed this.
|
||||
|
||||
if ($tpl->getCompiled()->getNocacheCode()) {
|
||||
// replace nocache_hash
|
||||
$compiled_code =
|
||||
str_replace(
|
||||
"{$tpl->getCompiled()->nocache_hash}",
|
||||
$compiler->getTemplate()->getCompiled()->nocache_hash,
|
||||
$compiled_code
|
||||
);
|
||||
$compiler->getTemplate()->getCompiled()->setNocacheCode(true);
|
||||
}
|
||||
$compiler->getParentCompiler()->mergedSubTemplatesCode[$tpl->getCompiled()->unifunc] = $compiled_code;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -62,7 +62,8 @@ class CodeFrame
|
||||
str_replace('*/', '* /', $this->_template->getSource()->filepath)
|
||||
);
|
||||
$output .= "/* @var \\Smarty\\Template \$_smarty_tpl */\n";
|
||||
$dec = "\$_smarty_tpl->isFresh(" . var_export($properties, true) . ',' . ($cache ? 'true' : 'false') . ')';
|
||||
$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)) {
|
||||
|
@@ -352,7 +352,7 @@ class Template extends BaseCompiler {
|
||||
*
|
||||
* @param \Smarty\Template $template template object to compile
|
||||
*
|
||||
* @return bool true if compiling succeeded, false if it failed
|
||||
* @return string code
|
||||
* @throws Exception
|
||||
*/
|
||||
public function compileTemplate(\Smarty\Template $template) {
|
||||
|
@@ -203,7 +203,6 @@ class Debug extends Data
|
||||
$debObj = new \Smarty\Smarty();
|
||||
// copy the working dirs from application
|
||||
$debObj->setCompileDir($smarty->getCompileDir());
|
||||
$debObj->force_compile = false;
|
||||
$debObj->compile_check = \Smarty::COMPILECHECK_ON;
|
||||
$debObj->security_policy = null;
|
||||
$debObj->debugging = false;
|
||||
|
@@ -36,35 +36,6 @@ abstract class RecompiledPlugin extends BasePlugin {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* compile template from source
|
||||
*
|
||||
* @param Template $_smarty_tpl do not change variable name, is used by compiled template
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function recompile(Template $_smarty_tpl) {
|
||||
$compiled = $_smarty_tpl->getCompiled();
|
||||
$compiled->file_dependency = [];
|
||||
$compiled->includes = [];
|
||||
$compiled->nocache_hash = null;
|
||||
$compiled->unifunc = null;
|
||||
$level = ob_get_level();
|
||||
ob_start();
|
||||
// call compiler
|
||||
try {
|
||||
eval('?>' . $_smarty_tpl->getCompiler()->compileTemplate($_smarty_tpl));
|
||||
} catch (\Exception $e) {
|
||||
while (ob_get_level() > $level) {
|
||||
ob_end_clean();
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
ob_get_clean();
|
||||
$compiled->timestamp = time();
|
||||
$compiled->exists = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable timestamp checks for recompiled resource.
|
||||
*
|
||||
|
@@ -56,13 +56,6 @@ class Template extends TemplateBase {
|
||||
*/
|
||||
public $template_resource = null;
|
||||
|
||||
/**
|
||||
* flag if compiled template is invalid and must be (re)compiled
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $mustCompile = null;
|
||||
|
||||
/**
|
||||
* Template ID
|
||||
*
|
||||
@@ -309,88 +302,16 @@ class Template extends TemplateBase {
|
||||
return parent::assign($tpl_var, $value, $nocache, $scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @param array $properties special template properties
|
||||
* @param bool $cache flag if called from cache file
|
||||
*
|
||||
* @return bool flag if compiled or cache file is valid
|
||||
* @throws \Smarty\Exception
|
||||
*/
|
||||
public function isFresh($properties, $cache = false) {
|
||||
// on cache resources other than file check version stored in cache code
|
||||
if (!isset($properties['version']) || \Smarty\Smarty::SMARTY_VERSION !== $properties['version']) {
|
||||
if ($cache) {
|
||||
$this->getSmarty()->clearAllCache();
|
||||
} else {
|
||||
$this->getSmarty()->clearCompiledTemplate();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
$is_valid = true;
|
||||
if (!empty($properties['file_dependency'])
|
||||
&& ((!$cache && $this->compile_check) || $this->compile_check === \Smarty\Smarty::COMPILECHECK_ON)
|
||||
) {
|
||||
// check file dependencies at compiled code
|
||||
foreach ($properties['file_dependency'] as $_file_to_check) {
|
||||
if ($_file_to_check[2] === 'file' || $_file_to_check[2] === 'php') {
|
||||
if ($this->getSource()->filepath === $_file_to_check[0]) {
|
||||
// do not recheck current template
|
||||
continue;
|
||||
//$mtime = $this->getSource()->getTimeStamp();
|
||||
} else {
|
||||
// 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($this->getSmarty(), $_file_to_check[2]);
|
||||
if ($handler->checkTimestamps()) {
|
||||
$source = Source::load($this, $this->getSmarty(), $_file_to_check[0]);
|
||||
$mtime = $source->getTimeStamp();
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ($mtime === false || $mtime > $_file_to_check[1]) {
|
||||
$is_valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($cache) {
|
||||
// CACHING_LIFETIME_SAVED cache expiry has to be validated here since otherwise we'd define the unifunc
|
||||
if ($this->caching === \Smarty\Smarty::CACHING_LIFETIME_SAVED && $properties['cache_lifetime'] >= 0
|
||||
&& (time() > ($this->getCached()->timestamp + $properties['cache_lifetime']))
|
||||
) {
|
||||
$is_valid = false;
|
||||
}
|
||||
$this->getCached()->cache_lifetime = $properties['cache_lifetime'];
|
||||
$this->getCached()->setValid($is_valid);
|
||||
$generatedFile = $this->getCached();
|
||||
} else {
|
||||
$this->mustCompile = !$is_valid;
|
||||
$generatedFile = $this->getCompiled();
|
||||
$generatedFile->includes = $properties['includes'] ?? [];
|
||||
}
|
||||
if ($is_valid) {
|
||||
$generatedFile->unifunc = $properties['unifunc'];
|
||||
$generatedFile->setNocacheCode($properties['has_nocache_code']);
|
||||
$generatedFile->file_dependency = $properties['file_dependency'];
|
||||
}
|
||||
return $is_valid && !function_exists($properties['unifunc']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles the template
|
||||
* If the template is not evaluated the compiled template is saved on disk
|
||||
*
|
||||
* @TODO only used in compileAll and 1 unit test: can we move this and make compileAndWrite private?
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function compileTemplateSource() {
|
||||
return $this->getCompiled()->compileTemplateSource($this);
|
||||
return $this->getCompiled()->compileAndWrite($this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -400,7 +321,7 @@ class Template extends TemplateBase {
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getCachedContent() {
|
||||
return $this->getCached()->handler->getCachedContent($this);
|
||||
return $this->getCached()->getContent($this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -547,7 +468,7 @@ class Template extends TemplateBase {
|
||||
* @return bool
|
||||
* @throws \Smarty\Exception
|
||||
*/
|
||||
public function mustCompile() {
|
||||
public function mustCompile(): bool {
|
||||
if (!$this->getSource()->exists) {
|
||||
if ($this->_isSubTpl()) {
|
||||
$parent_resource = " in '{$this->parent->template_resource}'";
|
||||
@@ -556,14 +477,13 @@ class Template extends TemplateBase {
|
||||
}
|
||||
throw new Exception("Unable to load template {$this->getSource()->type} '{$this->getSource()->name}'{$parent_resource}");
|
||||
}
|
||||
if ($this->mustCompile === null) {
|
||||
$this->mustCompile = $this->smarty->force_compile
|
||||
|
||||
// @TODO move this logic to Compiled
|
||||
return $this->smarty->force_compile
|
||||
|| $this->getSource()->handler->recompiled
|
||||
|| !$this->getCompiled()->exists
|
||||
|| ($this->compile_check && $this->getCompiled()->getTimeStamp() < $this->getSource()->getTimeStamp());
|
||||
}
|
||||
return $this->mustCompile;
|
||||
}
|
||||
|
||||
private function getCodeFrameCompiler(): Compiler\CodeFrame {
|
||||
return new \Smarty\Compiler\CodeFrame($this);
|
||||
|
@@ -216,11 +216,7 @@ class Cached extends GeneratedPhpFile {
|
||||
if ($this->handler->process($_template, $this, $update) === false) {
|
||||
$this->valid = false;
|
||||
}
|
||||
if ($this->valid) {
|
||||
$this->processed = true;
|
||||
} else {
|
||||
$this->processed = false;
|
||||
}
|
||||
$this->processed = $this->valid;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -287,10 +283,8 @@ class Cached extends GeneratedPhpFile {
|
||||
|
||||
$this->removeNoCacheHash($_template, $no_output_filter);
|
||||
|
||||
$compile_check = (int)$_template->compile_check;
|
||||
$_template->compile_check = \Smarty\Smarty::COMPILECHECK_OFF;
|
||||
|
||||
if ($_template->_isSubTpl()) {
|
||||
// @TODO why is this needed?
|
||||
$_template->getCompiled()->unifunc = $_template->parent->getCompiled()->unifunc;
|
||||
}
|
||||
|
||||
@@ -298,8 +292,6 @@ class Cached extends GeneratedPhpFile {
|
||||
$this->process($_template, true);
|
||||
}
|
||||
|
||||
$_template->compile_check = $compile_check;
|
||||
|
||||
if ($_template->getSmarty()->debugging) {
|
||||
$_template->getSmarty()->getDebug()->end_cache($_template);
|
||||
}
|
||||
@@ -386,4 +378,60 @@ class Cached extends GeneratedPhpFile {
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the generated content
|
||||
*
|
||||
* @param Template $template
|
||||
*
|
||||
* @return string|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getContent(Template $template) {
|
||||
ob_start();
|
||||
$this->render($template);
|
||||
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']);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Smarty\Template;
|
||||
|
||||
use Smarty\Exception;
|
||||
use Smarty\Template;
|
||||
|
||||
/**
|
||||
@@ -25,6 +26,10 @@ class Compiled extends GeneratedPhpFile {
|
||||
* @var int[]
|
||||
*/
|
||||
public $includes = [];
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $isValid = false;
|
||||
|
||||
/**
|
||||
* get a Compiled Object of this source
|
||||
@@ -103,14 +108,17 @@ class Compiled extends GeneratedPhpFile {
|
||||
$this->compileAndLoad($_template);
|
||||
}
|
||||
|
||||
// @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->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);
|
||||
}
|
||||
@@ -124,26 +132,48 @@ class Compiled extends GeneratedPhpFile {
|
||||
* @throws Exception
|
||||
*/
|
||||
private function compileAndLoad(Template $_smarty_tpl) {
|
||||
$source = $_smarty_tpl->getSource();
|
||||
$smarty = $_smarty_tpl->getSmarty();
|
||||
if ($source->handler->recompiled) {
|
||||
$source->handler->recompile($_smarty_tpl); // @TODO who is compiling here?
|
||||
} else {
|
||||
if (!$this->exists || $smarty->force_compile
|
||||
|| ($_smarty_tpl->compile_check && $source->getTimeStamp() > $this->getTimeStamp())
|
||||
|
||||
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->compileTemplateSource($_smarty_tpl);
|
||||
$this->loadCompiledTemplate($_smarty_tpl);
|
||||
} else {
|
||||
$_smarty_tpl->mustCompile = true;
|
||||
@include $this->filepath;
|
||||
if ($_smarty_tpl->mustCompile) {
|
||||
$this->compileTemplateSource($_smarty_tpl);
|
||||
$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));
|
||||
} catch (\Exception $e) {
|
||||
while (ob_get_level() > $level) {
|
||||
ob_end_clean();
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
ob_get_clean();
|
||||
$this->timestamp = time();
|
||||
$this->exists = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,11 +183,7 @@ class Compiled extends GeneratedPhpFile {
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function compileTemplateSource(Template $_template) {
|
||||
$this->file_dependency = [];
|
||||
$this->includes = [];
|
||||
$this->nocache_hash = null;
|
||||
$this->unifunc = null;
|
||||
public function compileAndWrite(Template $_template) {
|
||||
// compile locking
|
||||
if ($saved_timestamp = (!$_template->getSource()->handler->recompiled && is_file($this->filepath))) {
|
||||
$saved_timestamp = $this->getTimeStamp();
|
||||
@@ -166,7 +192,7 @@ class Compiled extends GeneratedPhpFile {
|
||||
// compile locking
|
||||
try {
|
||||
// call compiler
|
||||
$this->write($_template, $_template->getCompiler()->compileTemplate($_template));
|
||||
$this->write($_template, $this->doCompile($_template));
|
||||
} catch (\Exception $e) {
|
||||
// restore old timestamp in case of error
|
||||
if ($saved_timestamp && is_file($this->filepath)) {
|
||||
@@ -176,6 +202,22 @@ class Compiled extends GeneratedPhpFile {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the actual compiling.
|
||||
*
|
||||
* @param Template $_smarty_tpl
|
||||
*
|
||||
* @return string
|
||||
* @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
|
||||
*
|
||||
@@ -203,11 +245,11 @@ class Compiled extends GeneratedPhpFile {
|
||||
* Load fresh compiled template by including the PHP file
|
||||
* HHVM requires a workaround because of a PHP incompatibility
|
||||
*
|
||||
* @param \Smarty\Template $_smarty_tpl do not change variable name, is used by compiled template
|
||||
* @param Template $_smarty_tpl do not change/remove variable name, is used by compiled template
|
||||
*
|
||||
*/
|
||||
private function loadCompiledTemplate(Template $_smarty_tpl) {
|
||||
$compileCheck = $_smarty_tpl->compile_check;
|
||||
$_smarty_tpl->compile_check = \Smarty\Smarty::COMPILECHECK_OFF;
|
||||
|
||||
if (function_exists('opcache_invalidate')
|
||||
&& (!function_exists('ini_get') || strlen(ini_get("opcache.restrict_api")) < 1)
|
||||
) {
|
||||
@@ -220,7 +262,41 @@ class Compiled extends GeneratedPhpFile {
|
||||
} else {
|
||||
include $this->filepath;
|
||||
}
|
||||
$_smarty_tpl->compile_check = $compileCheck;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @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) {
|
||||
$is_valid = $this->checkFileDependencies($properties['file_dependency'], $_template);
|
||||
}
|
||||
|
||||
$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'];
|
||||
}
|
||||
return $is_valid && !function_exists($properties['unifunc']);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -2,8 +2,12 @@
|
||||
|
||||
namespace Smarty\Template;
|
||||
|
||||
use Smarty\Exception;
|
||||
use Smarty\Template;
|
||||
|
||||
/**
|
||||
* Base class for generated PHP files, such as compiled and cached versions of templates and config files.
|
||||
*
|
||||
* @author Rodney Rehm
|
||||
*/
|
||||
abstract class GeneratedPhpFile {
|
||||
@@ -113,4 +117,37 @@ abstract class GeneratedPhpFile {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -353,25 +353,32 @@ abstract class CacheResourceTestCommon extends PHPUnit_Smarty
|
||||
$this->smarty->clearAllCache();
|
||||
// create and cache templates
|
||||
$tpl = $this->smarty->createTemplate('helloworld.tpl');
|
||||
$tpl->writeCachedContent('hello world');
|
||||
$tpl->writeCachedContent('something else 1');
|
||||
$tpl2 = $this->smarty->createTemplate('helloworld.tpl', null, 'bar');
|
||||
$tpl2->writeCachedContent('hello world');
|
||||
$tpl2->writeCachedContent('something else 2');
|
||||
$tpl3 = $this->smarty->createTemplate('helloworld.tpl', 'buh|blar');
|
||||
$tpl3->writeCachedContent('hello world');
|
||||
$tpl3->writeCachedContent('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());
|
||||
sleep(10);
|
||||
$tpl4 = $this->smarty->createTemplate('helloworld2.tpl');
|
||||
$tpl4->writeCachedContent('something else 4');
|
||||
|
||||
// test number of deleted caches
|
||||
$this->doClearCacheAssertion(3,$this->smarty->clearAllCache(5));
|
||||
|
||||
$tpl = $this->smarty->createTemplate('helloworld.tpl');
|
||||
$tpl2 = $this->smarty->createTemplate('helloworld.tpl', null, 'bar');
|
||||
$tpl3 = $this->smarty->createTemplate('helloworld.tpl', 'buh|blar');
|
||||
$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());
|
||||
sleep(10);
|
||||
$tpl4 = $this->smarty->createTemplate('helloworld2.tpl');
|
||||
$tpl4->writeCachedContent('hello world');
|
||||
// test number of deleted caches
|
||||
$this->doClearCacheAssertion(3,$this->smarty->clearAllCache(5));
|
||||
// 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->assertEquals('something else 4', $tpl4->getCachedContent());
|
||||
}
|
||||
|
||||
public function testClearCacheCacheFileSub()
|
||||
|
Reference in New Issue
Block a user