Simplified the (no)caching architecture by:

- removing support for $cache_attrs for registered plugins,
- removing the undocumented {make_nocache} tag and the deprecated {insert} tag and associated code
- removing support for a compile_id property on include tags.

Fixes a bug in extends: resources by propagating the nocache-hashes between a master template and it's subtemplates in \Smarty\Template::_subTemplateRender. This might need further improvement.
This commit is contained in:
Simon Wisselink
2023-01-13 15:47:57 +01:00
parent e0f2c36d4d
commit cdf1ed2a50
45 changed files with 70 additions and 768 deletions

View File

@@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Removed
- support for $cache_attrs for registered plugins
- support for undocumented {make_nocache} tag
- support for deprecated {insert} tag, the 'insert' plugin type and the associated $smarty->trusted_dir variable
### Fixed
- `$smarty->muteUndefinedOrNullWarnings()` now also mutes PHP7 notices for undefined array indexes [#736](https://github.com/smarty-php/smarty/issues/736)
- `$smarty->muteUndefinedOrNullWarnings()` now treats undefined vars and array access of a null or false variables

View File

@@ -10,7 +10,6 @@ within delimiters like so: `{funcname attr1="val1" attr2="val2"}`.
{config_load file="colors.conf"}
{include file="header.tpl"}
{insert file="banner_ads.tpl" title="My Site"}
{if $logged_in}
Welcome, <span style="color:{#fontColor#}">{$name}!</span>

View File

@@ -16,7 +16,6 @@ Built-in Functions {#language.builtin.functions}
- [{function}](./language-builtin-functions/language-function-function.md)
- [{if},{elseif},{else}](./language-builtin-functions/language-function-if.md)
- [{include}](./language-builtin-functions/language-function-include.md)
- [{insert}](./language-builtin-functions/language-function-insert.md)
- [{ldelim},{rdelim}](./language-builtin-functions/language-function-ldelim.md)
- [{literal}](./language-builtin-functions/language-function-literal.md)
- [{nocache}](./language-builtin-functions/language-function-nocache.md)

View File

@@ -135,7 +135,6 @@ The following functions can also *optionally* assign template variables.
[`{capture}`](#language.function.capture),
[`{include}`](#language.function.include),
[`{insert}`](#language.function.insert),
[`{counter}`](#language.function.counter),
[`{cycle}`](#language.function.cycle),
[`{eval}`](#language.function.eval),

View File

@@ -28,13 +28,6 @@ is the value passed in the `name` attribute. If you do not supply the
--------- -----------------------------------------
nocache Disables caching of this captured block
> **Note**
>
> Be careful when capturing [`{insert}`](#language.function.insert)
> output. If you have [`$caching`](#caching) enabled and you have
> [`{insert}`](#language.function.insert) commands that you expect to
> run within cached content, do not capture this content.
{* we don't want to print a div tag unless content is displayed *}
{capture name="banner"}

View File

@@ -188,5 +188,5 @@ current template.
See also [`{insert}`](#language.function.insert), [template resources](#resources) and
See also [template resources](#resources) and
[componentized templates](#tips.componentized.templates).

View File

@@ -1,86 +0,0 @@
{insert} {#language.function.insert}
========
> **Note**
>
> `{insert}` tags are deprecated from Smarty, and should not be used.
> Put your PHP logic in PHP scripts or plugin functions instead.
> **Note**
>
> As of Smarty 3.1 the `{insert}` tags are only available from
> [SmartyBC](#bc).
`{insert}` tags work much like [`{include}`](#language.function.include)
tags, except that `{insert}` tags are NOT cached when template
[caching](#caching) is enabled. They will be executed on every
invocation of the template.
Attribute Name Type Required Default Description
---------------- -------------- ---------- --------- ----------------------------------------------------------------------------------
name string Yes *n/a* The name of the insert function (insert\_`name`) or insert plugin
assign string No *n/a* The name of the template variable the output will be assigned to
script string No *n/a* The name of the php script that is included before the insert function is called
\[var \...\] \[var type\] No *n/a* variable to pass to insert function
Let\'s say you have a template with a banner slot at the top of the
page. The banner can contain any mixture of HTML, images, flash, etc. so
we can\'t just use a static link here, and we don\'t want this contents
cached with the page. In comes the {insert} tag: the template knows
\#banner\_location\_id\# and \#site\_id\# values (gathered from a
[config file](#config.files)), and needs to call a function to get the
banner contents.
{* example of fetching a banner *}
{insert name="getBanner" lid=#banner_location_id# sid=#site_id#}
{insert "getBanner" lid=#banner_location_id# sid=#site_id#} {* short-hand *}
In this example, we are using the name "getBanner" and passing the
parameters \#banner\_location\_id\# and \#site\_id\#. Smarty will look
for a function named insert\_getBanner() in your PHP application,
passing the values of \#banner\_location\_id\# and \#site\_id\# as the
first argument in an associative array. All {insert} function names in
your application must be prepended with \"insert\_\" to remedy possible
function name-space conflicts. Your insert\_getBanner() function should
do something with the passed values and return the results. These
results are then displayed in the template in place of the {insert} tag.
In this example, Smarty would call this function:
insert\_getBanner(array(\"lid\" =\> \"12345\",\"sid\" =\> \"67890\"));
and display the returned results in place of the {insert} tag.
- If you supply the `assign` attribute, the output of the `{insert}`
tag will be assigned to this template variable instead of being
output to the template.
> **Note**
>
> Assigning the output to a template variable isn\'t too useful with
> [caching](#variable.caching) enabled.
- If you supply the `script` attribute, this php script will be
included (only once) before the `{insert}` function is executed.
This is the case where the insert function may not exist yet, and a
php script must be included first to make it work.
The path can be either absolute, or relative to
[`$trusted_dir`](#variable.trusted.dir). If security is enabled,
then the script must be located in the `$trusted_dir` path of the
security policy. See the [Security](#advanced.features.security)
section for details.
The Smarty object is passed as the second argument. This way you can
reference and modify information in the Smarty object from within the
`{insert}` function.
If no PHP script can be found Smarty is looking for a corresponding
insert plugin.
> **Note**
>
> It is possible to have portions of the template not cached. If you
> have [caching](#caching) turned on, `{insert}` tags will not be
> cached. They will run dynamically every time the page is created, even
> within cached pages. This works good for things like banners, polls,
> live weather, search results, user feedback areas, etc.
See also [`{include}`](#language.function.include)

View File

@@ -11,14 +11,8 @@ instance of the Smarty\_Security class. These are the possible settings:
- `$secure_dir` is an array of template directories that are
considered secure. [`$template_dir`](#variable.template.dir)
considered secure implicitly. The default is an empty array.
- `$trusted_dir` is an array of all directories that are considered
trusted. Trusted directories are where you keep php scripts that are
executed directly from the templates with
[`{insert}`](#language.function.insert.php). The default is an
empty array.
- `$trusted_uri` is an array of regular expressions matching URIs that
- `$trusted_uri` is an array of regular expressions matching URIs that
are considered trusted. This security directive used by
[`{fetch}`](#language.function.fetch) and
[`{html_image}`](#language.function.html.image). URIs passed to

View File

@@ -32,9 +32,9 @@ cache\_attrs
This method registers functions or methods defined in your script as
plugin. It uses the following parameters:
- `cacheable` and `cache_attrs` can be omitted in most cases. See
- `cacheable` can be omitted in most cases. See
[controlling cacheability of plugins output](#caching.cacheable) on
how to use them properly.
how to use this properly.
<!-- -->

View File

@@ -55,5 +55,4 @@ And the php script
See also [`display()`](#api.display), [`fetch()`](#api.fetch),
[`{include}`](#language.function.include) and
[`{insert}`](#language.function.insert)
and [`{include}`](#language.function.include)

View File

@@ -39,7 +39,6 @@ them directly, or use the corresponding setter/getter methods.
- [$right_delimiter](./api-variables/variable-right-delimiter.md)
- [$smarty_debug_id](./api-variables/variable-smarty-debug-id.md)
- [$template_dir](./api-variables/variable-template-dir.md)
- [$trusted_dir](./api-variables/variable-trusted-dir.md)
- [$use_sub_dirs](./api-variables/variable-use-sub-dirs.md)
> **Note**

View File

@@ -4,8 +4,7 @@
If set to TRUE, Smarty will respect the If-Modified-Since header sent
from the client. If the cached file timestamp has not changed since the
last visit, then a `'304: Not Modified'` header will be sent instead of
the content. This works only on cached content without
[`{insert}`](#language.function.insert) tags.
the content.
See also [`$caching`](#variable.caching),
[`$cache_lifetime`](#variable.cache.lifetime), and the [caching

View File

@@ -1,8 +0,0 @@
\$trusted\_dir {#variable.trusted.dir}
==============
`$trusted_dir` is only for use when security is enabled. This is an
array of all directories that are considered trusted. Trusted
directories are where you keep php scripts that are executed directly
from the templates with
[`{insert}`](#language.function.insert.php).

View File

@@ -76,62 +76,14 @@ third parameter to [`registerPlugin()`](#api.register.plugin) is called
When registering a plugin with `$cacheable=false` the plugin is called
everytime the page is displayed, even if the page comes from the cache.
The plugin function behaves a little like an
[`{insert}`](#plugins.inserts) function.
> **Note**
>
> The `$cacheable` status will effect the compiled template code. If you
> The `$cacheable` status will affect the compiled template code. If you
> change the status you must manually delete existing compiled and
> cached template files to force a recompile.
In contrast to [`{insert}`](#plugins.inserts) the attributes to the
plugins are not cached by default. They can be declared to be cached
with the fourth parameter `$cache_attrs`. `$cache_attrs` is an array of
attribute-names that should be cached, so the plugin-function get value
as it was the time the page was written to cache everytime it is fetched
from the cache.
<?php
$smarty->setCaching(Smarty::CACHING_LIFETIME_CURRENT);
function remaining_seconds($params, $smarty) {
$remain = $params['endtime'] - time();
if($remain >= 0){
return $remain . ' second(s)';
}else{
return 'done';
}
}
$smarty->registerPlugin('function','remaining', 'remaining_seconds', false, array('endtime'));
if (!$smarty->isCached('index.tpl')) {
// fetch $obj from db and assign...
$smarty->assignByRef('obj', $obj);
}
$smarty->display('index.tpl');
?>
where `index.tpl` is:
Time Remaining: {remaining endtime=$obj->endtime}
The number of seconds till the endtime of `$obj` is reached changes on
each display of the page, even if the page is cached. Since the endtime
attribute is cached the object only has to be pulled from the database
when page is written to the cache but not on subsequent requests of the
page.
index.php:
Example `index.php`:
<?php
$smarty->setCaching(Smarty::CACHING_LIFETIME_CURRENT);

View File

@@ -118,16 +118,13 @@ process.
You can keep parts of a page dynamic (disable caching) with the
[`{nocache}{/nocache}`](#language.function.nocache) block function, the
[`{insert}`](#language.function.insert) function, or by using the
[`{nocache}{/nocache}`](#language.function.nocache) block function, or by using the
`nocache` parameter for most template functions.
Let\'s say the whole page can be cached except for a banner that is
displayed down the side of the page. By using the
[`{insert}`](#language.function.insert) function for the banner, you can
keep this element dynamic within the cached content. See the
documentation on [`{insert}`](#language.function.insert) for more
details and examples.
displayed down the side of the page. By using a [`{nocache}{/nocache}`](#language.function.nocache)
block for the banner, you can
keep this element dynamic within the cached content.
You can clear all the cache files with the
[`clearAllCache()`](#api.clear.all.cache) function, or individual cache

View File

@@ -28,8 +28,6 @@ in order to be located by Smarty.
- resource
- insert
- And `name` should be a valid identifier; letters, numbers, and
underscores only, see [php
variables](&url.php-manual;language.variables).

View File

@@ -19,10 +19,7 @@ use Smarty\Template\Cached;
/**
* This class does contain all necessary methods for the HTML cache on file system
* Implements the file system as resource for the HTML cache Version ussing nocache inserts.
*
* Implements the file system as resource for the HTML cache Version using nocache inserts.
*/
class File extends Base
{

View File

@@ -68,22 +68,16 @@ abstract class Base implements CompilerInterface {
}
/**
* Converts attributes into parameter array string
* Converts attributes into parameter array strings
*
* @param array $_attr
*
* @return array
*/
protected function formatParamsArray($_attr, array $cacheAttributes = []) {
protected function formatParamsArray(array $_attr): array {
$_paramsArray = [];
foreach ($_attr as $_key => $_value) {
if (is_int($_key)) {
$_paramsArray[] = "$_key=>$_value";
} elseif (in_array($_key, $cacheAttributes)) {
$_value = str_replace('\'', "^#^", $_value);
$_paramsArray[] = "'$_key'=>^#^.var_export($_value,true).^#^";
} else {
$_paramsArray[] = "'$_key'=>$_value";
}
$_paramsArray[] = var_export($_key, true) . "=>" . $_value;
}
return $_paramsArray;
}
@@ -229,13 +223,13 @@ abstract class Base implements CompilerInterface {
}
/**
* @param array $_attr tag attributes
* @param mixed $scope
* @param array $invalidScopes
*
* @return int
* @throws Exception
*/
protected function convertScope($_attr, $invalidScopes = []): int {
protected function convertScope($scope, $invalidScopes = []): int {
static $scopes = [
'local' => Data::SCOPE_LOCAL, // current scope
@@ -247,11 +241,7 @@ abstract class Base implements CompilerInterface {
'smarty' => Data::SCOPE_SMARTY, // @deprecated alias of 'global'
];
if (!isset($_attr['scope'])) {
return 0;
}
$_scopeName = trim($_attr['scope'], '\'"');
$_scopeName = trim($scope, '\'"');
if (is_numeric($_scopeName) && in_array($_scopeName, $scopes)) {
return (int) $_scopeName;
}

View File

@@ -62,10 +62,7 @@ class FunctionCallCompiler extends Base {
// not cacheable?
$compiler->tag_nocache = $compiler->tag_nocache || !$functionHandler->isCacheable();
$_paramsArray = $this->formatParamsArray(
$_attr,
$compiler->template->caching ? $functionHandler->getCacheAttributes() : []
);
$_paramsArray = $this->formatParamsArray($_attr);
$_params = 'array(' . implode(',', $_paramsArray) . ')';

View File

@@ -65,7 +65,7 @@ class Assign extends Base
if ($_attr[ 'noscope' ]) {
$_scope = -1;
} else {
$_scope = $this->convertScope($_attr);
$_scope = isset($_attr['scope']) ? $this->convertScope($_attr['scope']) : 0;
}
// optional parameter
$_params = '';

View File

@@ -71,12 +71,7 @@ class ConfigLoad extends Base {
// save possible attributes
$conf_file = $_attr['file'];
$section = $_attr['section'] ?? 'null';
// scope setup
if ($_attr['noscope']) {
$_scope = -1;
} else {
$_scope = $this->convertScope($_attr);
}
// create config object
return "<?php\n\$_smarty_tpl->configLoad({$conf_file}, {$section});\n?>\n";
}

View File

@@ -73,7 +73,6 @@ class IncludeTag extends Base {
$_attr = $this->getAttributes($compiler, $args);
$fullResourceName = $source_resource = $_attr['file'];
$variable_template = false;
$cache_tpl = false;
// parse resource_name
if (preg_match('/^([\'"])(([A-Za-z0-9_\-]{2,})[:])?(([^$()]+)|(.+))\1$/', $source_resource, $match)) {
$type = !empty($match[3]) ? $match[3] : $compiler->template->smarty->default_resource_type;
@@ -88,14 +87,12 @@ class IncludeTag extends Base {
$compiled = $compiler->parent_compiler->template->getCompiled();
if (isset($compiled->includes[$fullResourceName])) {
$compiled->includes[$fullResourceName]++;
$cache_tpl = true;
} else {
if ("{$compiler->template->source->type}:{$compiler->template->source->name}" ==
$fullResourceName
) {
// recursive call of current template
$compiled->includes[$fullResourceName] = 2;
$cache_tpl = true;
} else {
$compiled->includes[$fullResourceName] = 1;
}
@@ -110,7 +107,7 @@ class IncludeTag extends Base {
$variable_template = true;
}
// scope setup
$_scope = $this->convertScope($_attr, [Data::SCOPE_LOCAL]);
$_scope = isset($_attr['scope']) ? $this->convertScope($_attr['scope'], [Data::SCOPE_LOCAL]) : 0;
// assume caching is off
$_caching = Smarty::CACHING_OFF;
@@ -127,10 +124,6 @@ class IncludeTag extends Base {
if ($variable_template) {
$merge_compiled_includes = false;
}
// variable compile_id?
if (isset($_attr['compile_id']) && $compiler->isVariable($_attr['compile_id'])) {
$merge_compiled_includes = false;
}
}
/*
* if the {include} tag provides individual parameter for caching or compile_id
@@ -158,11 +151,7 @@ class IncludeTag extends Base {
} else {
$_cache_id = '$_smarty_tpl->cache_id';
}
if (isset($_attr['compile_id'])) {
$_compile_id = $_attr['compile_id'];
} else {
$_compile_id = '$_smarty_tpl->compile_id';
}
// if subtemplate will be called in nocache mode do not merge
if ($compiler->template->caching && $call_nocache) {
$merge_compiled_includes = false;
@@ -182,7 +171,7 @@ class IncludeTag extends Base {
}
$has_compiled_template = false;
if ($merge_compiled_includes) {
$c_id = $_attr['compile_id'] ?? $compiler->template->compile_id;
$c_id = $compiler->template->compile_id;
// we must observe different compile_id and caching
$t_hash = sha1($c_id . ($_caching ? '--caching' : '--nocaching'));
@@ -206,7 +195,7 @@ class IncludeTag extends Base {
}
// delete {include} standard attributes
unset($_attr['file'], $_attr['assign'], $_attr['cache_id'], $_attr['compile_id'], $_attr['cache_lifetime'], $_attr['nocache'], $_attr['caching'], $_attr['scope'], $_attr['inline']);
unset($_attr['file'], $_attr['assign'], $_attr['cache_id'], $_attr['cache_lifetime'], $_attr['nocache'], $_attr['caching'], $_attr['scope'], $_attr['inline']);
// remaining attributes must be assigned as smarty variable
$_vars = 'array()';
if (!empty($_attr)) {
@@ -217,29 +206,21 @@ class IncludeTag extends Base {
}
$_vars = 'array(' . join(',', $_pairs) . ')';
}
$update_compile_id = $compiler->template->caching && !$compiler->tag_nocache && !$compiler->nocache &&
$_compile_id !== '$_smarty_tpl->compile_id';
if ($has_compiled_template && !$call_nocache) {
$_output = "<?php\n";
if ($update_compile_id) {
$_output .= $compiler->makeNocacheCode("\$_compile_id_save[] = \$_smarty_tpl->compile_id;\n\$_smarty_tpl->compile_id = {$_compile_id};\n");
}
if (!empty($_attr) && $_caching === \Smarty\Template::CACHING_NOCACHE_CODE && $compiler->template->caching) {
$_vars_nc = "foreach ($_vars as \$ik => \$iv) {\n";
$_vars_nc .= "\$_smarty_tpl->assign(\$ik, \$iv);\n";
$_vars_nc .= "}\n";
$_output .= substr($compiler->processNocacheCode('<?php ' . $_vars_nc . "?>\n", true), 6, -3);
$_output .= substr($compiler->processNocacheCode('<?php ' . $_vars_nc . "?>\n"), 6, -3);
}
if (isset($_assign)) {
$_output .= "ob_start();\n";
}
$_output .= "\$_smarty_tpl->_subTemplateRender({$fullResourceName}, {$_cache_id}, {$_compile_id}, {$_caching}, {$_cache_lifetime}, {$_vars}, '{$compiler->parent_compiler->mergedSubTemplatesData[$uid][$t_hash]['uid']}', '{$compiler->parent_compiler->mergedSubTemplatesData[$uid][$t_hash]['func']}');\n";
$_output .= "\$_smarty_tpl->_subTemplateRender({$fullResourceName}, {$_cache_id}, \$_smarty_tpl->compile_id, {$_caching}, {$_cache_lifetime}, {$_vars}, '{$compiler->parent_compiler->mergedSubTemplatesData[$uid][$t_hash]['uid']}', '{$compiler->parent_compiler->mergedSubTemplatesData[$uid][$t_hash]['func']}');\n";
if (isset($_assign)) {
$_output .= "\$_smarty_tpl->assign({$_assign}, ob_get_clean(), false, {$_scope});\n";
}
if ($update_compile_id) {
$_output .= $compiler->makeNocacheCode("\$_smarty_tpl->compile_id = array_pop(\$_compile_id_save);\n");
}
$_output .= "?>";
return $_output;
}
@@ -247,20 +228,14 @@ class IncludeTag extends Base {
$compiler->tag_nocache = true;
}
$_output = "<?php ";
if ($update_compile_id) {
$_output .= "\$_compile_id_save[] = \$_smarty_tpl->compile_id;\n\$_smarty_tpl->compile_id = {$_compile_id};\n";
}
// was there an assign attribute
if (isset($_assign)) {
$_output .= "ob_start();\n";
}
$_output .= "\$_smarty_tpl->_subTemplateRender({$fullResourceName}, $_cache_id, $_compile_id, $_caching, $_cache_lifetime, $_vars);\n";
$_output .= "\$_smarty_tpl->_subTemplateRender({$fullResourceName}, $_cache_id, \$_smarty_tpl->compile_id, $_caching, $_cache_lifetime, $_vars);\n";
if (isset($_assign)) {
$_output .= "\$_smarty_tpl->assign({$_assign}, ob_get_clean(), false, {$_scope});\n";
}
if ($update_compile_id) {
$_output .= "\$_smarty_tpl->compile_id = array_pop(\$_compile_id_save);\n";
}
$_output .= "?>";
return $_output;
}

View File

@@ -1,65 +0,0 @@
<?php
/**
* Smarty Internal Plugin Compile Make_Nocache
* Compiles the {make_nocache} tag
*
* @author Uwe Tews
*/
namespace Smarty\Compile\Tag;
use Smarty\Compile\Base;
/**
* Smarty Internal Plugin Compile Make_Nocache Class
*
*/
class MakeNocache extends Base {
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see BaseCompiler
*/
protected $option_flags = [];
/**
* Array of names of required attribute required by tag
*
* @var array
*/
protected $required_attributes = ['var'];
/**
* Shorttag attribute order defined by its names
*
* @var array
*/
protected $shorttag_order = ['var'];
/**
* Compiles code for the {make_nocache} tag
*
* @param array $args array with attributes from parser
* @param \Smarty\Compiler\Template $compiler compiler object
*
* @return string compiled code
*/
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
if ($compiler->template->caching) {
$output = "<?php \$_smarty_tpl->smarty->getRuntime('MakeNocache')->save(\$_smarty_tpl, {$_attr[ 'var' ]});\n?>\n";
$compiler->template->getCompiled()->setNocacheCode(true);
$compiler->suppressNocacheProcessing = true;
return $output;
} else {
return true;
}
}
}

View File

@@ -35,7 +35,6 @@ class NocacheClose extends Base {
[$compiler->nocache] = $this->closeTag($compiler, ['nocache']);
// this tag does not return compiled code
$compiler->has_code = false;
echo "has_code set to false in " . __METHOD__ . "\n";
return true;
}
}

View File

@@ -127,13 +127,6 @@ class Template extends BaseCompiler {
*/
public $trace_filepath = '';
/**
* force compilation of complete template as nocache
*
* @var boolean
*/
public $forceNocache = false;
/**
* Template functions
*
@@ -708,38 +701,47 @@ class Template extends BaseCompiler {
/**
* Inject inline code for nocache template sections
* This method gets the content of each template element from the parser.
* If the content is compiled code and it should be not cached the code is injected
* If the content is compiled code, and it should be not be cached the code is injected
* into the rendered output.
*
* @param string $content content of template element
* @param boolean $is_code true if content is compiled code
*
* @return string content
*/
public function processNocacheCode($content, $is_code) {
// If the template is not evaluated and we have a nocache section and or a nocache tag
if ($is_code && !empty($content)) {
// generate replacement code
if ((!($this->template->source->handler->recompiled) || $this->forceNocache) && $this->caching
&& !$this->suppressNocacheProcessing && ($this->nocache || $this->tag_nocache)
) {
$this->template->getCompiled()->setNocacheCode(true);
$_output = addcslashes($content, '\'\\');
$_output = str_replace('^#^', '\'', $_output);
$_output =
"<?php echo '/*%%SmartyNocache:{$this->nocache_hash}%%*/{$_output}/*/%%SmartyNocache:{$this->nocache_hash}%%*/';?>\n";
} else {
$_output = $content;
}
public function processNocacheCode($content) {
// If the template is not evaluated, and we have a nocache section and/or a nocache tag
// generate replacement code
if (!empty($content)
&& !($this->template->source->handler->recompiled)
&& $this->caching
&& !$this->suppressNocacheProcessing
&& ($this->nocache || $this->tag_nocache)
) {
$this->template->getCompiled()->setNocacheCode(true);
$_output = addcslashes($content, '\'\\');
$_output =
"<?php echo '" . $this->getNocacheBlockStartMarker() . $_output . $this->getNocacheBlockEndMarker() . "';?>\n";
} else {
$_output = $content;
}
$this->modifier_plugins = [];
$this->suppressNocacheProcessing = false;
$this->tag_nocache = false;
return $_output;
}
private function getNocacheBlockStartMarker(): string {
return "/*%%SmartyNocache:{$this->nocache_hash}%%*/";
}
private function getNocacheBlockEndMarker(): string {
return "/*/%%SmartyNocache:{$this->nocache_hash}%%*/";
}
/**
* Get Id
*
@@ -770,19 +772,6 @@ class Template extends BaseCompiler {
}
}
/**
* Generate nocache code string
*
* @param string $code PHP code
*
* @return string
*/
public function makeNocacheCode($code) {
return "echo '/*%%SmartyNocache:{$this->nocache_hash}%%*/<?php " .
str_replace('^#^', '\'', addcslashes($code, '\'\\')) .
"?>/*/%%SmartyNocache:{$this->nocache_hash}%%*/';\n";
}
/**
* display compiler error messages without dying
* If parameter $args is empty it is a parser detected syntax error.

View File

@@ -46,9 +46,8 @@ class BCPluginsAdapter extends Base {
}
$callback = $plugin[0];
$cacheable = (bool) $plugin[1] ?? true;
$cache_attributes = (array) $plugin[2] ?? [];
return new FunctionPluginWrapper($callback, $cacheable, $cache_attributes);
return new FunctionPluginWrapper($callback, $cacheable);
}
@@ -167,7 +166,6 @@ class BCPluginsAdapter extends Base {
'prefilter',
'postfilter',
'outputfilter',
'insert',
] as $type) {
foreach (glob($path . $type . '.?*.php') as $filename) {
$pluginName = $this->getPluginNameFromFilename($filename);

View File

@@ -34,10 +34,8 @@ class CoreExtension extends Base {
case 'elseif': return new \Smarty\Compile\Tag\ElseIfTag();
case 'ifclose': return new \Smarty\Compile\Tag\IfClose();
case 'include': return new \Smarty\Compile\Tag\IncludeTag();
case 'insert': return new \Smarty\Compile\Inser();
case 'ldelim': return new \Smarty\Compile\Tag\Ldelim();
case 'rdelim': return new \Smarty\Compile\Tag\Rdelim();
case 'make_nocache': return new \Smarty\Compile\Tag\MakeNocache();
case 'nocache': return new \Smarty\Compile\Tag\Nocache();
case 'nocacheclose': return new \Smarty\Compile\Tag\NocacheClose();
case 'parent': return new \Smarty\Compile\Tag\ParentTag();

View File

@@ -8,10 +8,9 @@ class BCPluginWrapper extends Base {
private $callback;
public function __construct($callback, bool $cacheable = true, array $cache_attributes = []) {
public function __construct($callback, bool $cacheable = true) {
$this->callback = $callback;
$this->cacheable = $cacheable;
$this->cache_attributes = $cache_attributes;
}
public function handle($params, Template $template) {

View File

@@ -11,19 +11,10 @@ class Base implements FunctionHandlerInterface {
*/
protected $cacheable = true;
/**
* @var array
*/
protected $cache_attributes = [];
public function isCacheable(): bool {
return $this->cacheable;
}
public function getCacheAttributes(): array {
return $this->cache_attributes;
}
public function handle($params, Template $template) {
// TODO: Implement handle() method.
}

View File

@@ -7,5 +7,4 @@ use Smarty\Template;
interface FunctionHandlerInterface {
public function handle($params, Template $template);
public function isCacheable(): bool;
public function getCacheAttributes(): array;
}

View File

@@ -330,7 +330,6 @@ class TemplateLexer
step = ~\s+step\s+~
if = ~(if|elseif|else if|while)\s+~
for = ~for\s+~
makenocache = ~make_nocache\s+~
array = ~array~
foreach = ~foreach(?![^\s])~
setfilter = ~setfilter\s+~
@@ -405,11 +404,6 @@ class TemplateLexer
$this->yybegin(self::TAGBODY);
$this->taglineno = $this->line;
}
ldel makenocache {
$this->token = \Smarty\Parser\TemplateParser::TP_LDELMAKENOCACHE;
$this->yybegin(self::TAGBODY);
$this->taglineno = $this->line;
}
ldel id nocacherdel {
$this->yypopstate();
$this->token = \Smarty\Parser\TemplateParser::TP_SIMPLETAG;

View File

@@ -431,11 +431,6 @@ tag(res) ::= LDEL ID(i) PTR ID(me) modifierlist(l) attributes(a). {
res = $this->compiler->compileTag(i,a,array('modifierlist'=>l, 'object_method'=>me));
}
// nocache tag
tag(res) ::= LDELMAKENOCACHE DOLLARID(i). {
res = $this->compiler->compileTag('make_nocache',array(array('var'=>'\''.substr(i,1).'\'')));
}
// {if}, {elseif} and {while} tag
tag(res) ::= LDELIF(i) expr(ie). {
$tag = trim(substr(i,$this->compiler->getLdelLength()));

View File

@@ -1,55 +0,0 @@
<?php
namespace Smarty\Runtime;
use Smarty\Template;
/**
* {make_nocache} Runtime Methods save(), store()
*
* @author Uwe Tews
*/
class MakeNocacheRuntime {
/**
* Save current variable value while rendering compiled template and inject nocache code to
* assign variable value in cached template
*
* @param \Smarty\Template $tpl
* @param string $var variable name
*
* @throws \Smarty\Exception
*/
public function save(Template $tpl, $var) {
if ($tpl->hasVariable($var)) {
$export =
preg_replace('/^\\\\Smarty\\\\Variable::__set_state[(]|[)]$/', '', var_export($tpl->getVariable($var), true));
if (preg_match('/(\w+)::__set_state/', $export, $match)) {
throw new \Smarty\Exception("{make_nocache \${$var}} in template '{$tpl->source->name}': variable does contain object '{$match[1]}' not implementing method '__set_state'");
}
echo "/*%%SmartyNocache:{$tpl->getCompiled()->nocache_hash}%%*/<?php " .
addcslashes("\$_smarty_tpl->smarty->getRuntime('MakeNocache')->store(\$_smarty_tpl, '{$var}', ", '\\') .
$export . ");?>\n/*/%%SmartyNocache:{$tpl->getCompiled()->nocache_hash}%%*/";
}
}
/**
* Store variable value saved while rendering compiled template in cached template context
*
* @param \Smarty\Template $tpl
* @param string $var variable name
* @param array $properties
*/
public function store(Template $tpl, $var, $properties) {
// do not overwrite existing nocache variables
if (!$tpl->getVariable($var)->isNocache()) {
$newVar = new \Smarty\Variable();
unset($properties['nocache']);
foreach ($properties as $k => $v) {
$newVar->$k = $v;
}
$tpl->tpl_vars[$var] = $newVar;
}
}
}

View File

@@ -35,14 +35,6 @@ class Security {
*/
public $secure_dir = [];
/**
* This is an array of directories where trusted php scripts reside.
* {@link $security} is disabled during their inclusion/execution.
*
* @var array
*/
public $trusted_dir = [];
/**
* List of regular expressions (PCRE) that include trusted URIs
*

View File

@@ -15,7 +15,6 @@ use Smarty\Resource\BasePlugin;
use Smarty\Smarty\Runtime\CaptureRuntime;
use Smarty\Smarty\Runtime\ForeachRuntime;
use Smarty\Smarty\Runtime\InheritanceRuntime;
use Smarty\Smarty\Runtime\MakeNocacheRuntime;
use Smarty\Smarty\Runtime\TplFunctionRuntime;
/**
@@ -760,7 +759,6 @@ class Smarty extends \Smarty\TemplateBase
* @param string $name name of template tag
* @param callable $callback PHP callback to register
* @param bool $cacheable if true (default) this function is cache able
* @param mixed $cache_attr caching attributes if any
*
* @return $this
* @throws \Smarty\Exception
@@ -768,15 +766,13 @@ class Smarty extends \Smarty\TemplateBase
*
* @api Smarty::registerPlugin()
*/
public function registerPlugin($type, $name, $callback, $cacheable = true, $cache_attr = null) {
public function registerPlugin($type, $name, $callback, $cacheable = true) {
if (isset($this->registered_plugins[$type][$name])) {
throw new Exception("Plugin tag '{$name}' already registered");
} elseif (!is_callable($callback)) {
throw new Exception("Plugin '{$name}' not callable");
} elseif ($cacheable && $cache_attr) {
throw new Exception("Cannot set caching attributes for plugin '{$name}' when it is cacheable.");
} else {
$this->registered_plugins[$type][$name] = [$callback, (bool)$cacheable, (array)$cache_attr];
$this->registered_plugins[$type][$name] = [$callback, (bool)$cacheable];
}
return $this;
}
@@ -1882,8 +1878,6 @@ class Smarty extends \Smarty\TemplateBase
return $this->runtimes[$type] = new \Smarty\Runtime\ForeachRuntime();
case 'Inheritance':
return $this->runtimes[$type] = new \Smarty\Runtime\InheritanceRuntime();
case 'MakeNocache':
return $this->runtimes[$type] = new \Smarty\Runtime\MakeNocacheRuntime();
case 'TplFunction':
return $this->runtimes[$type] = new \Smarty\Runtime\TplFunctionRuntime();
case 'DefaultPluginHandler':

View File

@@ -312,6 +312,9 @@ class Template extends TemplateBase {
// $tpl->render();
// }
}
// Merge the hashes... @TODO refactor this?
$this->getCached()->hashes = array_merge($this->getCached()->hashes, $tpl->getCached()->hashes);
}
/**
@@ -467,7 +470,7 @@ class Template extends TemplateBase {
*
* @throws Exception
*/
public function getCached($forceNew = false) {
public function getCached($forceNew = false): Cached {
if ($forceNew || !isset($this->cached)) {
$this->cached = new Cached($this);
$this->cached->handler->populate($this->cached, $this);
@@ -776,5 +779,4 @@ class Template extends TemplateBase {
throw $e;
}
}
}

View File

@@ -1,309 +0,0 @@
<?php
/**
* Smarty PHPunit tests compilation of {make_nocache} tags
*
* @author Uwe Tews
*/
/**
* class for {make_nocache} tags tests
*
*
* @preserveGlobalState disabled
*
*/
class CompileMakeNocacheTest extends PHPUnit_Smarty
{
public function setUp(): void
{
$this->setUpSmarty(__DIR__);
$this->smarty->addPluginsDir("../../../__shared/PHPunitplugins/");
$this->smarty->addTemplateDir("../../../__shared/templates/");
$this->smarty->addTemplateDir("./templates_tmp");
}
public function testInit()
{
$this->cleanDirs();
}
/**
* Test {make_nocache} tags caching disabled
*
* @not runInSeparateProcess
*
* @dataProvider dataTestMakeNocache001
*/
public function testMakeNocache_001($foo, $result)
{
if ($foo) {
$this->smarty->assign('foo', $foo);
}
$this->assertEquals($result, $this->smarty->fetch('001_test_foo.tpl'),
"foo = {$foo}");
}
/*
* Data provider für testMakeNocache_001
*/
public function dataTestMakeNocache001()
{
/*
* $foo
* result
*
*/
return array(array(1, '#001_test_foo.tpl:$foo =1'), array(2, '#001_test_foo.tpl:$foo =2'),
array(null, '#001_test_foo.tpl:$foo =>unassigned<'),);
}
/**
* Test {make_nocache} cached tags
*
* @not runInSeparateProcess
*
* @dataProvider dataTestMakeNocache001_1
*/
public function testMakeNocache_001_1($foo, $result)
{
$this->smarty->setCaching(true);
if ($foo) {
$this->smarty->assign('foo', $foo);
}
$this->assertEquals($result, $this->smarty->fetch('001_test_foo.tpl'),
"foo = {$foo}");
}
/*
* Data provider für testMakeNocache_001_1
*/
public function dataTestMakeNocache001_1()
{
/*
* $foo
* result
*
*/
return array(array(1, '#001_test_foo.tpl:$foo =1'), array(2, '#001_test_foo.tpl:$foo =1'),
array(null, '#001_test_foo.tpl:$foo =1'),);
}
/**
* Test {make_nocache} cached tags existing nocahe variable
*
*
*
* @dataProvider dataTestMakeNocache001_2
*/
public function testMakeNocache_001_2($foo, $result)
{
$this->smarty->setCaching(true);
if ($foo) {
$this->smarty->assign('foo', $foo, true);
}
$this->assertEquals($result, $this->smarty->fetch('001_test_foo.tpl'),
"foo = {$foo}");
}
/*
* Data provider für testMakeNocache_001_2
*/
public function dataTestMakeNocache001_2()
{
/*
* $foo
* result
*
*/
return array(array(1, '#001_test_foo.tpl:$foo =1'), array(2, '#001_test_foo.tpl:$foo =2'),
array(null, '#001_test_foo.tpl:$foo =1'),);
}
/**
* Test {make_nocache} cached tags reassign
*
*
*
* @dataProvider dataTestMakeNocache001_3
*/
public function testMakeNocache_001_3($foo, $result)
{
$this->smarty->setCaching(true);
if ($foo) {
$this->smarty->assign('foo', $foo);
}
$this->smarty->assign('bar', $foo + 4, true);
$this->assertEquals($result, $this->smarty->fetch('001_test_foo_assign.tpl'),
"foo = {$foo}");
}
/*
* Data provider für testMakeNocache_001_3
*/
public function dataTestMakeNocache001_3()
{
/*
* $foo
* result
*
*/
return array(array(1, '#001_test_foo_assign.tpl:$foo =5'), array(2, '#001_test_foo_assign.tpl:$foo =6'),
array(null, '#001_test_foo_assign.tpl:$foo =4'),);
}
/**
* Test {make_nocache} cached tags {if}
*
*
*
* @dataProvider dataTestMakeNocache001_4
*/
public function testMakeNocache_001_4($foo, $bar, $result)
{
$this->smarty->setCaching(true);
$this->smarty->assign('foo', $foo);
$this->smarty->assign('bar', $bar);
$this->assertEquals($result, $this->smarty->fetch('001_test_foo_if.tpl'),
"foo = {$foo}");
}
/*
* Data provider für testMakeNocache_001_4
*/
public function dataTestMakeNocache001_4()
{
/*
* $foo
* $bar
* result
*
*/
return array(array(10, 9, 'greater'), array(9, 10, 'greater'),);
}
/**
* Test {make_nocache} cached tags {if} nocache
*
*
*
* @dataProvider dataTestMakeNocache001_5
*/
public function testMakeNocache_001_5($foo, $bar, $result)
{
$this->smarty->setCaching(true);
$this->smarty->compile_id = 1;
if ($foo) {
$this->smarty->assign('foo', $foo);
}
$this->smarty->assign('bar', $bar, true);
$this->assertEquals($result, $this->smarty->fetch('001_test_foo_if.tpl'),
"foo = {$foo}");
}
/*
* Data provider für testMakeNocache_001_5
*/
public function dataTestMakeNocache001_5()
{
/*
* $foo
* $bar
* result
*
*/
return array(array(10, 9, 'greater'), array(9, 10, 'not greater'), array(null, 11, 'not greater'),
array(null, 2, 'greater'),);
}
/**
* Test {make_nocache} cached tags {foreach}
*
*
*
* @dataProvider dataTestMakeNocache001_6
*/
public function testMakeNocache_001_6($foo, $bar, $result)
{
$this->smarty->setCaching(true);
$this->smarty->assign('foo', $foo, true);
$this->smarty->assign('bar', $bar);
$this->assertEquals($result, $this->smarty->fetch('001_test_foo_foreach.tpl'),
"foo = {$foo}");
}
/*
* Data provider für testMakeNocache_001_6
*/
public function dataTestMakeNocache001_6()
{
/*
* $foo
* $bar
* result
*
*/
return array(array(2, array(1, 2, 3, 4), ' 1 2match 3 4'), array(3, array(7, 8, 9), ' 1 2 3match 4'),);
}
/**
* Test {make_nocache} cached tags {foreach} nocache
*
*
*
* @dataProvider dataTestMakeNocache001_7
*/
public function testMakeNocache_001_7($foo, $bar, $result)
{
$this->smarty->setCaching(true);
$this->smarty->compile_id = 1;
$this->smarty->assign('foo', $foo, true);
$this->smarty->assign('bar', $bar, true);
$this->assertEquals($result, $this->smarty->fetch('001_test_foo_foreach.tpl'),
"foo = {$foo}");
}
/*
* Data provider für testMakeNocache_001_7
*/
public function dataTestMakeNocache001_7()
{
/*
* $foo
* $bar
* result
*
*/
return array(array(2, array(1, 2, 3, 4), ' 1 2match 3 4'), array(7, array(7, 8, 9), ' 7match 8 9'),);
}
/**
* Test {make_nocache} with values containing '\'
*
*
*/
public function testMakeNocache_002()
{
$this->smarty->setCaching(true);
$this->smarty->assign('foo', 'uwe\'s');
$this->assertEquals($this->strip('uwe\'s'), $this->smarty->fetch('002_test_backslash.tpl'));
}
/**
* Test {make_nocache} with values containing spaces
*
*
*/
public function testMakeNocache_003()
{
$this->smarty->setCaching(true);
$this->smarty->assign('foo', 'the Smarty template engine');
$this->assertEquals('the Smarty template engine', $this->smarty->fetch('003_test_spaces.tpl'));
}
}

View File

@@ -1,2 +0,0 @@
# Ignore anything in here, but keep this directory
*

View File

@@ -1 +0,0 @@
{make_nocache $foo}{checkvar var=foo types='template' nocache}

View File

@@ -1 +0,0 @@
{make_nocache $foo}{$foo=$bar nocache}{checkvar var=foo types='template' nocache}

View File

@@ -1,3 +0,0 @@
{foreach $bar as $i}
{$i}{make_nocache $i}{if $i == $foo}match{/if}
{/foreach}

View File

@@ -1 +0,0 @@
{make_nocache $foo}{if $foo > $bar}greater{else}not greater{/if}

View File

@@ -1 +0,0 @@
{make_nocache $foo}{$foo nocache}

View File

@@ -1 +0,0 @@
{make_nocache $foo}{$foo nocache}

View File

@@ -1,2 +0,0 @@
# Ignore anything in here, but keep this directory
*