Fix code duplication in block compilers and fix (most) BlockPluginTests. Default plugin handler blocks still need fixing.

This commit is contained in:
Simon Wisselink
2023-01-04 23:45:57 +01:00
parent 216347b4ff
commit 3cc61133a3
6 changed files with 129 additions and 144 deletions

View File

@@ -13,6 +13,6 @@ class BlockPluginWrapper implements BlockHandlerInterface {
}
public function handle($params, $content, Template $template, &$repeat) {
return call_user_func($this->callback, $params, $content, $template, $repeat);
return call_user_func_array($this->callback, [$params, $content, $template, &$repeat]);
}
}

View File

@@ -2,6 +2,7 @@
namespace Smarty\BlockHandler;
use Smarty\Smarty;
use Smarty\Template;
/**
@@ -78,8 +79,8 @@ class TextFormat implements BlockHandlerInterface {
$_paragraph =
preg_replace(
array(
'!\s+!' . \Smarty::$_UTF8_MODIFIER,
'!(^\s+)|(\s+$)!' . \Smarty::$_UTF8_MODIFIER
'!\s+!' . Smarty::$_UTF8_MODIFIER,
'!(^\s+)|(\s+$)!' . Smarty::$_UTF8_MODIFIER
),
array(
' ',

View File

@@ -10,6 +10,10 @@
namespace Smarty\Compile;
use Smarty\Compiler\Template;
use Smarty\CompilerException;
use Smarty\Exception;
/**
* Smarty Internal Plugin Compile Block Plugin Class
*
@@ -33,48 +37,101 @@ class BlockCompiler extends Base {
*/
public $nesting = 0;
/**
* Compiles code for the execution of block plugin
*
* @param array $args array with attributes from parser
* @param \Smarty\Compiler\Template $compiler compiler object
* @param Template $compiler compiler object
* @param array $parameter array with compilation parameter
* @param string $tag name of block plugin
* @param string $function PHP function name
*
* @return string compiled code
* @throws \Smarty\CompilerException
* @throws \Smarty\Exception
* @throws CompilerException
* @throws Exception
*/
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
public function compile($args, Template $compiler, $parameter = [], $tag = null, $function = null) {
if (!isset($tag[5]) || substr($tag, -5) !== 'close') {
// opening tag of block plugin
$output = $this->compileOpeningTag($compiler, $args, $tag, $function);
} else {
$output = $this->compileClosingTag($compiler, $tag, $parameter, $function);
}
return $output;
}
/**
* Returns the code used for the isset check
*
* @param string $tag tag name
* @param string $function base tag or method name
*
* @return string
*/
protected function getIsCallableCode($tag, $function): string {
return "\$_smarty_tpl->smarty->getBlockHandler(" . var_export($function, true) . ")";
}
/**
* Returns the full code used to call the callback
*
* @param string $tag tag name
* @param string $function base tag or method name
*
* @return string
*/
protected function getFullCallbackCode($tag, $function): string {
return "\$_smarty_tpl->smarty->getBlockHandler(" . var_export($function, true) . ")->handle";
}
/**
* @param Template $compiler
* @param array $args
* @param string|null $tag
* @param string|null $function
*
* @return string
*/
private function compileOpeningTag(Template $compiler, array $args, ?string $tag, ?string $function): string {
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
$this->nesting++;
unset($_attr['nocache']);
[$callback, $_paramsArray, $callable] = $this->setup($compiler, $_attr, $tag, $function);
$_params = 'array(' . implode(',', $_paramsArray) . ')';
$_params = 'array(' . implode(',', $this->formatParamsArray($_attr)) . ')';
// compile code
$output = "<?php ";
if (is_array($callback)) {
$output .= "\$_block_plugin{$this->nesting} = isset({$callback[0]}) ? {$callback[0]} : null;\n";
$callback = "\$_block_plugin{$this->nesting}{$callback[1]}";
}
if (isset($callable)) {
$output .= "if (!is_callable({$callable})) {\nthrow new \\Smarty\\Exception('block tag \'{$tag}\' not callable or registered');\n}\n";
}
$output .= "\$_block_repeat=true;\necho {$callback}({$_params}, null, \$_smarty_tpl, \$_block_repeat);\nwhile (\$_block_repeat) {\nob_start();?>";
$this->openTag($compiler, $tag, [$_params, $compiler->nocache, $callback]);
$output = "<?php \$_block_repeat=true;
if (!" . $this->getIsCallableCode($tag, $function) .") {\nthrow new \\Smarty\\Exception('block tag \'{$tag}\' not callable or registered');\n}\n
echo " . $this->getFullCallbackCode($tag, $function) . "({$_params}, null, \$_smarty_tpl, \$_block_repeat);
while (\$_block_repeat) {
ob_start();
?>";
$this->openTag($compiler, $tag, [$_params, $compiler->nocache]);
// maybe nocache because of nocache variables or nocache plugin
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
} else {
return $output;
}
/**
* @param Template $compiler
* @param string $tag
* @param array $parameter
* @param string|null $function
*
* @return string
* @throws CompilerException
* @throws Exception
*/
private function compileClosingTag(Template $compiler, string $tag, array $parameter, ?string $function): string {
// must endblock be nocache?
if ($compiler->nocache) {
$compiler->tag_nocache = true;
}
// closing tag of block plugin, restore nocache
[$_params, $compiler->nocache, $callback] = $this->closeTag($compiler, substr($tag, 0, -5));
$base_tag = substr($tag, 0, -5);
[$_params, $compiler->nocache] = $this->closeTag($compiler, $base_tag);
// compile code
if (!isset($parameter['modifier_list'])) {
$mod_pre = $mod_post = $mod_content = '';
@@ -86,25 +143,11 @@ class BlockCompiler extends Base {
$mod_post = 'echo ' . $compiler->compileModifier($parameter['modifier_list'], 'ob_get_clean()')
. ";\n";
}
$output =
"<?php {$mod_content}\$_block_repeat=false;\n{$mod_pre}echo {$callback}({$_params}, {$mod_content2}, \$_smarty_tpl, \$_block_repeat);\n{$mod_post}}\n";
$output .= '?>';
}
$output = "<?php {$mod_content}\$_block_repeat=false;\n{$mod_pre}";
$callback = $this->getFullCallbackCode($base_tag, $function);
$output .= "echo {$callback}({$_params}, {$mod_content2}, \$_smarty_tpl, \$_block_repeat);\n";
$output .= "{$mod_post}}\n?>";
return $output;
}
/**
* Setup callback and parameter array
*
* @param \Smarty\Compiler\Template $compiler
* @param array $_attr attributes
* @param string $tag
* @param string $function
*
* @return array
*/
protected function setup(\Smarty\Compiler\Template $compiler, $_attr, $tag, $function) {
$_paramsArray = $this->formatParamsArray($_attr);
return [$function, $_paramsArray, null];
}
}

View File

@@ -11,6 +11,8 @@
namespace Smarty\Compile;
use Smarty\Compiler\Template;
use Smarty\CompilerException;
use Smarty\Exception;
/**
* Smarty Internal Plugin Compile Object Block Function Class
@@ -21,18 +23,19 @@ use Smarty\Compiler\Template;
class ObjectMethodBlockCompiler extends BlockCompiler {
/**
* Setup callback and parameter array
*
* @param Template $compiler
* @param array $_attr attributes
* @param string $tag
* @param string $function
*
* @return array
* @inheritDoc
*/
protected function setup(Template $compiler, $_attr, $tag, $function) {
$_paramsArray = $this->formatParamsArray($_attr);
$callback = ["\$_smarty_tpl->smarty->registered_objects['{$tag}'][0]", "->{$function}"];
return [$callback, $_paramsArray, "array(\$_block_plugin{$this->nesting}, '{$function}')"];
protected function getIsCallableCode($tag, $function): string {
$callbackObject = "\$_smarty_tpl->smarty->registered_objects['{$tag}'][0]";
return "(isset({$callbackObject}) && is_callable(array({$callbackObject}, '{$function}')))";
}
/**
* @inheritDoc
*/
protected function getFullCallbackCode($tag, $function): string {
$callbackObject = "\$_smarty_tpl->smarty->registered_objects['{$tag}'][0]";
return "{$callbackObject}->{$function}";
}
}

View File

@@ -286,6 +286,10 @@ class Template extends BaseCompiler {
* @var string
*/
public $postfixCompiledCode = '';
/**
* @var ObjectMethodBlockCompiler
*/
private $objectMethodBlockCompiler;
/**
* Initialize compiler
@@ -302,6 +306,8 @@ class Template extends BaseCompiler {
'_',
uniqid(mt_rand(), true)
);
$this->objectMethodBlockCompiler = new ObjectMethodBlockCompiler();
}
/**
@@ -1424,7 +1430,7 @@ class Template extends BaseCompiler {
|| in_array($method, $this->smarty->registered_objects[$base_tag][1]);
if ($allowedAsBlockFunction) {
return (new ObjectMethodBlockCompiler())->compile($args, $this, $parameter, $tag, $method);
return $this->objectMethodBlockCompiler->compile($args, $this, $parameter, $tag, $method);
} elseif ($allowedAsNormalFunction) {
return (new ObjectMethodCallCompiler())->compile($args, $this, $parameter, $tag, $method);
}
@@ -1439,7 +1445,7 @@ class Template extends BaseCompiler {
// closing tag
if ($allowedAsBlockFunction) {
return (new ObjectMethodBlockCompiler())->compile($args, $this, $parameter, $tag, $method);
return $this->objectMethodBlockCompiler->compile($args, $this, $parameter, $tag, $method);
}
$this->trigger_template_error(

View File

@@ -57,10 +57,6 @@ class CompileBlockPluginTest extends PHPUnit_Smarty
/**
* test block plugin function definition in script
*
* @runInSeparateProcess
* @preserveGlobalState disabled
*
*/
public function testBlockPluginRegisteredFunction()
{
@@ -70,9 +66,6 @@ class CompileBlockPluginTest extends PHPUnit_Smarty
/**
* test block plugin function definition in script
*
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testBlockPluginRegisteredFunction2()
{
@@ -83,10 +76,6 @@ class CompileBlockPluginTest extends PHPUnit_Smarty
/**
* test block plugin static method
*
* @runInSeparateProcess
* @preserveGlobalState disabled
*
*/
public function testBlockPluginRegisteredStatic()
{
@@ -96,10 +85,6 @@ class CompileBlockPluginTest extends PHPUnit_Smarty
/**
* test block plugin static method failure
*
* @runInSeparateProcess
* @preserveGlobalState disabled
*
*/
public function testBlockPluginRegisteredStatic2()
{
@@ -110,10 +95,6 @@ class CompileBlockPluginTest extends PHPUnit_Smarty
/**
* test block plugin object method
*
* @runInSeparateProcess
* @preserveGlobalState disabled
*
*/
public function testBlockPluginRegisteredMethod()
{
@@ -124,9 +105,6 @@ class CompileBlockPluginTest extends PHPUnit_Smarty
/**
* test block plugin object method failure
*
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testBlockPluginRegisteredMethod2()
{
@@ -137,10 +115,6 @@ class CompileBlockPluginTest extends PHPUnit_Smarty
/**
* test block plugin registered object
*
* @runInSeparateProcess
* @preserveGlobalState disabled
*
*/
public function testBlockPluginRegisteredObject()
{
@@ -151,23 +125,16 @@ class CompileBlockPluginTest extends PHPUnit_Smarty
/**
* test block plugin registered object failure
*
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testBlockPluginRegisteredObject2()
{
$this->expectException(\Smarty\Exception::class);
$this->expectExceptionMessage('block tag \'myobject\' not callable');
$this->expectExceptionMessage('block tag \'myobject\' not callable or registered');
$this->assertEquals('object block test', $this->smarty->fetch('registered_object.tpl'));
}
/**
* test block plugin repeat function
*
* @runInSeparateProcess
* @preserveGlobalState disabled
*
*/
public function testBlockPluginRepeat()
{
@@ -176,10 +143,6 @@ class CompileBlockPluginTest extends PHPUnit_Smarty
/**
* test block plugin repeat function with modifier
*
* @runInSeparateProcess
* @preserveGlobalState disabled
*
*/
public function testBlockPluginRepeatModidier1()
{
@@ -188,10 +151,6 @@ class CompileBlockPluginTest extends PHPUnit_Smarty
/**
* test block plugin repeat function with modifier list
*
* @runInSeparateProcess
* @preserveGlobalState disabled
*
*/
public function testBlockPluginRepeatModidier2()
{
@@ -200,10 +159,6 @@ class CompileBlockPluginTest extends PHPUnit_Smarty
/**
* test block plugin with no output
*
* @runInSeparateProcess
* @preserveGlobalState disabled
*
*/
public function testBlockPluginNoOutput()
{
@@ -212,10 +167,6 @@ class CompileBlockPluginTest extends PHPUnit_Smarty
/**
* test nested block plugin
*
* @runInSeparateProcess
* @preserveGlobalState disabled
*
*/
public function testBlockPluginNested()
{
@@ -224,10 +175,6 @@ class CompileBlockPluginTest extends PHPUnit_Smarty
/**
* test default block plugin
*
* @runInSeparateProcess
* @preserveGlobalState disabled
*
*/
public function testBlockPluginDefault1()
{
@@ -237,10 +184,6 @@ class CompileBlockPluginTest extends PHPUnit_Smarty
/**
* test default block plugin
*
* @runInSeparateProcess
* @preserveGlobalState disabled
*
*/
public function testBlockPluginDefault2()
{
@@ -251,10 +194,7 @@ class CompileBlockPluginTest extends PHPUnit_Smarty
/**
* Test caching
*
* @runInSeparateProcess
* @preserveGlobalState disabled
* @dataProvider data
*
*/
public function testCache($isCached,
$caching,
@@ -304,9 +244,7 @@ class CompileBlockPluginTest extends PHPUnit_Smarty
/**
* Test spacings
*
* @preserveGlobalState disabled
* @dataProvider dataTestSpacing
* @runInSeparateProcess
*/
public function testSpacing($code, $result, $testName, $testNumber)
{
@@ -345,9 +283,7 @@ class CompileBlockPluginTest extends PHPUnit_Smarty
/**
* Test spacings
*
* @preserveGlobalState disabled
* @dataProvider dataTestDefaultSpacing
* @runInSeparateProcess
*/
public function testSpacingDefault($code, $result, $testName, $testNumber)
{
@@ -389,9 +325,7 @@ class CompileBlockPluginTest extends PHPUnit_Smarty
/**
* Test nocache block spacings
*
* @preserveGlobalState disabled
* @dataProvider dataTestNocacheSpacing
* @runInSeparateProcess
*/
public function testBlockNocache($code, $result, $testName, $testNumber)
{
@@ -409,9 +343,7 @@ class CompileBlockPluginTest extends PHPUnit_Smarty
/**
* Test nocache block spacings
*
* @preserveGlobalState disabled
* @dataProvider dataTestNocacheSpacing
* @runInSeparateProcess
*/
public function testBlockNocache2($code, $result, $testName, $testNumber)
{
@@ -446,7 +378,7 @@ class CompileBlockPluginTest extends PHPUnit_Smarty
}
}
function myblockplugintest($params, $content, &$smarty_tpl, &$repeat)
function myblockplugintest($params, $content, $smarty_tpl, &$repeat)
{
if (!$repeat) {
$output = str_replace('hello world', 'block test', $content);
@@ -455,7 +387,7 @@ function myblockplugintest($params, $content, &$smarty_tpl, &$repeat)
}
}
function myblockplugintest2($params, $content, &$smarty_tpl, &$repeat)
function myblockplugintest2($params, $content, $smarty_tpl, &$repeat)
{
if (!$repeat) {
$output = str_replace('hello world', "block test{$params['var']}", $content);
@@ -466,7 +398,7 @@ function myblockplugintest2($params, $content, &$smarty_tpl, &$repeat)
class myblockclass1
{
static function staticfunc($params, $content, &$smarty_tpl, &$repeat)
static function staticfunc($params, $content, $smarty_tpl, &$repeat)
{
if (!$repeat) {
$output = str_replace('hello world', 'static block test', $content);
@@ -474,7 +406,7 @@ class myblockclass1
}
}
public function methodfunc($params, $content, &$smarty_tpl, &$repeat)
public function methodfunc($params, $content, $smarty_tpl, &$repeat)
{
if (!$repeat) {
$output = str_replace('hello world', 'method block test', $content);
@@ -482,7 +414,7 @@ class myblockclass1
}
}
public function objectfunc($params, $content, &$smarty_tpl, &$repeat)
public function objectfunc($params, $content, $smarty_tpl, &$repeat)
{
if (!$repeat) {
$output = str_replace('hello world', 'object block test', $content);