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

Adding While loops to Smarty
Goto page 1, 2  Next
 
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 -> Tips and Tricks
View previous topic :: View next topic  
Author Message
Vicky`s Webgeek
Smarty Rookie


Joined: 07 Mar 2007
Posts: 9

PostPosted: Wed Mar 07, 2007 3:43 pm    Post subject: Adding While loops to Smarty Reply with quote

I'm not sure why they've never been added, but while loops can be immensely handy. They let you loop a block while a condition evaluates to true, much like an if statement -- in fact it uses the same code to compile that an if statement uses.

I use them to do things like show the number of pages of content in a blog without needing to create new arrays:
Code:

{assign var=loop value=1}
{assign var=num_pages value=`ceil($content.total_entries_per_page/$content.entry_count)`}
{while $loop <= $num_pages}
{if $loop != $content.current_page}
<a href="index.php?section={$page.name}&page={$loop}">Page {$loop}</a>&nbsp;
{else}
Page {$loop}
{/if}
{assign var=loop value=$loop+1}
{/while}


And they're a piece of cake to add into the code.

four changes in Smarty_Compiler.class.php

the first two in function _compile_tag
search for 'case 'if': (around line 471)
and make the following change:
(using quotes instead of code to allow for bolding of changes)
Quote:

case 'if':
$this->_push_tag('if');
return $this->_compile_if_tag($tag_args);

case 'else':
list($_open_tag) = end($this->_tag_stack);
if ($_open_tag != 'if' && $_open_tag != 'elseif')
$this->_syntax_error('unexpected {else}', E_USER_ERROR, __FILE__, __LINE__);
else
$this->_push_tag('else');
return '<?php else: ?>';

case 'elseif':
list($_open_tag) = end($this->_tag_stack);
if ($_open_tag != 'if' && $_open_tag != 'elseif')
$this->_syntax_error('unexpected {elseif}', E_USER_ERROR, __FILE__, __LINE__);
if ($_open_tag == 'if')
$this->_push_tag('elseif');
return $this->_compile_if_tag($tag_args, true);

case 'while': //adding while loop
$this->_push_tag('while');
return $this->_compile_if_tag($tag_args,false,true);


case '/if':
$this->_pop_tag('if');
return '<?php endif; ?>';

case '/while': //adding while loop
$this->_pop_tag('while');
return '<?php endwhile; ?>';




then the final two in function _compile_if_tag
the first of these is at the function declaration (now around line 1256)
Quote:

/**
* Compile {if ...} or {while ...} tag
*
* @param string $tag_args
* @param boolean $elseif if true, uses elseif instead of if
* @param boolean $while if true, uses while instead of if
* @return string
*/
function _compile_if_tag($tag_args, $elseif = false,$while = false)
{


and then at the end of the function (now around line 1422)
Quote:

if ($elseif)
return '<?php elseif ('.implode(' ', $tokens).'): ?>';
elseif ($while)
return '<?php while ('.implode(' ',$tokens).'): ?>';

else
return '<?php if ('.implode(' ', $tokens).'): ?>';

Back to top
View user's profile Send private message
Hielke Hoeve
Smarty Elite


Joined: 06 Jan 2006
Posts: 406
Location: Netherlands

PostPosted: Wed Mar 07, 2007 5:41 pm    Post subject: Reply with quote

u just implemented {foreach} and {section}...
_________________
Debug XHTML Compliance
SmartyPaginate
Smarty License Questions
---
(About Unix) The learning curve is full of aha! moments, such as that glorious day that the full beauty of grep and, later, find is revealed in all its majesty. --- Robert Uhl <ruhl@4dv.net>
Back to top
View user's profile Send private message
mohrt
Administrator


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

PostPosted: Wed Mar 07, 2007 5:54 pm    Post subject: Reply with quote

Why it hasn't been implemented, because there is no strong need for it. Assigned template content can easily be looped over with {foreach}. A {while} loop is merely an alternate, and implementing this will only encourage looping constructs that aren't necessary for templates.
Back to top
View user's profile Send private message Visit poster's website
Vicky`s Webgeek
Smarty Rookie


Joined: 07 Mar 2007
Posts: 9

PostPosted: Wed Mar 07, 2007 6:05 pm    Post subject: Reply with quote

Hielke Hoeve wrote:
u just implemented {foreach} and {section}...


No.

{foreach} and {section} both require an arrays to iterate through

{while} only needs a condition to be true.

if you look at my example, which is the simplest example of it's use, I'm setting a variable with assign, checking it against a second value, and incrementing the variable at the end of the loop. and creating several links with essentially one number value.

I've used this to create simple calendar displays by having a start date, and end date, and a custom date increment function. then loop through and display each date between the two initial dates. both {foreach} and {section} would require an array of values containing each date value in between.
Back to top
View user's profile Send private message
Vicky`s Webgeek
Smarty Rookie


Joined: 07 Mar 2007
Posts: 9

PostPosted: Wed Mar 07, 2007 6:13 pm    Post subject: Reply with quote

mohrt wrote:
Assigned template content can easily be looped over with {foreach}.


this isn't for looping over assigned content

it's for repeating a section while a certain condition is still valid.

if this was possible with existing tags, then there wouldn't be a need for http://www.phpinsider.com/php/code/SmartyPaginate/

in fact, my example code at the top essentially does exactly what SmartyPaginate was designed to do.


If you don't see the need to include it in the main smarty system, that's fine... those of us who do see it's use can simply add it in afterwards. Wink
Back to top
View user's profile Send private message
boots
Administrator


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

PostPosted: Wed Mar 07, 2007 6:31 pm    Post subject: Reply with quote

Vicky`s Webgeek wrote:
If you don't see the need to include it in the main smarty system, that's fine... those of us who do see it's use can simply add it in afterwards. Wink


Yes indeed Smile I advise you do so with compiler plugins rather than by modifying the compiler directly.
Back to top
View user's profile Send private message
mohrt
Administrator


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

PostPosted: Wed Mar 07, 2007 6:40 pm    Post subject: Reply with quote

Vicky`s Webgeek wrote:

in fact, my example code at the top essentially does exactly what SmartyPaginate was designed to do.


Not even remotely the same. SmartyPaginate requires PHP-side coordination so only the data-segment that will get displayed is assigned to the template. Then SmartyPaginate shows a pagination bar that represents the entire dataset. There is nothing in SmartyPaginate that works like a while loop.

Without SmartyPaginate you could assign the whole dataset and loop over a portion of it (say 1000 items and show the first 20), but that is rediculously wasteful, and what SmartyPaginate was designed to avoid.
Back to top
View user's profile Send private message Visit poster's website
Vicky`s Webgeek
Smarty Rookie


Joined: 07 Mar 2007
Posts: 9

PostPosted: Wed Mar 07, 2007 6:48 pm    Post subject: Reply with quote

boots wrote:
Yes indeed Smile I advise you do so with compiler plugins rather than by modifying the compiler directly.


I remember trying that and finding it nearly impossible to do properly -- at least without cutting and pasting the entire contents of the _compile_if_tag function.

It just seemed much cleaner to inject the least code possible by extending the compiler.

I am, after all, adding access to a core control structure.
Back to top
View user's profile Send private message
boots
Administrator


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

PostPosted: Wed Mar 07, 2007 6:55 pm    Post subject: Reply with quote

Well okay...but it is fraught with problems when we release upgrades to the compiler as you will then have to re-patch your code -- even extended classes. A while loop is doable with plugins and that would be the "correct" way of extending Smarty's language.

I want to emphasize that there is no indication that Smarty ever intended to simply duplicate every control structure in existence. Thinking that way misses the point of Smarty as a simplified language for templates, IMHO.
Back to top
View user's profile Send private message
Vicky`s Webgeek
Smarty Rookie


Joined: 07 Mar 2007
Posts: 9

PostPosted: Wed Mar 07, 2007 7:12 pm    Post subject: Reply with quote

mohrt wrote:
Not even remotely the same. SmartyPaginate requires PHP-side coordination so only the data-segment that will get displayed is assigned to the template. Then SmartyPaginate shows a pagination bar that represents the entire dataset. There is nothing in SmartyPaginate that works like a while loop.


I don't want to get into a semantic pissing match, and I know your code does a lot more than what my little example shows, but I think you should look at my example again. It may not be completely obvious what I'm dong, since you don't have the complete structure.

I pass in an array ($content) that contains the following

$content.entry_count (total entries in the dataset)
$content.total_entries_per_page (number of entries to display at one time)
$content.current_page (the numbered subset I am currently showing)
$content.entries (an array containing the paged subset of entries I will display)
given these three values,
I assign 1 (the first page number) to a variable named loop
Code:
{assign var=loop value=1}

I then calculate the maximum number of pages
Code:
{assign var=num_pages value=`ceil($content.total_entries_per_page/$content.entry_count)`}

and while my loop variable is less than or equal to the total number of pages,
Code:
{while $loop <= $num_pages}

I either build a link to the paged content subset
Code:
{if $loop != $content.current_page}
<a href="index.php?section={$page.name}&page={$loop}">Page {$loop}</a>&nbsp;

or a simple place holder if this is the subset page I am currently
Code:
{else}
Page {$loop}
{/if}

then increment the loop variable up one at the end of the while loop
Code:
{assign var=loop value=$loop+1}
{/while}


all of this is done without the need for a plug in (if you don't count {while} that is Wink ), or extra call to the db or even, as you do in SmartyPaginate, building a numbered array of elements in memory to then reiterate through.

the other elements of your code (displaying which page section you seeing, next a pref buttons, etc.) are all derivable from the entry_count, total_entries per page, and current_page)
Back to top
View user's profile Send private message
Vicky`s Webgeek
Smarty Rookie


Joined: 07 Mar 2007
Posts: 9

PostPosted: Wed Mar 07, 2007 7:22 pm    Post subject: Reply with quote

boots wrote:
Well okay...but it is fraught with problems when we release upgrades to the compiler as you will then have to re-patch your code -- even extended classes. A while loop is doable with plugins and that would be the "correct" way of extending Smarty's language.


agreed, and I did have to do just that when I upgraded a older project's smarty engine.

boots wrote:
I want to emphasize that there is no indication that Smarty ever intended to simply duplicate every control structure in existence. Thinking that way misses the point of Smarty as a simplified language for templates, IMHO.

Also agree. but adding a core language control structure is a bit more than a simple 'add-on'. There is a reason why most languages have both a for and a while loop.

I just found that some of the things I was doing were much more efficient with the while loop. (like the pagination thing: 3 passed values and 2 derived ones - instead of having to build a 1-n numbered array to represent each page link -- or introduce an custom class object to do it for me)
Back to top
View user's profile Send private message
boots
Administrator


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

PostPosted: Wed Mar 07, 2007 7:27 pm    Post subject: Reply with quote

Hi.

I understand why you want it and it obvious you know how and when to best use it. Unfortunately, that is atypical. There is a reason why most languages have gone beyond while loops and implemented more modern structures: while loops are mainly manual and require the coder to coordinate the control structure's exit condition. It is very simple to make a mistake that results in an infinite loop or is adversely impacted by a variable assignment side-effect. It is fine to expect the PHP coders to deal with that intelligently -- I don't think it is necessary to introduce that for the general Smarty templaters.

That aside, one of the reasons Smarty has a plugin system is to make it extendible for uses beyond just what is delivered out-of-the-box. Customize to your heart's content Smile
Back to top
View user's profile Send private message
Vicky`s Webgeek
Smarty Rookie


Joined: 07 Mar 2007
Posts: 9

PostPosted: Wed Mar 07, 2007 7:42 pm    Post subject: Reply with quote

however, there currently is no way to simply loop through a specific number or value range,

even a {loop start=VALUE end=VALUE step=VALUE name=VARIABLE}{/loop} type structure would be invaluable.

I just liked this solution because it was suprisingly simple to implement -- mostly thanks to the original code.
Back to top
View user's profile Send private message
mohrt
Administrator


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

PostPosted: Wed Mar 07, 2007 7:42 pm    Post subject: Reply with quote

Vicky`s Webgeek wrote:

and while my loop variable is less than or equal to the total number of pages,
Code:
{while $loop <= $num_pages}



There is a lot of business logic that belongs in PHP imho Wink

But to the topic at hand, you can do the same thing with:

Code:
{section ... loop=$num_pages}


The loop param will accept either an array or a number. Also, {section} is not subject to infinite looping errors, as boots pointed out.


Last edited by mohrt on Wed Mar 07, 2007 7:50 pm; edited 1 time in total
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: Wed Mar 07, 2007 7:46 pm    Post subject: Reply with quote

Vicky`s Webgeek wrote:
however, there currently is no way to simply loop through a specific number or value range,

even a {loop start=VALUE end=VALUE step=VALUE name=VARIABLE}{/loop} type structure would be invaluable.

I just liked this solution because it was suprisingly simple to implement -- mostly thanks to the original code.


The {section} function will accept step, max, loop, etc.

http://smarty.php.net/manual/en/language.function.section.php
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 -> Tips and Tricks All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
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