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

View File

@@ -10,6 +10,10 @@
namespace Smarty\Compile; namespace Smarty\Compile;
use Smarty\Compiler\Template;
use Smarty\CompilerException;
use Smarty\Exception;
/** /**
* Smarty Internal Plugin Compile Block Plugin Class * Smarty Internal Plugin Compile Block Plugin Class
* *
@@ -33,78 +37,117 @@ class BlockCompiler extends Base {
*/ */
public $nesting = 0; public $nesting = 0;
/** /**
* Compiles code for the execution of block plugin * Compiles code for the execution of block plugin
* *
* @param array $args array with attributes from parser * @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 array $parameter array with compilation parameter
* @param string $tag name of block plugin * @param string $tag name of block plugin
* @param string $function PHP function name * @param string $function PHP function name
* *
* @return string compiled code * @return string compiled code
* @throws \Smarty\CompilerException * @throws CompilerException
* @throws \Smarty\Exception * @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') { if (!isset($tag[5]) || substr($tag, -5) !== 'close') {
// opening tag of block plugin $output = $this->compileOpeningTag($compiler, $args, $tag, $function);
// 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) . ')';
// 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]);
// maybe nocache because of nocache variables or nocache plugin
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
} else { } else {
// must endblock be nocache? $output = $this->compileClosingTag($compiler, $tag, $parameter, $function);
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));
// compile code
if (!isset($parameter['modifier_list'])) {
$mod_pre = $mod_post = $mod_content = '';
$mod_content2 = 'ob_get_clean()';
} else {
$mod_content2 = "\$_block_content{$this->nesting}";
$mod_content = "\$_block_content{$this->nesting} = ob_get_clean();\n";
$mod_pre = "ob_start();\n";
$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 .= '?>';
} }
return $output; return $output;
} }
/** /**
* Setup callback and parameter array * Returns the code used for the isset check
* *
* @param \Smarty\Compiler\Template $compiler * @param string $tag tag name
* @param array $_attr attributes * @param string $function base tag or method name
* @param string $tag
* @param string $function
* *
* @return array * @return string
*/ */
protected function setup(\Smarty\Compiler\Template $compiler, $_attr, $tag, $function) { protected function getIsCallableCode($tag, $function): string {
$_paramsArray = $this->formatParamsArray($_attr); return "\$_smarty_tpl->smarty->getBlockHandler(" . var_export($function, true) . ")";
return [$function, $_paramsArray, null];
} }
/**
* 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']);
$_params = 'array(' . implode(',', $this->formatParamsArray($_attr)) . ')';
// compile code
$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;
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
$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 = '';
$mod_content2 = 'ob_get_clean()';
} else {
$mod_content2 = "\$_block_content{$this->nesting}";
$mod_content = "\$_block_content{$this->nesting} = ob_get_clean();\n";
$mod_pre = "ob_start();\n";
$mod_post = 'echo ' . $compiler->compileModifier($parameter['modifier_list'], 'ob_get_clean()')
. ";\n";
}
$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;
}
} }

View File

@@ -11,6 +11,8 @@
namespace Smarty\Compile; namespace Smarty\Compile;
use Smarty\Compiler\Template; use Smarty\Compiler\Template;
use Smarty\CompilerException;
use Smarty\Exception;
/** /**
* Smarty Internal Plugin Compile Object Block Function Class * Smarty Internal Plugin Compile Object Block Function Class
@@ -21,18 +23,19 @@ use Smarty\Compiler\Template;
class ObjectMethodBlockCompiler extends BlockCompiler { class ObjectMethodBlockCompiler extends BlockCompiler {
/** /**
* Setup callback and parameter array * @inheritDoc
*
* @param Template $compiler
* @param array $_attr attributes
* @param string $tag
* @param string $function
*
* @return array
*/ */
protected function setup(Template $compiler, $_attr, $tag, $function) { protected function getIsCallableCode($tag, $function): string {
$_paramsArray = $this->formatParamsArray($_attr); $callbackObject = "\$_smarty_tpl->smarty->registered_objects['{$tag}'][0]";
$callback = ["\$_smarty_tpl->smarty->registered_objects['{$tag}'][0]", "->{$function}"]; return "(isset({$callbackObject}) && is_callable(array({$callbackObject}, '{$function}')))";
return [$callback, $_paramsArray, "array(\$_block_plugin{$this->nesting}, '{$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 * @var string
*/ */
public $postfixCompiledCode = ''; public $postfixCompiledCode = '';
/**
* @var ObjectMethodBlockCompiler
*/
private $objectMethodBlockCompiler;
/** /**
* Initialize compiler * Initialize compiler
@@ -302,6 +306,8 @@ class Template extends BaseCompiler {
'_', '_',
uniqid(mt_rand(), true) 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]); || in_array($method, $this->smarty->registered_objects[$base_tag][1]);
if ($allowedAsBlockFunction) { if ($allowedAsBlockFunction) {
return (new ObjectMethodBlockCompiler())->compile($args, $this, $parameter, $tag, $method); return $this->objectMethodBlockCompiler->compile($args, $this, $parameter, $tag, $method);
} elseif ($allowedAsNormalFunction) { } elseif ($allowedAsNormalFunction) {
return (new ObjectMethodCallCompiler())->compile($args, $this, $parameter, $tag, $method); return (new ObjectMethodCallCompiler())->compile($args, $this, $parameter, $tag, $method);
} }
@@ -1439,7 +1445,7 @@ class Template extends BaseCompiler {
// closing tag // closing tag
if ($allowedAsBlockFunction) { if ($allowedAsBlockFunction) {
return (new ObjectMethodBlockCompiler())->compile($args, $this, $parameter, $tag, $method); return $this->objectMethodBlockCompiler->compile($args, $this, $parameter, $tag, $method);
} }
$this->trigger_template_error( $this->trigger_template_error(

View File

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