diff --git a/src/Extension/BCPluginsAdapter.php b/src/Extension/BCPluginsAdapter.php
index 95c9538f..1a46389e 100644
--- a/src/Extension/BCPluginsAdapter.php
+++ b/src/Extension/BCPluginsAdapter.php
@@ -5,6 +5,7 @@ namespace Smarty\Extension;
use Smarty\BlockHandler\BlockPluginWrapper;
use Smarty\Compile\Modifier\BCPluginWrapper as ModifierCompilerPluginWrapper;
use Smarty\Compile\Tag\BCPluginWrapper as TagPluginWrapper;
+use Smarty\Filter\FilterPluginWrapper;
use Smarty\FunctionHandler\BCPluginWrapper as FunctionPluginWrapper;
class BCPluginsAdapter extends Base {
@@ -80,6 +81,82 @@ class BCPluginsAdapter extends Base {
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) {
foreach([
diff --git a/src/Extension/DefaultExtension.php b/src/Extension/DefaultExtension.php
index 5c83ba0b..f5fa2566 100644
--- a/src/Extension/DefaultExtension.php
+++ b/src/Extension/DefaultExtension.php
@@ -74,12 +74,6 @@ class DefaultExtension extends Base {
return null;
}
- public function getOutputFilters(): array {
- return [
- new \Smarty\Filter\Output\TrimWhitespace(),
- ];
- }
-
/**
* Smarty spacify modifier plugin
* Type: modifier
diff --git a/src/Filter/FilterPluginWrapper.php b/src/Filter/FilterPluginWrapper.php
new file mode 100644
index 00000000..665ee385
--- /dev/null
+++ b/src/Filter/FilterPluginWrapper.php
@@ -0,0 +1,15 @@
+callback = $callback;
+ }
+ public function filter($code, \Smarty\Template $template) {
+ return call_user_func($this->callback, $code, $template);
+ }
+}
\ No newline at end of file
diff --git a/src/Filter/Output/TrimWhitespace.php b/src/Filter/Output/TrimWhitespace.php
index 83887ca7..199d097f 100644
--- a/src/Filter/Output/TrimWhitespace.php
+++ b/src/Filter/Output/TrimWhitespace.php
@@ -11,7 +11,6 @@ namespace Smarty\Filter\Output;
* @param string $source input string
*
* @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 {
diff --git a/src/Smarty.php b/src/Smarty.php
index c5a28ec5..77bbef58 100644
--- a/src/Smarty.php
+++ b/src/Smarty.php
@@ -9,6 +9,7 @@ use Smarty\Extension\BCPluginsAdapter;
use Smarty\Extension\CoreExtension;
use Smarty\Extension\DefaultExtension;
use Smarty\Extension\ExtensionInterface;
+use Smarty\Filter\Output\TrimWhitespace;
use Smarty\Smarty\Runtime\CaptureRuntime;
use Smarty\Smarty\Runtime\ForeachRuntime;
use Smarty\Smarty\Runtime\InheritanceRuntime;
@@ -2113,4 +2114,157 @@ class Smarty extends \Smarty\TemplateBase
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;
+ }
+
}
+
diff --git a/src/Template.php b/src/Template.php
index c3129e91..d1aa12d8 100644
--- a/src/Template.php
+++ b/src/Template.php
@@ -244,8 +244,8 @@ class Template extends TemplateBase {
if (
!$no_output_filter
&& (!$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 cache content
diff --git a/src/Template/Cached.php b/src/Template/Cached.php
index 869e2ea1..b8377e26 100644
--- a/src/Template/Cached.php
+++ b/src/Template/Cached.php
@@ -368,7 +368,6 @@ class Cached extends ResourceBase {
if (
!$no_output_filter
&& !$_template->cached->has_nocache_code
- && isset($_template->smarty->registered_filters['output'])
) {
$content = $_template->smarty->runOutputFilters($content, $_template);
}
diff --git a/src/TemplateBase.php b/src/TemplateBase.php
index 0813be7f..a3864aad 100644
--- a/src/TemplateBase.php
+++ b/src/TemplateBase.php
@@ -76,13 +76,6 @@ abstract class TemplateBase extends Data {
*/
public $_var_stack = null;
- /**
- * Valid filter types
- *
- * @var array
- */
- private $filterTypes = ['pre' => true, 'post' => true, 'output' => true, 'variable' => true];
-
/**
* 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
*
@@ -622,37 +504,6 @@ abstract class TemplateBase extends Data {
$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
*
diff --git a/tests/UnitTests/A_Core/Filter/FilterTest.php b/tests/UnitTests/A_Core/Filter/FilterTest.php
index 89409073..1fc49dee 100644
--- a/tests/UnitTests/A_Core/Filter/FilterTest.php
+++ b/tests/UnitTests/A_Core/Filter/FilterTest.php
@@ -26,6 +26,15 @@ class FilterTest extends PHPUnit_Smarty
$this->cleanDirs();
}
+ /**
+ * test loaded filter
+ */
+ public function testNoOutputFilter()
+ {
+ $tpl = $this->smarty->createTemplate('string:{"
hello world"}');
+ $this->assertEquals("
hello world", $this->smarty->fetch($tpl));
+ }
+
/**
* test loaded filter
*/
@@ -87,6 +96,7 @@ class FilterTest extends PHPUnit_Smarty
$this->smarty->assign('bar', 6);
$this->smarty->registerFilter(\Smarty\Smarty::FILTER_OUTPUT, 'myoutputfilter2');
$this->assertEquals('5 filter 6', $this->smarty->fetch('output_001.tpl'));
+
}
/**
diff --git a/tests/UnitTests/SmartyMethodsTests/AppendByRef/AppendByRefTest.php b/tests/UnitTests/SmartyMethodsTests/AppendByRef/AppendByRefTest.php
index 0f6abe5e..e97bb8d7 100644
--- a/tests/UnitTests/SmartyMethodsTests/AppendByRef/AppendByRefTest.php
+++ b/tests/UnitTests/SmartyMethodsTests/AppendByRef/AppendByRefTest.php
@@ -47,8 +47,6 @@ class AppendByRefTest extends PHPUnit_Smarty
/**
* test appendByRef merge
- *
- * @todo fix testAppendByRefMerge
*/
public function testAppendByRefMerge()
{