fixed pre/post/output filters and removed some old todo-comments

This commit is contained in:
Simon Wisselink
2023-01-02 23:26:36 +01:00
parent 60a56969dd
commit b9ecf115dd
10 changed files with 257 additions and 160 deletions

View File

@@ -5,6 +5,7 @@ namespace Smarty\Extension;
use Smarty\BlockHandler\BlockPluginWrapper; use Smarty\BlockHandler\BlockPluginWrapper;
use Smarty\Compile\Modifier\BCPluginWrapper as ModifierCompilerPluginWrapper; use Smarty\Compile\Modifier\BCPluginWrapper as ModifierCompilerPluginWrapper;
use Smarty\Compile\Tag\BCPluginWrapper as TagPluginWrapper; use Smarty\Compile\Tag\BCPluginWrapper as TagPluginWrapper;
use Smarty\Filter\FilterPluginWrapper;
use Smarty\FunctionHandler\BCPluginWrapper as FunctionPluginWrapper; use Smarty\FunctionHandler\BCPluginWrapper as FunctionPluginWrapper;
class BCPluginsAdapter extends Base { class BCPluginsAdapter extends Base {
@@ -80,6 +81,82 @@ class BCPluginsAdapter extends Base {
return new ModifierCompilerPluginWrapper($callback); return new ModifierCompilerPluginWrapper($callback);
} }
/**
* @var array
*/
private $preFilters = [];
public function getPreFilters(): array {
return $this->preFilters;
}
public function addPreFilter(\Smarty\Filter\FilterInterface $filter) {
$this->preFilters[] = $filter;
}
public function addCallableAsPreFilter(callable $callable, ?string $name = null) {
if ($name === null) {
$this->preFilters[] = new FilterPluginWrapper($callable);
} else {
$this->preFilters[$name] = new FilterPluginWrapper($callable);
}
}
public function removePrefilter(string $name) {
unset($this->preFilters[$name]);
}
/**
* @var array
*/
private $postFilters = [];
public function getPostFilters(): array {
return $this->postFilters;
}
public function addPostFilter(\Smarty\Filter\FilterInterface $filter) {
$this->postFilters[] = $filter;
}
public function addCallableAsPostFilter(callable $callable, ?string $name = null) {
if ($name === null) {
$this->postFilters[] = new FilterPluginWrapper($callable);
} else {
$this->postFilters[$name] = new FilterPluginWrapper($callable);
}
}
public function removePostFilter(string $name) {
unset($this->postFilters[$name]);
}
/**
* @var array
*/
private $outputFilters = [];
public function getOutputFilters(): array {
return $this->outputFilters;
}
public function addOutputFilter(\Smarty\Filter\FilterInterface $filter) {
$this->outputFilters[] = $filter;
}
public function addCallableAsOutputFilter(callable $callable, ?string $name = null) {
if ($name === null) {
$this->outputFilters[] = new FilterPluginWrapper($callable);
} else {
$this->outputFilters[$name] = new FilterPluginWrapper($callable);
}
}
public function removeOutputFilter(string $name) {
unset($this->outputFilters[$name]);
}
public function loadPluginsFromDir(string $path) { public function loadPluginsFromDir(string $path) {
foreach([ foreach([

View File

@@ -74,12 +74,6 @@ class DefaultExtension extends Base {
return null; return null;
} }
public function getOutputFilters(): array {
return [
new \Smarty\Filter\Output\TrimWhitespace(),
];
}
/** /**
* Smarty spacify modifier plugin * Smarty spacify modifier plugin
* Type: modifier * Type: modifier

View File

@@ -0,0 +1,15 @@
<?php
namespace Smarty\Filter;
class FilterPluginWrapper implements FilterInterface {
private $callback;
public function __construct($callback) {
$this->callback = $callback;
}
public function filter($code, \Smarty\Template $template) {
return call_user_func($this->callback, $code, $template);
}
}

View File

@@ -11,7 +11,6 @@ namespace Smarty\Filter\Output;
* @param string $source input string * @param string $source input string
* *
* @return string filtered output * @return string filtered output
* @todo substr_replace() is not overloaded by mbstring.func_overload - so this function might fail!
*/ */
class TrimWhitespace implements \Smarty\Filter\FilterInterface { class TrimWhitespace implements \Smarty\Filter\FilterInterface {

View File

@@ -9,6 +9,7 @@ use Smarty\Extension\BCPluginsAdapter;
use Smarty\Extension\CoreExtension; use Smarty\Extension\CoreExtension;
use Smarty\Extension\DefaultExtension; use Smarty\Extension\DefaultExtension;
use Smarty\Extension\ExtensionInterface; use Smarty\Extension\ExtensionInterface;
use Smarty\Filter\Output\TrimWhitespace;
use Smarty\Smarty\Runtime\CaptureRuntime; use Smarty\Smarty\Runtime\CaptureRuntime;
use Smarty\Smarty\Runtime\ForeachRuntime; use Smarty\Smarty\Runtime\ForeachRuntime;
use Smarty\Smarty\Runtime\InheritanceRuntime; use Smarty\Smarty\Runtime\InheritanceRuntime;
@@ -2113,4 +2114,157 @@ class Smarty extends \Smarty\TemplateBase
return $this->default_plugin_handler_func; return $this->default_plugin_handler_func;
} }
/**
* load a filter of specified type and name
*
* @param string $type filter type
* @param string $name filter name
*
* @return bool
* @throws \Smarty\Exception
* @api Smarty::loadFilter()
* @link https://www.smarty.net/docs/en/api.load.filter.tpl
*
* @deprecated since 5.0
*/
public function loadFilter($type, $name) {
trigger_error('Using Smarty::loadFilter() to load filters is deprecated and will be ' .
'removed in a future release. Use Smarty::addExtension() to add an extension or Smarty::registerFilter to ' .
'quickly register a filter using a callback function.', E_USER_DEPRECATED);
if ($type == 'output' && $name == 'trimwhitespace') {
$this->BCPluginsAdapter->addOutputFilter(new TrimWhitespace());
return true;
} else {
$_plugin = "smarty_{$type}filter_{$name}";
if (!is_callable($_plugin) && class_exists($_plugin, false)) {
$_plugin = [$_plugin, 'execute'];
}
}
if (is_callable($_plugin)) {
$this->registerFilter($type, $_plugin, $name);
return true;
}
throw new Exception("{$type}filter '{$name}' not found or callable");
}
/**
* load a filter of specified type and name
*
* @param string $type filter type
* @param string $name filter name
*
* @return TemplateBase
* @throws \Smarty\Exception
* @api Smarty::unloadFilter()
*
* @link https://www.smarty.net/docs/en/api.unload.filter.tpl
*
* @deprecated since 5.0
*/
public function unloadFilter($type, $name) {
trigger_error('Using Smarty::unloadFilter() to unload filters is deprecated and will be ' .
'removed in a future release. Use Smarty::addExtension() to add an extension or Smarty::(un)registerFilter to ' .
'quickly (un)register a filter using a callback function.', E_USER_DEPRECATED);
return $this->unregisterFilter($type, $name);
}
/**
* Registers a filter function
*
* @param string $type filter type
* @param callable $callback
* @param string|null $name optional filter name
*
* @return TemplateBase
* @throws \Smarty\Exception
* @link https://www.smarty.net/docs/en/api.register.filter.tpl
*
* @api Smarty::registerFilter()
*/
public function registerFilter($type, $callback, $name = null) {
$name = $name ?? $this->_getFilterName($callback);
if (!is_callable($callback)) {
throw new Exception("{$type}filter '{$name}' not callable");
}
switch ($type) {
case 'output':
$this->BCPluginsAdapter->addCallableAsOutputFilter($callback, $name);
break;
case 'pre':
$this->BCPluginsAdapter->addCallableAsPreFilter($callback, $name);
break;
case 'post':
$this->BCPluginsAdapter->addCallableAsPostFilter($callback, $name);
break;
default:
throw new Exception("Illegal filter type '{$type}'");
}
return $this;
}
/**
* Return internal filter name
*
* @param callback $callable
*
* @return string|null internal filter name or null if callable cannot be serialized
*/
private function _getFilterName($callable)
{
if (is_array($callable)) {
$_class_name = is_object($callable[0]) ? get_class($callable[0]) : $callable[0];
return $_class_name . '_' . $callable[1];
} elseif (is_string($callable)) {
return $callable;
}
return null;
}
/**
* Unregisters a filter function. Smarty cannot unregister closures/anonymous functions if
* no name was given in ::registerFilter.
*
* @param string $type filter type
* @param callback|string $name the name previously used in ::registerFilter
*
* @return TemplateBase
* @throws \Smarty\Exception
* @api Smarty::unregisterFilter()
*
* @link https://www.smarty.net/docs/en/api.unregister.filter.tpl
*
*/
public function unregisterFilter($type, $name) {
if (!is_string($name)) {
$name = $this->_getFilterName($name);
}
if ($name) {
switch ($type) {
case 'output':
$this->BCPluginsAdapter->removeOutputFilter($name);
break;
case 'pre':
$this->BCPluginsAdapter->removePreFilter($name);
break;
case 'post':
$this->BCPluginsAdapter->removePostFilter($name);
break;
default:
throw new Exception("Illegal filter type '{$type}'");
}
}
return $this;
}
} }

View File

@@ -244,8 +244,8 @@ class Template extends TemplateBase {
if ( if (
!$no_output_filter !$no_output_filter
&& (!$this->caching || $this->cached->has_nocache_code || $this->source->handler->recompiled) && (!$this->caching || $this->cached->has_nocache_code || $this->source->handler->recompiled)
&& isset($this->smarty->registered_filters['output'])
) { ) {
return $this->smarty->runOutputFilters(ob_get_clean(), $this); return $this->smarty->runOutputFilters(ob_get_clean(), $this);
} }
// return cache content // return cache content

View File

@@ -368,7 +368,6 @@ class Cached extends ResourceBase {
if ( if (
!$no_output_filter !$no_output_filter
&& !$_template->cached->has_nocache_code && !$_template->cached->has_nocache_code
&& isset($_template->smarty->registered_filters['output'])
) { ) {
$content = $_template->smarty->runOutputFilters($content, $_template); $content = $_template->smarty->runOutputFilters($content, $_template);
} }

View File

@@ -76,13 +76,6 @@ abstract class TemplateBase extends Data {
*/ */
public $_var_stack = null; public $_var_stack = null;
/**
* Valid filter types
*
* @var array
*/
private $filterTypes = ['pre' => true, 'post' => true, 'output' => true, 'variable' => true];
/** /**
* fetches a rendered Smarty template * fetches a rendered Smarty template
* *
@@ -252,117 +245,6 @@ abstract class TemplateBase extends Data {
} }
} }
/**
* load a filter of specified type and name
*
* @param string $type filter type
* @param string $name filter name
*
* @return bool
* @throws \Smarty\Exception
* @api Smarty::loadFilter()
* @link https://www.smarty.net/docs/en/api.load.filter.tpl
*
*/
public function loadFilter($type, $name) {
$smarty = $this->_getSmartyObj();
$this->_checkFilterType($type);
$_plugin = "smarty_{$type}filter_{$name}";
$_filter_name = $_plugin;
if (is_callable($_plugin)) {
$smarty->registered_filters[$type][$_filter_name] = $_plugin;
return true;
}
if (class_exists($_plugin, false)) {
$_plugin = [$_plugin, 'execute'];
}
if (is_callable($_plugin)) {
$smarty->registered_filters[$type][$_filter_name] = $_plugin;
return true;
}
throw new Exception("{$type}filter '{$name}' not found or callable");
}
/**
* load a filter of specified type and name
*
* @param string $type filter type
* @param string $name filter name
*
* @return TemplateBase
* @throws \Smarty\Exception
* @api Smarty::unloadFilter()
*
* @link https://www.smarty.net/docs/en/api.unload.filter.tpl
*
*/
public function unloadFilter($type, $name) {
$smarty = $this->_getSmartyObj();
$this->_checkFilterType($type);
if (isset($smarty->registered_filters[$type])) {
$_filter_name = "smarty_{$type}filter_{$name}";
if (isset($smarty->registered_filters[$type][$_filter_name])) {
unset($smarty->registered_filters[$type][$_filter_name]);
if (empty($smarty->registered_filters[$type])) {
unset($smarty->registered_filters[$type]);
}
}
}
return $this;
}
/**
* Registers a filter function
*
* @param string $type filter type
* @param callable $callback
* @param string|null $name optional filter name
*
* @return TemplateBase
* @throws \Smarty\Exception
* @link https://www.smarty.net/docs/en/api.register.filter.tpl
*
* @api Smarty::registerFilter()
*/
public function registerFilter($type, $callback, $name = null) {
$smarty = $this->_getSmartyObj();
$this->_checkFilterType($type);
$name = isset($name) ? $name : $this->_getFilterName($callback);
if (!is_callable($callback)) {
throw new Exception("{$type}filter '{$name}' not callable");
}
$smarty->registered_filters[$type][$name] = $callback;
return $this;
}
/**
* Unregisters a filter function
*
* @param string $type filter type
* @param callback|string $callback
*
* @return TemplateBase
* @throws \Smarty\Exception
* @api Smarty::unregisterFilter()
*
* @link https://www.smarty.net/docs/en/api.unregister.filter.tpl
*
*/
public function unregisterFilter($type, $callback) {
$smarty = $this->_getSmartyObj();
$this->_checkFilterType($type);
if (isset($smarty->registered_filters[$type])) {
$name = is_string($callback) ? $callback : $this->_getFilterName($callback);
if (isset($smarty->registered_filters[$type][$name])) {
unset($smarty->registered_filters[$type][$name]);
if (empty($smarty->registered_filters[$type])) {
unset($smarty->registered_filters[$type]);
}
}
}
return $this;
}
/** /**
* Registers object to be used in templates * Registers object to be used in templates
* *
@@ -622,37 +504,6 @@ abstract class TemplateBase extends Data {
$smarty->literals = array_merge((array)$smarty->literals, (array)$literals); $smarty->literals = array_merge((array)$smarty->literals, (array)$literals);
} }
/**
* Check if filter type is valid
*
* @param string $type
*
* @throws \Smarty\Exception
*/
private function _checkFilterType($type) {
if (!isset($this->filterTypes[$type])) {
throw new Exception("Illegal filter type '{$type}'");
}
}
/**
* Return internal filter name
*
* @param callback $function_name
*
* @return string internal filter name
*/
private function _getFilterName($function_name) {
if (is_array($function_name)) {
$_class_name = (is_object($function_name[0]) ? get_class($function_name[0]) : $function_name[0]);
return $_class_name . '_' . $function_name[1];
} elseif (is_string($function_name)) {
return $function_name;
} else {
return 'closure';
}
}
/** /**
* Registers static classes to be used in templates * Registers static classes to be used in templates
* *

View File

@@ -26,6 +26,15 @@ class FilterTest extends PHPUnit_Smarty
$this->cleanDirs(); $this->cleanDirs();
} }
/**
* test loaded filter
*/
public function testNoOutputFilter()
{
$tpl = $this->smarty->createTemplate('string:{" <br>hello world"}');
$this->assertEquals(" <br>hello world", $this->smarty->fetch($tpl));
}
/** /**
* test loaded filter * test loaded filter
*/ */
@@ -87,6 +96,7 @@ class FilterTest extends PHPUnit_Smarty
$this->smarty->assign('bar', 6); $this->smarty->assign('bar', 6);
$this->smarty->registerFilter(\Smarty\Smarty::FILTER_OUTPUT, 'myoutputfilter2'); $this->smarty->registerFilter(\Smarty\Smarty::FILTER_OUTPUT, 'myoutputfilter2');
$this->assertEquals('5 filter 6', $this->smarty->fetch('output_001.tpl')); $this->assertEquals('5 filter 6', $this->smarty->fetch('output_001.tpl'));
} }
/** /**

View File

@@ -47,8 +47,6 @@ class AppendByRefTest extends PHPUnit_Smarty
/** /**
* test appendByRef merge * test appendByRef merge
*
* @todo fix testAppendByRefMerge
*/ */
public function testAppendByRefMerge() public function testAppendByRefMerge()
{ {