View previous topic :: View next topic |
Author |
Message |
c960657 Smarty Regular
Joined: 07 May 2003 Posts: 75 Location: Copenhagen, Denmark
|
Posted: Tue Jul 06, 2004 11:54 am Post subject: Error when using {foreach ... name=$foo} |
|
|
Usually variables may be used in attribute values. For example the following code will assign the value "abc" to the variable $foo, and then assign the value of $foo to the variable $bar, so that the value of $bar becomes "abc".
Code: | {assign var=foo value="abc"}
{assign var=bar value=$foo} |
However, this is not possible for the item attribute in {foreach}. Consider the following piece of template:
Code: | {assign var=foo value="abc"}
{foreach from=$persons item=$foo}
{$abc|escape}
{/foreach} |
If variables in the item attribute value were expanded like in {assign}, the foreach look would be equivalent to {foreach from=$persons item=abc}, and the elements in the array would be displayed. But it doesn't work. The compiled template looks contains the following:
[php:1:0c55a2211a]foreach ($_from as $this->_tpl_vars['$this->_tpl_vars['foo']']):[/php:1:0c55a2211a]
and that generates a PHP parse error.
I can't think of a case where one would like to use a variable in the item attribute, so perhaps variables should not be allowed there at all (that's how it is today). If they shouldn't, I think a more understandable error should be thrown, when an item attribute contains a variable, instead of the PHP parse error that is thrown today.
On the other hand, for consistency with other attributes one could argue that variables should be allowed in the item attribute.
The following change to Smarty_Compiler::_compile_foreach_start() allows variables to be expanded like other attribute values (assuming this should be allowed):
Code: |
$from = $attrs['from'];
- $item = $this->_dequote($attrs['item']);
+ $item = $attrs['item'];
if (isset($attrs['name']))
...
$output .= "{$foreach_props}['iteration'] = 0;\n";
- $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n";
+ $output .= " foreach (\$_from as $key_part\$this->_tpl_vars[$item]):\n";
$output .= " {$foreach_props}['iteration']++;\n";
...
} else {
$output .= "if (count(\$_from = (array)$from)):\n";
- $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n";
+ $output .= " foreach (\$_from as $key_part\$this->_tpl_vars[$item]):\n";
}
|
If it is decided that variables in the item attribute should be allowed, I have another suggestion: I sometimes by mistake write {foreach from=$foo item=$bar} when I really mean {foreach from=$foo item=bar}. This does not make sense, if $bar is empty or not set. In that case it would be helpful, if Smarty would throw a runtime error. This can be accomplished by the following changes (this diff assumes that the above diff was applied):
Code: | if (isset($name)) {
$output .= "{$foreach_props}['total'] = count(\$_from = (array)$from);\n";
$output .= "{$foreach_props}['show'] = {$foreach_props}['total'] > 0;\n";
+ $output .= "if (!$item) \$this->trigger_error('item: empty variable name');\n";
+ $output .= "if ($item && {$foreach_props}['show']):\n";
$output .= "{$foreach_props}['iteration'] = 0;\n";
- $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n";
$output .= " foreach (\$_from as $key_part\$this->_tpl_vars[$item]):\n";
$output .= " {$foreach_props}['iteration']++;\n";
$output .= " {$foreach_props}['first'] = ({$foreach_props}['iteration'] == 1);\n";
$output .= " {$foreach_props}['last'] = ({$foreach_props}['iteration'] == {$foreach_props}['total']);\n";
} else {
- $output .= "if (count(\$_from = (array)$from)):\n";
+ $output .= "if (!$item) \$this->trigger_error('item: empty variable name');\n";
+ $output .= "if ($item && count(\$_from = (array)$from)):\n";
$output .= " foreach (\$_from as $key_part\$this->_tpl_vars[$item]):\n";
}
$output .= '?>'; |
|
|
Back to top |
|
mohrt Administrator
Joined: 16 Apr 2003 Posts: 7368 Location: Lincoln Nebraska, USA
|
Posted: Tue Jul 06, 2004 1:53 pm Post subject: |
|
|
Did you try the CVS version of Smarty? I think messju already committed a patch to throw a sensible error message when a variable is passed as the item attribute to {foreach} |
|
Back to top |
|
c960657 Smarty Regular
Joined: 07 May 2003 Posts: 75 Location: Copenhagen, Denmark
|
Posted: Tue Jul 06, 2004 2:04 pm Post subject: |
|
|
mohrt wrote: | Did you try the CVS version of Smarty? |
No, I am running 2.6.3.
/me looks at the latest CVS version
Excellent - just what I was looking for |
|
Back to top |
|
c960657 Smarty Regular
Joined: 07 May 2003 Posts: 75 Location: Copenhagen, Denmark
|
Posted: Tue Jul 06, 2004 2:22 pm Post subject: |
|
|
_compile_foreach_start() should probably be changed to return early, when an error is triggered.
In the latest CVS version, the following two errors are thrown, if the item attribute is missing - I think that latter should be omitted:
Quote: |
Error: Smarty error: [in file:/home/dr/www/drk-indsamling/templates/lokalafdeling/enrolments.tpl line 19]: syntax error: foreach: missing 'item' attribute (Smarty_Compiler.class.php, line 1130)
Error: Smarty error: [in file:/home/dr/www/drk-indsamling/templates/lokalafdeling/enrolments.tpl line 19]: syntax error: 'foreach: item' must be a variable name (literal string) (Smarty_Compiler.class.php, line 1134)
|
|
|
Back to top |
|
boots Administrator
Joined: 16 Apr 2003 Posts: 5611 Location: Toronto, Canada
|
Posted: Tue Jul 06, 2004 2:28 pm Post subject: |
|
|
I actually wonder if, given $foo, we should assume the literal 'foo' and just throw a notice. |
|
Back to top |
|
c960657 Smarty Regular
Joined: 07 May 2003 Posts: 75 Location: Copenhagen, Denmark
|
Posted: Tue Jul 06, 2004 2:44 pm Post subject: |
|
|
boots wrote: | I actually wonder if, given $foo, we should assume the literal 'foo' and just throw a notice. |
In {foreach} I think it is rather unlikely that someone would like to use a variable in the item attribute.
But in e.g. {assign} the var attribute is also a variable, but here it would sometimes make sense to supply a variable in the var attribute. For example the following currently displays "abc", not "def" (as it would, if the leading $ was automatically stripped).
Code: | {assign var=foo value=abc}
{assign var=$foo value=def}
{$foo} |
This construct can be used to achieve some effects simlar to PHP's variable variables.
So for consistency with assign, I don't think your suggestion is a good idea.
Also it would cause problems if it is one day decided that variables should be allowed in the item attribute afterall. |
|
Back to top |
|
boots Administrator
Joined: 16 Apr 2003 Posts: 5611 Location: Toronto, Canada
|
Posted: Tue Jul 06, 2004 2:54 pm Post subject: |
|
|
Hi c960657,
I understand the issue--I'm not sure if I made my suggestion clear enough--I was only speaking of foreach, for which messju's patch solely considered.
So, given:
{foreach ... item=$foo}
I am suggesting that since we all agree that $foo makes no sense in this context and that 'foo' was likely meant, instead of throwing an error, why not just assume 'foo' and throw a notice? I don't see why that should involve semantics from other constructs.
In other words, we can be strict and throw an error (stopping processing), or we can be loose and assume the proper behaviour (proceeding with the best guess), but let the user know that is not the right thing to do. If anything, I would say being loose is more inline with PHP's design philospohy and with scripters in-general |
|
Back to top |
|
messju Administrator
Joined: 16 Apr 2003 Posts: 3336 Location: Oldenburg, Germany
|
Posted: Tue Jul 06, 2004 3:54 pm Post subject: |
|
|
boots wrote: | I am suggesting that since we all agree that $foo makes no sense in this context and that 'foo' was likely meant, instead of throwing an error, why not just assume 'foo' and throw a notice? I don't see why that should involve semantics from other constructs. |
i disagree.
{foreach item=abc ...} and {assign var=abc ...} have similar semantics to me, but smarty doesn't reflect that. |
|
Back to top |
|
mohrt Administrator
Joined: 16 Apr 2003 Posts: 7368 Location: Lincoln Nebraska, USA
|
Posted: Tue Jul 06, 2004 4:00 pm Post subject: |
|
|
I don't like the idea of assuming, I'd rather see an error and let them correct it. |
|
Back to top |
|
boots Administrator
Joined: 16 Apr 2003 Posts: 5611 Location: Toronto, Canada
|
Posted: Tue Jul 06, 2004 4:49 pm Post subject: |
|
|
alright, alright--it was just an idea. I should add though that throwing a notice does give the opportunity to correct the error--it just doesn't keep things from working when we know in advance how to proceed. Sort of like not responding to someone when they say "boots" (general noun) instead of "Boots" (proper noun) even though, in context, I know that they mean ME.
Also, as far as messju's comment--I'm not sure I follow. We aren't talking about literal names are we? Indeed, are we not suggesting that the issue is with variable names given in a context where they do not make sense? Using item=$foo implies, almost certainly, that you will not be able to access the assigned item from inside the template because you would need a variable-variable. The same can probably be said about var=$foo in assign, but AFAIK, the only patch made so far was to foreach processing. If the contention is that they should be disallowed in that context as well, then I am all for that. If the idea is that different contexts can not have different rules--I'm against that. However, my only suggestion was that if the compiler can tell that $foo is senseless, it can (in theory) assume that $foo was a TYPO and that in reality, the literal 'foo' was assumed. Apply that reasoning to any context you feel it fits in.
My feeling is that the reason we see this error made at all is that people probably are used to things like foreach($arr as $k=>$v) {}
Anyways, like I said, it was just a suggestion to try to be "nice" but I can certainly see why it shouldn't be persued. |
|
Back to top |
|
mohrt Administrator
Joined: 16 Apr 2003 Posts: 7368 Location: Lincoln Nebraska, USA
|
Posted: Tue Jul 06, 2004 5:07 pm Post subject: |
|
|
I still disagree. Two humans in a discussion can't be compared to text interpreted by a parser. An assumption in a parsed syntax could easily create an ambiguous/confusing condition. Maybe this particular case is fairly safe, but I'd rather keep the template synatax and behavior consistant.
eg. I don't want {foo bar=$blah} to behave one way here and another way there. |
|
Back to top |
|
boots Administrator
Joined: 16 Apr 2003 Posts: 5611 Location: Toronto, Canada
|
Posted: Tue Jul 06, 2004 5:22 pm Post subject: |
|
|
mohrt wrote: | eg. I don't want {foo bar=$blah} to behave one way here and another way there. |
But monte, item=$foo doesn't work at all. |
|
Back to top |
|
mohrt Administrator
Joined: 16 Apr 2003 Posts: 7368 Location: Lincoln Nebraska, USA
|
Posted: Tue Jul 06, 2004 6:29 pm Post subject: |
|
|
I still think it is a good idea to force the required syntax. I'm just taking caution for the future... eg. we let "assumed" syntax slide here and there and end up creating an ambiguous situation that we can't fix. |
|
Back to top |
|
|