Skip to content

Commit

Permalink
Implemented support for substr, implode and json_encode as modifiers.
Browse files Browse the repository at this point in the history
Fixes #939
  • Loading branch information
wisskid committed Feb 25, 2024
1 parent 66edb56 commit e249440
Show file tree
Hide file tree
Showing 10 changed files with 233 additions and 9 deletions.
1 change: 1 addition & 0 deletions changelog/939.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Add support for implode, substr and json_encode as modifiers/functions in templates [#939](https://github.com/smarty-php/smarty/issues/939)
14 changes: 14 additions & 0 deletions src/Compile/Modifier/JsonEncodeModifierCompiler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace Smarty\Compile\Modifier;

/**
* Smarty json_encode modifier plugin
*/
class JsonEncodeModifierCompiler extends Base {

public function compile($params, \Smarty\Compiler\Template $compiler) {
return 'json_encode(' . $params[0] . (isset($params[1]) ? ', (int) ' . $params[1] : '') . ')';
}

}
15 changes: 15 additions & 0 deletions src/Compile/Modifier/SubstrModifierCompiler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace Smarty\Compile\Modifier;

/**
* Smarty substr modifier plugin
*/
class SubstrModifierCompiler extends Base {

public function compile($params, \Smarty\Compiler\Template $compiler) {
return 'substr((string) ' . $params[0] . ', (int) ' . $params[1] .
(isset($params[2]) ? ', (int) ' . $params[2] : '') . ')';
}

}
13 changes: 8 additions & 5 deletions src/Compile/ModifierCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,24 +43,27 @@ public function compile($args, \Smarty\Compiler\Template $compiler, $parameter =
foreach ($parameter['modifierlist'] as $single_modifier) {
/* @var string $modifier */
$modifier = $single_modifier[0];
$single_modifier[0] = $output;
$params = implode(',', $single_modifier);


$modifier_params = array_values($single_modifier);

$modifier_params[0] = $output;
$params = implode(',', $modifier_params);

if (!is_object($compiler->getSmarty()->security_policy)
|| $compiler->getSmarty()->security_policy->isTrustedModifier($modifier, $compiler)
) {

if ($handler = $compiler->getModifierCompiler($modifier)) {
$output = $handler->compile($single_modifier, $compiler);

$output = $handler->compile($modifier_params, $compiler);
} elseif ($compiler->getSmarty()->getModifierCallback($modifier)) {
$output = sprintf(
'$_smarty_tpl->getSmarty()->getModifierCallback(%s)(%s)',
var_export($modifier, true),
$params
);
} elseif ($callback = $compiler->getPluginFromDefaultHandler($modifier, \Smarty\Smarty::PLUGIN_MODIFIERCOMPILER)) {
$output = (new \Smarty\Compile\Modifier\BCPluginWrapper($callback))->compile($single_modifier, $compiler);
$output = (new \Smarty\Compile\Modifier\BCPluginWrapper($callback))->compile($modifier_params, $compiler);
} elseif ($function = $compiler->getPluginFromDefaultHandler($modifier, \Smarty\Smarty::PLUGIN_MODIFIER)) {
if (!is_array($function)) {
$output = "{$function}({$params})";
Expand Down
4 changes: 1 addition & 3 deletions src/Compiler/Configfile.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,6 @@ class Configfile extends BaseCompiler {
* @param Smarty $smarty global instance
*/
public function __construct(Smarty $smarty) {
$this->smarty = $smarty;
// get required plugins
$this->smarty = $smarty;
$this->config_data['sections'] = [];
$this->config_data['vars'] = [];
Expand Down Expand Up @@ -104,7 +102,7 @@ public function compileTemplate(Template $template) {
) . "\n",
$this
);
/* @var ConfigfileParser $this->parser */

$this->parser = new ConfigfileParser($this->lex, $this);
if ($this->smarty->_parserdebug) {
$this->parser->PrintTrace();
Expand Down
24 changes: 24 additions & 0 deletions src/Extension/DefaultExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public function getModifierCompiler(string $modifier): ?\Smarty\Compile\Modifier
case 'from_charset': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\FromCharsetModifierCompiler(); break;
case 'indent': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\IndentModifierCompiler(); break;
case 'isset': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\IssetModifierCompiler(); break;
case 'json_encode': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\JsonEncodeModifierCompiler(); break;
case 'lower': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\LowerModifierCompiler(); break;
case 'nl2br': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\Nl2brModifierCompiler(); break;
case 'noprint': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\NoPrintModifierCompiler(); break;
Expand All @@ -37,6 +38,7 @@ public function getModifierCompiler(string $modifier): ?\Smarty\Compile\Modifier
case 'strip': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\StripModifierCompiler(); break;
case 'strip_tags': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\StripTagsModifierCompiler(); break;
case 'strlen': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\StrlenModifierCompiler(); break;
case 'substr': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\SubstrModifierCompiler(); break;
case 'to_charset': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\ToCharsetModifierCompiler(); break;
case 'unescape': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\UnescapeModifierCompiler(); break;
case 'upper': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\UpperModifierCompiler(); break;
Expand All @@ -54,6 +56,7 @@ public function getModifierCallback(string $modifierName) {
case 'debug_print_var': return [$this, 'smarty_modifier_debug_print_var'];
case 'escape': return [$this, 'smarty_modifier_escape'];
case 'explode': return [$this, 'smarty_modifier_explode'];
case 'implode': return [$this, 'smarty_modifier_implode'];
case 'mb_wordwrap': return [$this, 'smarty_modifier_mb_wordwrap'];
case 'number_format': return [$this, 'smarty_modifier_number_format'];
case 'regex_replace': return [$this, 'smarty_modifier_regex_replace'];
Expand Down Expand Up @@ -522,6 +525,27 @@ public function smarty_modifier_explode($separator, $string, ?int $limit = null)
return explode($separator, $string ?? '', $limit ?? PHP_INT_MAX);
}

/**
* Smarty implode modifier plugin
* Type: modifier
* Name: implode
* Purpose: join an array of values into a single string
*
* @param array $values
* @param string $separator
*
* @return string
*/
public function smarty_modifier_implode($values, $separator = '')
{
if (is_array($separator)) {
trigger_error("Using implode with the separator first is deprecated. " .
"Call implode using the array first, separator second.", E_USER_DEPRECATED);
return implode((string) ($values ?? ''), (array) $separator);
}
return implode((string) ($separator ?? ''), (array) $values);
}

/**
* Smarty wordwrap modifier plugin
* Type: modifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ public function testNativePHPModifiers($template, $expectedValue)

public function dataUnknownModifiers(): array {
return [
['{"blah"|substr:1:2}', 'la'],
['{" blah"|ltrim:" "}', 'blah'],
['{"blah"|strrev}', 'halb'],
['{"blah"|ucfirst}', 'Blah'],
['{"blah"|md5}', md5('blah')],
];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php
/**
* Smarty PHPunit tests of modifier
*/

namespace UnitTests\TemplateSource\TagTests\PluginModifier;
use PHPUnit_Smarty;

class PluginModifierImplodeTest extends PHPUnit_Smarty
{
public function setUp(): void
{
$this->setUpSmarty(__DIR__);
}

public function testDefault()
{
$tpl = $this->smarty->createTemplate('string:{$v|implode}');
$tpl->assign("v", ["1", "2"]);
$this->assertEquals("12", $this->smarty->fetch($tpl));
}
public function testWithSeparator()
{
$tpl = $this->smarty->createTemplate('string:{$v|implode:","}');
$tpl->assign("v", ["a", "b"]);
$this->assertEquals("a,b", $this->smarty->fetch($tpl));
}
/**
* @deprecated
*/
public function testLegacyArgumentOrder()
{
$tpl = $this->smarty->createTemplate('string:{","|implode:$v}');
$tpl->assign("v", ["a", "b"]);
$this->assertEquals("a,b", $this->smarty->fetch($tpl));
}

public function testInConditional()
{
$tpl = $this->smarty->createTemplate('string:{if implode($v) == "abc"}good{else}bad{/if}');
$tpl->assign("v", ['a','b','c']);
$this->assertEquals("good", $this->smarty->fetch($tpl));
}

public function testInConditionalWithSeparator()
{
$tpl = $this->smarty->createTemplate('string:{if implode($v, "-") == "a-b-c"}good{else}bad{/if}');
$tpl->assign("v", ['a','b','c']);
$this->assertEquals("good", $this->smarty->fetch($tpl));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php
/**
* Smarty PHPunit tests of modifier
*/

namespace UnitTests\TemplateSource\TagTests\PluginModifier;
use PHPUnit_Smarty;

class PluginModifierJsonEncodeTest extends PHPUnit_Smarty
{
public function setUp(): void
{
$this->setUpSmarty(__DIR__);
}

/**
* @dataProvider dataForDefault
*/
public function testDefault($value, $expected)
{
$tpl = $this->smarty->createTemplate('string:{$v|json_encode}');
$tpl->assign("v", $value);
$this->assertEquals($expected, $this->smarty->fetch($tpl));
}

/**
* @dataProvider dataForDefault
*/
public function testDefaultAsFunction($value, $expected)
{
$tpl = $this->smarty->createTemplate('string:{json_encode($v)}');
$tpl->assign("v", $value);
$this->assertEquals($expected, $this->smarty->fetch($tpl));
}

public function dataForDefault() {
return [
["abc", '"abc"'],
[["abc"], '["abc"]'],
[["abc",["a"=>2]], '["abc",{"a":2}]'],
];
}

/**
* @dataProvider dataForForceObject
*/
public function testForceObject($value, $expected)
{
$tpl = $this->smarty->createTemplate('string:{$v|json_encode:16}');
$tpl->assign("v", $value);
$this->assertEquals($expected, $this->smarty->fetch($tpl));
}

/**
* @dataProvider dataForForceObject
*/
public function testForceObjectAsFunction($value, $expected)
{
$tpl = $this->smarty->createTemplate('string:{json_encode($v,16)}');
$tpl->assign("v", $value);
$this->assertEquals($expected, $this->smarty->fetch($tpl));
}

public function dataForForceObject() {
return [
["abc", '"abc"'],
[["abc"], '{"0":"abc"}'],
[["abc",["a"=>2]], '{"0":"abc","1":{"a":2}}'],
];
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php
/**
* Smarty PHPunit tests of modifier
*/

namespace UnitTests\TemplateSource\TagTests\PluginModifier;
use PHPUnit_Smarty;

class PluginModifierSubstrTest extends PHPUnit_Smarty
{
public function setUp(): void
{
$this->setUpSmarty(__DIR__);
}

public function testDefault()
{
$tpl = $this->smarty->createTemplate('string:{$v|substr:1}');
$tpl->assign("v", "abc");
$this->assertEquals("bc", $this->smarty->fetch($tpl));
}

public function testTwoArguments()
{
$tpl = $this->smarty->createTemplate('string:{$v|substr:1:1}');
$tpl->assign("v", "abc");
$this->assertEquals("b", $this->smarty->fetch($tpl));
}

public function testNegativeOffset()
{
$tpl = $this->smarty->createTemplate('string:{$v|substr:-1}');
$tpl->assign("v", "abc");
$this->assertEquals("c", $this->smarty->fetch($tpl));
}

public function testInConditional()
{
$tpl = $this->smarty->createTemplate('string:{if substr($v, -1) == "c"}good{else}bad{/if}');
$tpl->assign("v", "abc");
$this->assertEquals("good", $this->smarty->fetch($tpl));
}

}

0 comments on commit e249440

Please sign in to comment.