Smarty Forum Index Smarty
WARNING: All discussion is moving to https://reddit.com/r/smarty, please go there! This forum will be closing soon.

Error when using {foreach ... name=$foo}

 
This forum is locked: you cannot post, reply to, or edit topics.   This topic is locked: you cannot edit posts or make replies.    Smarty Forum Index -> Bugs
View previous topic :: View next topic  
Author Message
c960657
Smarty Regular


Joined: 07 May 2003
Posts: 75
Location: Copenhagen, Denmark

PostPosted: Tue Jul 06, 2004 11:54 am    Post subject: Error when using {foreach ... name=$foo} Reply with quote

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
View user's profile Send private message Visit poster's website
mohrt
Administrator


Joined: 16 Apr 2003
Posts: 7368
Location: Lincoln Nebraska, USA

PostPosted: Tue Jul 06, 2004 1:53 pm    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
c960657
Smarty Regular


Joined: 07 May 2003
Posts: 75
Location: Copenhagen, Denmark

PostPosted: Tue Jul 06, 2004 2:04 pm    Post subject: Reply with quote

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 Smile
Back to top
View user's profile Send private message Visit poster's website
c960657
Smarty Regular


Joined: 07 May 2003
Posts: 75
Location: Copenhagen, Denmark

PostPosted: Tue Jul 06, 2004 2:22 pm    Post subject: Reply with quote

_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
View user's profile Send private message Visit poster's website
boots
Administrator


Joined: 16 Apr 2003
Posts: 5611
Location: Toronto, Canada

PostPosted: Tue Jul 06, 2004 2:28 pm    Post subject: Reply with quote

I actually wonder if, given $foo, we should assume the literal 'foo' and just throw a notice.
Back to top
View user's profile Send private message
c960657
Smarty Regular


Joined: 07 May 2003
Posts: 75
Location: Copenhagen, Denmark

PostPosted: Tue Jul 06, 2004 2:44 pm    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
boots
Administrator


Joined: 16 Apr 2003
Posts: 5611
Location: Toronto, Canada

PostPosted: Tue Jul 06, 2004 2:54 pm    Post subject: Reply with quote

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 Wink
Back to top
View user's profile Send private message
messju
Administrator


Joined: 16 Apr 2003
Posts: 3336
Location: Oldenburg, Germany

PostPosted: Tue Jul 06, 2004 3:54 pm    Post subject: Reply with quote

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
View user's profile Send private message Send e-mail Visit poster's website
mohrt
Administrator


Joined: 16 Apr 2003
Posts: 7368
Location: Lincoln Nebraska, USA

PostPosted: Tue Jul 06, 2004 4:00 pm    Post subject: Reply with quote

I don't like the idea of assuming, I'd rather see an error and let them correct it.
Back to top
View user's profile Send private message Visit poster's website
boots
Administrator


Joined: 16 Apr 2003
Posts: 5611
Location: Toronto, Canada

PostPosted: Tue Jul 06, 2004 4:49 pm    Post subject: Reply with quote

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
View user's profile Send private message
mohrt
Administrator


Joined: 16 Apr 2003
Posts: 7368
Location: Lincoln Nebraska, USA

PostPosted: Tue Jul 06, 2004 5:07 pm    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
boots
Administrator


Joined: 16 Apr 2003
Posts: 5611
Location: Toronto, Canada

PostPosted: Tue Jul 06, 2004 5:22 pm    Post subject: Reply with quote

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
View user's profile Send private message
mohrt
Administrator


Joined: 16 Apr 2003
Posts: 7368
Location: Lincoln Nebraska, USA

PostPosted: Tue Jul 06, 2004 6:29 pm    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
Display posts from previous:   
This forum is locked: you cannot post, reply to, or edit topics.   This topic is locked: you cannot edit posts or make replies.    Smarty Forum Index -> Bugs All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group
Protected by Anti-Spam ACP