mirror of
https://github.com/smarty-php/smarty.git
synced 2025-08-03 18:04:26 +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);
|
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
|
* Empty cache
|
||||||
*
|
*
|
||||||
|
@@ -186,69 +186,4 @@ class IncludeTag extends Base {
|
|||||||
return $_output;
|
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)
|
str_replace('*/', '* /', $this->_template->getSource()->filepath)
|
||||||
);
|
);
|
||||||
$output .= "/* @var \\Smarty\\Template \$_smarty_tpl */\n";
|
$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 .= "if ({$dec}) {\n";
|
||||||
$output .= "function {$properties['unifunc']} (\\Smarty\\Template \$_smarty_tpl) {\n";
|
$output .= "function {$properties['unifunc']} (\\Smarty\\Template \$_smarty_tpl) {\n";
|
||||||
if (!$cache && !empty($compiler->tpl_function)) {
|
if (!$cache && !empty($compiler->tpl_function)) {
|
||||||
|
@@ -352,7 +352,7 @@ class Template extends BaseCompiler {
|
|||||||
*
|
*
|
||||||
* @param \Smarty\Template $template template object to compile
|
* @param \Smarty\Template $template template object to compile
|
||||||
*
|
*
|
||||||
* @return bool true if compiling succeeded, false if it failed
|
* @return string code
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function compileTemplate(\Smarty\Template $template) {
|
public function compileTemplate(\Smarty\Template $template) {
|
||||||
|
@@ -203,7 +203,6 @@ class Debug extends Data
|
|||||||
$debObj = new \Smarty\Smarty();
|
$debObj = new \Smarty\Smarty();
|
||||||
// copy the working dirs from application
|
// copy the working dirs from application
|
||||||
$debObj->setCompileDir($smarty->getCompileDir());
|
$debObj->setCompileDir($smarty->getCompileDir());
|
||||||
$debObj->force_compile = false;
|
|
||||||
$debObj->compile_check = \Smarty::COMPILECHECK_ON;
|
$debObj->compile_check = \Smarty::COMPILECHECK_ON;
|
||||||
$debObj->security_policy = null;
|
$debObj->security_policy = null;
|
||||||
$debObj->debugging = false;
|
$debObj->debugging = false;
|
||||||
|
@@ -36,35 +36,6 @@ abstract class RecompiledPlugin extends BasePlugin {
|
|||||||
return false;
|
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.
|
* Disable timestamp checks for recompiled resource.
|
||||||
*
|
*
|
||||||
|
@@ -56,13 +56,6 @@ class Template extends TemplateBase {
|
|||||||
*/
|
*/
|
||||||
public $template_resource = null;
|
public $template_resource = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* flag if compiled template is invalid and must be (re)compiled
|
|
||||||
*
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
public $mustCompile = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Template ID
|
* Template ID
|
||||||
*
|
*
|
||||||
@@ -309,88 +302,16 @@ class Template extends TemplateBase {
|
|||||||
return parent::assign($tpl_var, $value, $nocache, $scope);
|
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
|
* Compiles the template
|
||||||
* If the template is not evaluated the compiled template is saved on disk
|
* 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
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function compileTemplateSource() {
|
public function compileTemplateSource() {
|
||||||
return $this->getCompiled()->compileTemplateSource($this);
|
return $this->getCompiled()->compileAndWrite($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -400,7 +321,7 @@ class Template extends TemplateBase {
|
|||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function getCachedContent() {
|
public function getCachedContent() {
|
||||||
return $this->getCached()->handler->getCachedContent($this);
|
return $this->getCached()->getContent($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -547,7 +468,7 @@ class Template extends TemplateBase {
|
|||||||
* @return bool
|
* @return bool
|
||||||
* @throws \Smarty\Exception
|
* @throws \Smarty\Exception
|
||||||
*/
|
*/
|
||||||
public function mustCompile() {
|
public function mustCompile(): bool {
|
||||||
if (!$this->getSource()->exists) {
|
if (!$this->getSource()->exists) {
|
||||||
if ($this->_isSubTpl()) {
|
if ($this->_isSubTpl()) {
|
||||||
$parent_resource = " in '{$this->parent->template_resource}'";
|
$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}");
|
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->getSource()->handler->recompiled
|
||||||
|| !$this->getCompiled()->exists
|
|| !$this->getCompiled()->exists
|
||||||
|| ($this->compile_check && $this->getCompiled()->getTimeStamp() < $this->getSource()->getTimeStamp());
|
|| ($this->compile_check && $this->getCompiled()->getTimeStamp() < $this->getSource()->getTimeStamp());
|
||||||
}
|
}
|
||||||
return $this->mustCompile;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getCodeFrameCompiler(): Compiler\CodeFrame {
|
private function getCodeFrameCompiler(): Compiler\CodeFrame {
|
||||||
return new \Smarty\Compiler\CodeFrame($this);
|
return new \Smarty\Compiler\CodeFrame($this);
|
||||||
|
@@ -216,11 +216,7 @@ class Cached extends GeneratedPhpFile {
|
|||||||
if ($this->handler->process($_template, $this, $update) === false) {
|
if ($this->handler->process($_template, $this, $update) === false) {
|
||||||
$this->valid = false;
|
$this->valid = false;
|
||||||
}
|
}
|
||||||
if ($this->valid) {
|
$this->processed = $this->valid;
|
||||||
$this->processed = true;
|
|
||||||
} else {
|
|
||||||
$this->processed = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -287,10 +283,8 @@ class Cached extends GeneratedPhpFile {
|
|||||||
|
|
||||||
$this->removeNoCacheHash($_template, $no_output_filter);
|
$this->removeNoCacheHash($_template, $no_output_filter);
|
||||||
|
|
||||||
$compile_check = (int)$_template->compile_check;
|
|
||||||
$_template->compile_check = \Smarty\Smarty::COMPILECHECK_OFF;
|
|
||||||
|
|
||||||
if ($_template->_isSubTpl()) {
|
if ($_template->_isSubTpl()) {
|
||||||
|
// @TODO why is this needed?
|
||||||
$_template->getCompiled()->unifunc = $_template->parent->getCompiled()->unifunc;
|
$_template->getCompiled()->unifunc = $_template->parent->getCompiled()->unifunc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,8 +292,6 @@ class Cached extends GeneratedPhpFile {
|
|||||||
$this->process($_template, true);
|
$this->process($_template, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$_template->compile_check = $compile_check;
|
|
||||||
|
|
||||||
if ($_template->getSmarty()->debugging) {
|
if ($_template->getSmarty()->debugging) {
|
||||||
$_template->getSmarty()->getDebug()->end_cache($_template);
|
$_template->getSmarty()->getDebug()->end_cache($_template);
|
||||||
}
|
}
|
||||||
@@ -386,4 +378,60 @@ class Cached extends GeneratedPhpFile {
|
|||||||
$this->source = $source;
|
$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;
|
namespace Smarty\Template;
|
||||||
|
|
||||||
|
use Smarty\Exception;
|
||||||
use Smarty\Template;
|
use Smarty\Template;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,6 +26,10 @@ class Compiled extends GeneratedPhpFile {
|
|||||||
* @var int[]
|
* @var int[]
|
||||||
*/
|
*/
|
||||||
public $includes = [];
|
public $includes = [];
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $isValid = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get a Compiled Object of this source
|
* get a Compiled Object of this source
|
||||||
@@ -103,14 +108,17 @@ class Compiled extends GeneratedPhpFile {
|
|||||||
$this->compileAndLoad($_template);
|
$this->compileAndLoad($_template);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @TODO Can't Cached handle this? Maybe introduce an event to decouple.
|
||||||
$_template->getCached()->file_dependency =
|
$_template->getCached()->file_dependency =
|
||||||
array_merge($_template->getCached()->file_dependency, $this->file_dependency);
|
array_merge($_template->getCached()->file_dependency, $this->file_dependency);
|
||||||
|
|
||||||
$this->getRenderedTemplateCode($_template, $this->unifunc);
|
$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()) {
|
if ($_template->caching && $this->getNocacheCode()) {
|
||||||
$_template->getCached()->hashes[$this->nocache_hash] = true;
|
$_template->getCached()->hashes[$this->nocache_hash] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($_template->getSmarty()->debugging) {
|
if ($_template->getSmarty()->debugging) {
|
||||||
$_template->getSmarty()->getDebug()->end_render($_template);
|
$_template->getSmarty()->getDebug()->end_render($_template);
|
||||||
}
|
}
|
||||||
@@ -124,26 +132,48 @@ class Compiled extends GeneratedPhpFile {
|
|||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
private function compileAndLoad(Template $_smarty_tpl) {
|
private function compileAndLoad(Template $_smarty_tpl) {
|
||||||
$source = $_smarty_tpl->getSource();
|
|
||||||
$smarty = $_smarty_tpl->getSmarty();
|
if ($_smarty_tpl->getSource()->handler->recompiled) {
|
||||||
if ($source->handler->recompiled) {
|
$this->recompile($_smarty_tpl);
|
||||||
$source->handler->recompile($_smarty_tpl); // @TODO who is compiling here?
|
return;
|
||||||
} else {
|
}
|
||||||
if (!$this->exists || $smarty->force_compile
|
|
||||||
|| ($_smarty_tpl->compile_check && $source->getTimeStamp() > $this->getTimeStamp())
|
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);
|
$this->loadCompiledTemplate($_smarty_tpl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$this->isValid) {
|
||||||
|
$this->compileAndWrite($_smarty_tpl);
|
||||||
|
$this->loadCompiledTemplate($_smarty_tpl);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->processed = true;
|
$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
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function compileTemplateSource(Template $_template) {
|
public function compileAndWrite(Template $_template) {
|
||||||
$this->file_dependency = [];
|
|
||||||
$this->includes = [];
|
|
||||||
$this->nocache_hash = null;
|
|
||||||
$this->unifunc = null;
|
|
||||||
// compile locking
|
// compile locking
|
||||||
if ($saved_timestamp = (!$_template->getSource()->handler->recompiled && is_file($this->filepath))) {
|
if ($saved_timestamp = (!$_template->getSource()->handler->recompiled && is_file($this->filepath))) {
|
||||||
$saved_timestamp = $this->getTimeStamp();
|
$saved_timestamp = $this->getTimeStamp();
|
||||||
@@ -166,7 +192,7 @@ class Compiled extends GeneratedPhpFile {
|
|||||||
// compile locking
|
// compile locking
|
||||||
try {
|
try {
|
||||||
// call compiler
|
// call compiler
|
||||||
$this->write($_template, $_template->getCompiler()->compileTemplate($_template));
|
$this->write($_template, $this->doCompile($_template));
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
// restore old timestamp in case of error
|
// restore old timestamp in case of error
|
||||||
if ($saved_timestamp && is_file($this->filepath)) {
|
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
|
* Write compiled code by handler
|
||||||
*
|
*
|
||||||
@@ -203,11 +245,11 @@ class Compiled extends GeneratedPhpFile {
|
|||||||
* Load fresh compiled template by including the PHP file
|
* Load fresh compiled template by including the PHP file
|
||||||
* HHVM requires a workaround because of a PHP incompatibility
|
* 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) {
|
private function loadCompiledTemplate(Template $_smarty_tpl) {
|
||||||
$compileCheck = $_smarty_tpl->compile_check;
|
|
||||||
$_smarty_tpl->compile_check = \Smarty\Smarty::COMPILECHECK_OFF;
|
|
||||||
if (function_exists('opcache_invalidate')
|
if (function_exists('opcache_invalidate')
|
||||||
&& (!function_exists('ini_get') || strlen(ini_get("opcache.restrict_api")) < 1)
|
&& (!function_exists('ini_get') || strlen(ini_get("opcache.restrict_api")) < 1)
|
||||||
) {
|
) {
|
||||||
@@ -220,7 +262,41 @@ class Compiled extends GeneratedPhpFile {
|
|||||||
} else {
|
} else {
|
||||||
include $this->filepath;
|
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;
|
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.
|
* Base class for generated PHP files, such as compiled and cached versions of templates and config files.
|
||||||
|
*
|
||||||
* @author Rodney Rehm
|
* @author Rodney Rehm
|
||||||
*/
|
*/
|
||||||
abstract class GeneratedPhpFile {
|
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();
|
$this->smarty->clearAllCache();
|
||||||
// create and cache templates
|
// create and cache templates
|
||||||
$tpl = $this->smarty->createTemplate('helloworld.tpl');
|
$tpl = $this->smarty->createTemplate('helloworld.tpl');
|
||||||
$tpl->writeCachedContent('hello world');
|
$tpl->writeCachedContent('something else 1');
|
||||||
$tpl2 = $this->smarty->createTemplate('helloworld.tpl', null, 'bar');
|
$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 = $this->smarty->createTemplate('helloworld.tpl', 'buh|blar');
|
||||||
$tpl3->writeCachedContent('hello world');
|
$tpl3->writeCachedContent('something else 3');
|
||||||
// test cached content
|
// 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', $tpl->getCachedContent());
|
||||||
$this->assertEquals('hello world', $tpl2->getCachedContent());
|
$this->assertEquals('hello world', $tpl2->getCachedContent());
|
||||||
$this->assertEquals('hello world', $tpl3->getCachedContent());
|
$this->assertEquals('hello world', $tpl3->getCachedContent());
|
||||||
sleep(10);
|
$this->assertEquals('something else 4', $tpl4->getCachedContent());
|
||||||
$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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testClearCacheCacheFileSub()
|
public function testClearCacheCacheFileSub()
|
||||||
|
Reference in New Issue
Block a user