mirror of
https://github.com/smarty-php/smarty.git
synced 2025-07-29 23:47:15 +02:00
* Restore special handling of isset and empty as it was in v4. Fixes #1063
This commit is contained in:
@ -505,7 +505,7 @@ class Template extends BaseCompiler {
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function compileVariable($variable) {
|
||||
public function triggerTagNoCache($variable): void {
|
||||
if (!strpos($variable, '(')) {
|
||||
// not a variable variable
|
||||
$var = trim($variable, '\'');
|
||||
@ -516,7 +516,6 @@ class Template extends BaseCompiler {
|
||||
false
|
||||
)->isNocache();
|
||||
}
|
||||
return '$_smarty_tpl->getValue(' . $variable . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -19,7 +19,7 @@ use \Smarty\ParseTree\Code;
|
||||
use \Smarty\ParseTree\Dq;
|
||||
use \Smarty\ParseTree\DqContent;
|
||||
use \Smarty\ParseTree\Tag;
|
||||
|
||||
use \Smarty\CompilerException;
|
||||
|
||||
/**
|
||||
* Smarty Template Parser Class
|
||||
@ -306,7 +306,8 @@ smartytag(A) ::= SIMPELOUTPUT(B). {
|
||||
$attributes[] = 'nocache';
|
||||
$var = $match[1];
|
||||
}
|
||||
A = $this->compiler->compilePrintExpression($this->compiler->compileVariable('\''.$var.'\''), $attributes);
|
||||
$this->compiler->triggerTagNoCache($var);
|
||||
A = $this->compiler->compilePrintExpression('$_smarty_tpl->getValue(\''.$var.'\')', $attributes);
|
||||
}
|
||||
|
||||
// simple tag like {name}
|
||||
@ -375,7 +376,7 @@ outattr(A) ::= output(B) attributes(C). {
|
||||
A = array(B,C);
|
||||
}
|
||||
|
||||
output(A) ::= variable(B). {
|
||||
output(A) ::= variablevalue(B). {
|
||||
A = B;
|
||||
}
|
||||
output(A) ::= value(B). {
|
||||
@ -689,7 +690,8 @@ nullcoalescing(res) ::= expr(v) QMARK QMARK expr(e2). {
|
||||
// ternary
|
||||
//
|
||||
ternary(res) ::= expr(v) QMARK DOLLARID(e1) COLON expr(e2). {
|
||||
res = v.' ? '. $this->compiler->compileVariable('\''.substr(e1,1).'\'') . ' : '.e2;
|
||||
$this->compiler->triggerTagNoCache(substr(e1,1));
|
||||
res = v.' ? $_smarty_tpl->getValue(\''.substr(e1,1).'\') : '.e2;
|
||||
}
|
||||
|
||||
ternary(res) ::= expr(v) QMARK value(e1) COLON expr(e2). {
|
||||
@ -706,7 +708,7 @@ ternary(res) ::= expr(v) QMARK COLON expr(e2). {
|
||||
}
|
||||
|
||||
// value
|
||||
value(res) ::= variable(v). {
|
||||
value(res) ::= variablevalue(v). {
|
||||
res = v;
|
||||
}
|
||||
|
||||
@ -724,7 +726,7 @@ value(res) ::= TYPECAST(t) value(v). {
|
||||
res = t.v;
|
||||
}
|
||||
|
||||
value(res) ::= variable(v) INCDEC(o). {
|
||||
value(res) ::= variablevalue(v) INCDEC(o). {
|
||||
res = v.o;
|
||||
}
|
||||
|
||||
@ -771,10 +773,10 @@ value(res) ::= OPENP expr(e) CLOSEP. {
|
||||
res = '('. e .')';
|
||||
}
|
||||
|
||||
value(res) ::= variable(v1) INSTANCEOF(i) ns1(v2). {
|
||||
value(res) ::= variablevalue(v1) INSTANCEOF(i) ns1(v2). {
|
||||
res = v1.i.v2;
|
||||
}
|
||||
value(res) ::= variable(v1) INSTANCEOF(i) variable(v2). {
|
||||
value(res) ::= variablevalue(v1) INSTANCEOF(i) variablevalue(v2). {
|
||||
res = v1.i.v2;
|
||||
}
|
||||
|
||||
@ -797,7 +799,8 @@ value(res) ::= varindexed(vi) DOUBLECOLON static_class_access(r). {
|
||||
if (vi['var'] === '\'smarty\'') {
|
||||
$this->compiler->appendPrefixCode("<?php {$prefixVar} = ". (new \Smarty\Compile\SpecialVariableCompiler())->compile(array(),$this->compiler,vi['smarty_internal_index']).';?>');
|
||||
} else {
|
||||
$this->compiler->appendPrefixCode("<?php {$prefixVar} = ". $this->compiler->compileVariable(vi['var']).vi['smarty_internal_index'].';?>');
|
||||
$this->compiler->triggerTagNoCache(vi['var']);
|
||||
$this->compiler->appendPrefixCode("<?php {$prefixVar} = \$_smarty_tpl->getValue(" . vi['var'] . ')'.vi['smarty_internal_index'].';?>');
|
||||
}
|
||||
res = $prefixVar .'::'.r[0].r[1];
|
||||
}
|
||||
@ -847,54 +850,88 @@ ns1(res) ::= NAMESPACE(i). {
|
||||
}
|
||||
|
||||
|
||||
// variable lists
|
||||
|
||||
// multiple variables
|
||||
variablelist(res) ::= variablelist(l) COMMA variable(v). {
|
||||
res = array_merge(l,array(v));
|
||||
}
|
||||
|
||||
variablelist(res) ::= variablelist(l) COMMA expr(e). {
|
||||
res = array_merge(l,array(e));
|
||||
}
|
||||
|
||||
// single variable
|
||||
variablelist(res) ::= variable(v). {
|
||||
res = array(v);
|
||||
}
|
||||
|
||||
// single expression
|
||||
variablelist(res) ::= expr(e). {
|
||||
res = array(e);
|
||||
}
|
||||
|
||||
// no variable
|
||||
variablelist(res) ::= . {
|
||||
res = array();
|
||||
}
|
||||
|
||||
//
|
||||
// variables
|
||||
//
|
||||
// Smarty variable (optional array)
|
||||
variable(res) ::= DOLLARID(i). {
|
||||
res = $this->compiler->compileVariable('\''.substr(i,1).'\'');
|
||||
$this->compiler->triggerTagNoCache(substr(i,1));
|
||||
res = array('$_smarty_tpl->hasVariable(\''.substr(i,1).'\')','$_smarty_tpl->getValue(\''.substr(i,1).'\')');
|
||||
}
|
||||
variable(res) ::= varindexed(vi). {
|
||||
if (vi['var'] === '\'smarty\'') {
|
||||
$smarty_var = (new \Smarty\Compile\SpecialVariableCompiler())->compile(array(),$this->compiler,vi['smarty_internal_index']);
|
||||
res = $smarty_var;
|
||||
res = array('true', $smarty_var);
|
||||
} else {
|
||||
// used for array reset,next,prev,end,current
|
||||
$this->last_variable = vi['var'];
|
||||
$this->last_index = vi['smarty_internal_index'];
|
||||
res = $this->compiler->compileVariable(vi['var']).vi['smarty_internal_index'];
|
||||
$this->compiler->triggerTagNoCache(vi['var']);
|
||||
res = array('true', '$_smarty_tpl->getValue(' . vi['var'] . ')'.vi['smarty_internal_index']);
|
||||
}
|
||||
}
|
||||
|
||||
// variable with property
|
||||
variable(res) ::= varvar(v) AT ID(p). {
|
||||
res = '$_smarty_tpl->getVariable('. v .')->'.p;
|
||||
res = array('true', '$_smarty_tpl->getVariable('. v .')->'.p);
|
||||
}
|
||||
|
||||
// object
|
||||
variable(res) ::= object(o). {
|
||||
res = o;
|
||||
res = array('true', o);
|
||||
}
|
||||
|
||||
// config variable
|
||||
variable(res) ::= HATCH ID(i) HATCH. {
|
||||
configvariable(res) ::= HATCH ID(i) HATCH. {
|
||||
res = $this->compiler->compileConfigVariable('\'' . i . '\'');
|
||||
}
|
||||
|
||||
variable(res) ::= HATCH ID(i) HATCH arrayindex(a). {
|
||||
configvariable(res) ::= HATCH ID(i) HATCH arrayindex(a). {
|
||||
res = '(is_array($tmp = ' . $this->compiler->compileConfigVariable('\'' . i . '\'') . ') ? $tmp'.a.' :null)';
|
||||
}
|
||||
|
||||
variable(res) ::= HATCH variable(v) HATCH. {
|
||||
configvariable(res) ::= HATCH variablevalue(v) HATCH. {
|
||||
res = $this->compiler->compileConfigVariable(v);
|
||||
}
|
||||
|
||||
variable(res) ::= HATCH variable(v) HATCH arrayindex(a). {
|
||||
configvariable(res) ::= HATCH variablevalue(v) HATCH arrayindex(a). {
|
||||
res = '(is_array($tmp = ' . $this->compiler->compileConfigVariable(v) . ') ? $tmp'.a.' : null)';
|
||||
}
|
||||
|
||||
variablevalue(res) ::= variable(v). {
|
||||
res = v[1];
|
||||
}
|
||||
|
||||
variablevalue(res) ::= configvariable(v). {
|
||||
res = v;
|
||||
}
|
||||
|
||||
varindexed(res) ::= DOLLARID(i) arrayindex(a). {
|
||||
res = array('var'=>'\''.substr(i,1).'\'', 'smarty_internal_index'=>a);
|
||||
}
|
||||
@ -918,14 +955,17 @@ arrayindex ::= . {
|
||||
// single index definition
|
||||
// Smarty2 style index
|
||||
indexdef(res) ::= DOT DOLLARID(i). {
|
||||
res = '['.$this->compiler->compileVariable('\''.substr(i,1).'\'').']';
|
||||
$this->compiler->triggerTagNoCache(substr(i,1));
|
||||
res = '[$_smarty_tpl->getValue(\''.substr(i,1).'\')]';
|
||||
}
|
||||
indexdef(res) ::= DOT varvar(v). {
|
||||
res = '['.$this->compiler->compileVariable(v).']';
|
||||
$this->compiler->triggerTagNoCache(v);
|
||||
res = '[$_smarty_tpl->getValue(' . v . ')]';
|
||||
}
|
||||
|
||||
indexdef(res) ::= DOT varvar(v) AT ID(p). {
|
||||
res = '['.$this->compiler->compileVariable(v).'->'.p.']';
|
||||
$this->compiler->triggerTagNoCache(v);
|
||||
res = '[$_smarty_tpl->getValue(' . v . ')->'.p.']';
|
||||
}
|
||||
|
||||
indexdef(res) ::= DOT ID(i). {
|
||||
@ -956,9 +996,10 @@ indexdef(res) ::= OPENB INTEGER(n) CLOSEB. {
|
||||
res = '['.n.']';
|
||||
}
|
||||
indexdef(res) ::= OPENB DOLLARID(i) CLOSEB. {
|
||||
res = '['.$this->compiler->compileVariable('\''.substr(i,1).'\'').']';
|
||||
$this->compiler->triggerTagNoCache(substr(i,1));
|
||||
res = '[$_smarty_tpl->getValue(\''.substr(i,1).'\')]';
|
||||
}
|
||||
indexdef(res) ::= OPENB variable(v) CLOSEB. {
|
||||
indexdef(res) ::= OPENB variablevalue(v) CLOSEB. {
|
||||
res = '['.v.']';
|
||||
}
|
||||
indexdef(res) ::= OPENB value(v) CLOSEB. {
|
||||
@ -1000,7 +1041,8 @@ varvarele(res) ::= ID(s). {
|
||||
}
|
||||
varvarele(res) ::= SIMPELOUTPUT(i). {
|
||||
$var = trim(substr(i, $this->compiler->getLdelLength(), -$this->compiler->getRdelLength()), ' $');
|
||||
res = $this->compiler->compileVariable('\''.$var.'\'');
|
||||
$this->compiler->triggerTagNoCache($var);
|
||||
res = '$_smarty_tpl->getValue(\''.$var.'\')';
|
||||
}
|
||||
|
||||
// variable sections of element
|
||||
@ -1015,7 +1057,8 @@ object(res) ::= varindexed(vi) objectchain(oc). {
|
||||
if (vi['var'] === '\'smarty\'') {
|
||||
res = (new \Smarty\Compile\SpecialVariableCompiler())->compile(array(),$this->compiler,vi['smarty_internal_index']).oc;
|
||||
} else {
|
||||
res = $this->compiler->compileVariable(vi['var']).vi['smarty_internal_index'].oc;
|
||||
$this->compiler->triggerTagNoCache(vi['var']);
|
||||
res = '$_smarty_tpl->getValue(' . vi['var'] . ')'.vi['smarty_internal_index'].oc;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1041,7 +1084,8 @@ objectelement(res)::= PTR varvar(v) arrayindex(a). {
|
||||
if ($this->security) {
|
||||
$this->compiler->trigger_template_error (self::ERR2);
|
||||
}
|
||||
res = '->{'.$this->compiler->compileVariable(v).a.'}';
|
||||
$this->compiler->triggerTagNoCache(v);
|
||||
res = '->{$_smarty_tpl->getValue(' . v . ')'.a.'}';
|
||||
}
|
||||
|
||||
objectelement(res)::= PTR LDEL expr(e) RDEL arrayindex(a). {
|
||||
@ -1067,8 +1111,41 @@ objectelement(res)::= PTR method(f). {
|
||||
//
|
||||
// function
|
||||
//
|
||||
function(res) ::= ns1(f) OPENP params(p) CLOSEP. {
|
||||
res = $this->compiler->compileModifierInExpression(f, p);
|
||||
function(res) ::= ns1(f) OPENP variablelist(v) CLOSEP. {
|
||||
|
||||
if (f == 'isset') {
|
||||
res = '(true';
|
||||
if (count(v) == 0) {
|
||||
throw new CompilerException("Invalid number of arguments for isset. isset expects at least one parameter.");
|
||||
}
|
||||
foreach (v as $value) {
|
||||
if (is_array($value)) {
|
||||
res .= ' && (' . $value[0] . ' && null !== (' . $value[1] . ' ?? null))';
|
||||
} else {
|
||||
res .= ' && (' . $value . ' !== null)';
|
||||
}
|
||||
}
|
||||
res .= ')';
|
||||
} elseif (f == 'empty') {
|
||||
if (count(v) != 1) {
|
||||
throw new CompilerException("Invalid number of arguments for empty. empty expects at exactly one parameter.");
|
||||
}
|
||||
if (is_array(v[0])) {
|
||||
res .= '( !' . v[0][0] . ' || empty(' . v[0][1] . '))';
|
||||
} else {
|
||||
res = 'false == ' . v[0];
|
||||
}
|
||||
} else {
|
||||
$p = array();
|
||||
foreach (v as $value) {
|
||||
if (is_array($value)) {
|
||||
$p[] = $value[1];
|
||||
} else {
|
||||
$p[] = $value;
|
||||
}
|
||||
}
|
||||
res = $this->compiler->compileModifierInExpression(f, $p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1087,7 +1164,8 @@ method(res) ::= DOLLARID(f) OPENP params(p) CLOSEP. {
|
||||
$this->compiler->trigger_template_error (self::ERR2);
|
||||
}
|
||||
$prefixVar = $this->compiler->getNewPrefixVariable();
|
||||
$this->compiler->appendPrefixCode("<?php {$prefixVar} = ".$this->compiler->compileVariable('\''.substr(f,1).'\'').';?>');
|
||||
$this->compiler->triggerTagNoCache(substr(f,1));
|
||||
$this->compiler->appendPrefixCode("<?php {$prefixVar} = \$_smarty_tpl->getValue('".substr(f,1).'\')'.';?>');
|
||||
res = $prefixVar .'('. implode(',',p) .')';
|
||||
}
|
||||
|
||||
@ -1282,7 +1360,7 @@ doublequoted(res) ::= doublequotedcontent(o). {
|
||||
res = new Dq($this, o);
|
||||
}
|
||||
|
||||
doublequotedcontent(res) ::= BACKTICK variable(v) BACKTICK. {
|
||||
doublequotedcontent(res) ::= BACKTICK variablevalue(v) BACKTICK. {
|
||||
res = new Code('(string)'.v);
|
||||
}
|
||||
|
||||
@ -1294,7 +1372,7 @@ doublequotedcontent(res) ::= DOLLARID(i). {
|
||||
res = new Code('(string)$_smarty_tpl->getValue(\''. substr(i,1) .'\')');
|
||||
}
|
||||
|
||||
doublequotedcontent(res) ::= LDEL variable(v) RDEL. {
|
||||
doublequotedcontent(res) ::= LDEL variablevalue(v) RDEL. {
|
||||
res = new Code('(string)'.v);
|
||||
}
|
||||
|
||||
|
@ -65,15 +65,34 @@ class UndefinedTemplateVarTest extends PHPUnit_Smarty
|
||||
*/
|
||||
public function testError()
|
||||
{
|
||||
$this->smarty->error_unassigned = true;
|
||||
$this->smarty->error_unassigned = true;
|
||||
$this->expectException(PHPUnit\Framework\Error\Error::class);
|
||||
$this->expectExceptionMessage('Undefined ');
|
||||
$this->expectExceptionMessage('Undefined ');
|
||||
$e1 = error_reporting();
|
||||
$this->assertEquals('undefined = ', $this->smarty->fetch('001_main.tpl'));
|
||||
$e2 = error_reporting();
|
||||
$this->assertEquals($e1, $e2);
|
||||
}
|
||||
|
||||
public function testNoError()
|
||||
{
|
||||
$this->smarty->error_unassigned = false;
|
||||
$e1 = error_reporting();
|
||||
$this->assertEquals('undefined = ', $this->smarty->fetch('001_main.tpl'));
|
||||
$e2 = error_reporting();
|
||||
$this->assertEquals($e1, $e2);
|
||||
}
|
||||
|
||||
public function testNoErrorForIssetOrEmpty()
|
||||
{
|
||||
$this->smarty->error_unassigned = true;
|
||||
$e1 = error_reporting();
|
||||
$this->assertEquals('undefined = ', $this->smarty->fetch('001_isset.tpl'));
|
||||
$this->assertEquals('undefined = ', $this->smarty->fetch('001_empty.tpl'));
|
||||
$e2 = error_reporting();
|
||||
$this->assertEquals($e1, $e2);
|
||||
}
|
||||
|
||||
public function testUndefinedSimpleVar() {
|
||||
$this->smarty->muteUndefinedOrNullWarnings();
|
||||
$tpl = $this->smarty->createTemplate('string:a{if $undef}def{/if}b');
|
||||
@ -133,30 +152,30 @@ class UndefinedTemplateVarTest extends PHPUnit_Smarty
|
||||
}
|
||||
|
||||
|
||||
public function testDereferenceOnNull() {
|
||||
$this->smarty->setErrorReporting(E_ALL & ~E_WARNING & ~E_NOTICE);
|
||||
$this->smarty->muteUndefinedOrNullWarnings();
|
||||
$tpl = $this->smarty->createTemplate('string:a{if $object->myprop}def{/if}b');
|
||||
$this->smarty->assign('object', null);
|
||||
$this->assertEquals("ab", $this->smarty->fetch($tpl));
|
||||
}
|
||||
public function testDereferenceOnNull() {
|
||||
$this->smarty->setErrorReporting(E_ALL & ~E_WARNING & ~E_NOTICE);
|
||||
$this->smarty->muteUndefinedOrNullWarnings();
|
||||
$tpl = $this->smarty->createTemplate('string:a{if $object->myprop}def{/if}b');
|
||||
$this->smarty->assign('object', null);
|
||||
$this->assertEquals("ab", $this->smarty->fetch($tpl));
|
||||
}
|
||||
|
||||
|
||||
public function testDereferenceOnBool() {
|
||||
$this->smarty->setErrorReporting(E_ALL & ~E_NOTICE);
|
||||
$this->smarty->muteUndefinedOrNullWarnings();
|
||||
$tpl = $this->smarty->createTemplate('string:a{if $object->myprop}def{/if}b');
|
||||
$this->smarty->assign('object', false);
|
||||
$this->assertEquals("ab", $this->smarty->fetch($tpl));
|
||||
}
|
||||
public function testDereferenceOnBool() {
|
||||
$this->smarty->setErrorReporting(E_ALL & ~E_NOTICE);
|
||||
$this->smarty->muteUndefinedOrNullWarnings();
|
||||
$tpl = $this->smarty->createTemplate('string:a{if $object->myprop}def{/if}b');
|
||||
$this->smarty->assign('object', false);
|
||||
$this->assertEquals("ab", $this->smarty->fetch($tpl));
|
||||
}
|
||||
|
||||
|
||||
public function testDereferenceOnString() {
|
||||
$this->smarty->setErrorReporting(E_ALL & ~E_NOTICE);
|
||||
$this->smarty->muteUndefinedOrNullWarnings();
|
||||
$tpl = $this->smarty->createTemplate('string:a{if $object->myprop}def{/if}b');
|
||||
$this->smarty->assign('object', 'xyz');
|
||||
$this->assertEquals("ab", $this->smarty->fetch($tpl));
|
||||
}
|
||||
public function testDereferenceOnString() {
|
||||
$this->smarty->setErrorReporting(E_ALL & ~E_NOTICE);
|
||||
$this->smarty->muteUndefinedOrNullWarnings();
|
||||
$tpl = $this->smarty->createTemplate('string:a{if $object->myprop}def{/if}b');
|
||||
$this->smarty->assign('object', 'xyz');
|
||||
$this->assertEquals("ab", $this->smarty->fetch($tpl));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
undefined = {if empty($foo)}{/if}
|
@ -0,0 +1 @@
|
||||
undefined = {if isset($foo)}{/if}
|
@ -41,10 +41,9 @@ class CompileIfTest extends PHPUnit_Smarty
|
||||
$name = empty($testName) ? $testNumber : $testName;
|
||||
$file = "testIf_{$name}.tpl";
|
||||
$this->makeTemplateFile($file, $code);
|
||||
$this->smarty->assignGlobal('file', $file);
|
||||
$this->smarty->assign('file', $file);
|
||||
$this->smarty->assign('bar', 'buh');
|
||||
$this->assertEquals($result, $this->smarty->fetch($file),
|
||||
"testIf - {$code} - {$name}");
|
||||
$this->assertEquals($result, $this->smarty->fetch($file), "testIf - {$code} - {$name}");
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user