Smarty Forum Index Smarty
The discussions here are for Smarty, a template engine for the PHP programming language.
ADVANCED: Recursion with Smarty
Goto page 1, 2, 3 ... 9, 10, 11  Next
 
Post new topic   Reply to topic    Smarty Forum Index -> Tips and Tricks
View previous topic :: View next topic  
Author Message
marvin
Smarty Rookie


Joined: 12 May 2003
Posts: 5

PostPosted: Mon May 12, 2003 4:27 pm    Post subject: ADVANCED: Recursion with Smarty Reply with quote

Does anyone know if there is a way to handle recursion gracefully with smarty?
What I'm trying to do is somethin that looks a bit like XSLT:

Code:

{template name="section" param1="node"}
    Normal: {$node.name}
{/template}

{template name="section" param1="node"}
   Section: {$node.name}
   {section name="iter" loop=$node.subnodes}
        {if $node.subnodes[iter].type == "section"}
              {apply-template name="section" param1="$node.subnodes[iter]"}
        {else}
              {apply-template name="normal" param1="$node.subnodes[iter]"}
        {/if}
   {/section}
{/template}

{apply-template name="section" param1="$tree"}
Back to top
View user's profile Send private message
boots
Administrator


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

PostPosted: Mon May 12, 2003 4:34 pm    Post subject: Reply with quote

Its doable but very slow (include overhead) and not graceful (you need to keep track of depth, etc.).

Basically, you do an include to yourself and you pass subitems as the data items -- something along the lines of:

Code:
{math equation="x+1" x=$level assign=level}
{foreach from=$data.items key=k item=i}
    {include file="menu_items" data=$i level=$level}
{/foreach}


There is an alternative that you can use to unroll recursive patterns, if you are willing to use the CVS version of Smarty: http://www.phpinsider.com/smarty-forum/viewtopic.php?t=119&highlight=recursion
Back to top
View user's profile Send private message
marvin
Smarty Rookie


Joined: 12 May 2003
Posts: 5

PostPosted: Tue May 13, 2003 11:51 am    Post subject: Reply with quote

Thanks for the pointer!
Does there exist documentation or an example for this repeatable block feature somewhere?
Back to top
View user's profile Send private message
messju
Administrator


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

PostPosted: Tue May 13, 2003 12:09 pm    Post subject: Reply with quote

documentation does not exist, yet.

see the thread at
http://marc.theaimsgroup.com/?l=smarty-dev&m=105084930710497&w=2
for a short introduction.

another foreach-like example is here
http://phpinsider.com/smarty-forum/viewtopic.php?p=1564#1564

HTH
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Transistor
Smarty Rookie


Joined: 20 May 2003
Posts: 9

PostPosted: Tue May 20, 2003 5:25 pm    Post subject: Recursion for HTML List Reply with quote

Hi,

I have a similar problem with recursions or better with the absence of recursions in smarty.

I want to display a tree structure with html <ul> and <li> tags.

PHP Code:

Code:
$objSmarty->assign("tree",array("element"=>array(array("name"    => "test1",
                                                       "element" => array(array("name"  => "test1.1"),
                                                                          array("name"  => "test1.2",
                                                                                "element" => array(array("name"  => "test1.2.1"),
                                                                                                   array("name"  => "test1.2.2"))))))));
echo $objSmarty->fetch("test.tpl");


test.tpl

Code:
<html>
<body>
<ul>
{foreach from=$tree.element item=element}
   <li>{$element.name}</li>
   {if $element.element}
   <ul>{include file="test-recursion.tpl" element=$element.element}</ul>
   {/if}
{/foreach}
</ul>
</body>
</html>


test-recursion.tpl

Code:
{foreach from=$element item=element}
   <li>{$element.name}</li>
   {if $element.element}
   <ul>{include file="test-recursion.tpl" element=$element.element}</ul>
   {/if}
{/foreach}



html output

Code:
<html>
<body>
<ul>
   <li>test1</li>
   <ul>   <li>test1.1</li>
   <ul></ul>
   <li>test1.2</li>
   <ul>   <li>test1.2.1</li>
   <ul></ul>
   <li>test1.2.2</li>
   <ul></ul>
</ul>
</ul>
</ul>
</body>
</html>


This code works but is not very fast. I use it for a bulletin board (http://www.torsten-rentsch.de/pxm.html) where 1000 messages/ thread are not rare. What can i do to improve the recursion speed?

What i really need is something like marvin mentinoned or something like this:

Code:
{block name="testrecursion" var=element}
<li>{$element.name}</li>
   {if $element.element}
   <ul>{callblock name="testrecursion" var=$element.element}</ul>
   {/if}
{/block}


Maybe smarty can compile the block to a php function in the compiled template file.

I think the lack of true recursion is a big problem not only for me and i don't think that the recursion should be done in php because its pure display information what i use in the template.
I switched from XSLT to Smarty with this version of the board (switch is not the correct word because it supports xslt and/or smarty now and i want to keep the flexibility) and the functional range of xslt and smarty is almost the same for me ... almost except the recursion problem which is covered in xslt with apply templates.

Thanks for the great template engine,

Transistor
Back to top
View user's profile Send private message
messju
Administrator


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

PostPosted: Wed May 21, 2003 8:15 am    Post subject: Reply with quote

transistor: this sounds challenging. i like challenges Smile

i don't know if this is overall good, as a little test i did 2 compiler-functions.

the pity of compiler-functions is, you cannot write reasonable ones without relying heavily on some of smarty's internals. this can send you easily to upgrade/maintenaince-hell Sad. anyway these should work with 2.4.2 and after for now.

define a function with {defun name="...."}...{/defun}
call a function with {fun name="..." param1=... param2=...}
(the defined function is called implicitely once after definition)

(edit: this should be in compiler.defun.php in your plugins_dir-path of course)

[php:1:adfdbda69b]<?php
function smarty_compiler_defun($tag_args, &$smarty) {
$_attrs = $smarty->_parse_attrs($tag_args);
$smarty->_tag_stack[] = array('defun', $_attrs, $tag_args);
if (!isset($_attrs['name'])) $smary->syntax_error("defun: missing name parameter");

$_func_name = $smarty->_dequote($_attrs['name']);
$_func = 'smarty_fun_'.$_func_name;
return "if (!function_exists('$_func')) { function $_func(&\$this, \$params) { \$_fun_tpl_vars = \$this->_tpl_vars; \$this->assign(\$params); ";

}


function smarty_compiler_defun_close($tag_args, &$smarty) {
list($_name, $_attrs, $_open_tag_args) = array_pop($smarty->_tag_stack);
if ($_name!='defun') $smarty->_syntax_error("unexpected {/defun}");
return " \$this->_tpl_vars = \$_fun_tpl_vars; }} ".smarty_compiler_fun($_open_tag_args, $smarty);
}


function smarty_compiler_fun($tag_args, &$smarty) {
$_attrs = $smarty->_parse_attrs($tag_args);

if (!isset($_attrs['name'])) $smarty->_syntax_error("fun: missing name parameter");
$_func_name = $smarty->_dequote($_attrs['name']);
$_func = 'smarty_fun_'.$_func_name;
$_params = 'array(';
$_sep = '';
unset($_attrs['name']);
foreach ($_attrs as $_key=>$_value) {
$_params .= "$_sep'$_key'=>$_value";
$_sep = ',';
}
$_params .= ')';
return "$_func(\$this, $_params); ";

}


$this->register_compiler_function('/defun', 'smarty_compiler_defun_close');
$this->register_compiler_function('fun', 'smarty_compiler_fun');

?>[/php:1:adfdbda69b]

your example would read then:
Code:
{defun name="testrecursion" list=$tree}
{foreach from=$list item=element}
<li>{$element.name}
   {if $element.element}
   <ul>{fun name="testrecursion" list=$element.element}</ul>
   {/if}
</li>
{/foreach}
{/defun}


i had to put one array(...) around your $tree, but then it worked Smile


Last edited by messju on Tue Aug 24, 2004 7:51 pm; edited 2 times in total
Back to top
View user's profile Send private message Send e-mail Visit poster's website
boots
Administrator


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

PostPosted: Wed May 21, 2003 6:07 pm    Post subject: Reply with quote

@messju: I like it -- especially with the compiler "block" function trick. I'm going to replace my current non-compiler code with this to see how it goes.
Back to top
View user's profile Send private message
messju
Administrator


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

PostPosted: Wed May 21, 2003 6:28 pm    Post subject: Reply with quote

@boots: i knew you'll like it. it's just a proof of concept now.

if i had the time i would maintain all the weird test-plugins i do but for now it's just a case study.

of course i like any feedback how it performs in speed and stability.
Back to top
View user's profile Send private message Send e-mail Visit poster's website
boots
Administrator


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

PostPosted: Wed May 21, 2003 7:35 pm    Post subject: Reply with quote

@messju: Smile I'll give you feedback in the next couple of days...

What do you think of a shared sourceforge (or similar) project where experimental plugins and hacks can be shared?
Back to top
View user's profile Send private message
Transistor
Smarty Rookie


Joined: 20 May 2003
Posts: 9

PostPosted: Wed May 21, 2003 7:37 pm    Post subject: Thanks Reply with quote

@messju

Thanks for the plugin. I'll test it on weekend.

Quote:
i don't know if this is overall good, as a little test i did 2 compiler-functions.


I tried to write this plugin too, but i stumbled over the missing compiler-block function in smarty.

Is there any chance that this plugin will be added to the smarty package?
I think it provides some useful advantages:

- true recursion for smarty
- alternative to put some template snippets into one single template file and use them wherever you need them (include your (single) standard snippets template only once and use them over and over again)
- put together what belongs together (in my case test template and the according recursion) -> less template fragmentation
- faster (no include overhead)
- close to xslt standard ...at least for me it is important and i think xslt expirienced developers will like it to :)

Maybe the tags can be named similar to the xslt tags?

{template name="xxxx"}
{/template}

{call-template name="xxxx"}

This is how xslt handles "call template" calls:

<xsl:template name="xxxx">
hello
<xsl:call-template name="xxxx"/>
</xsl:template>

<xsl:call-template name="xxxx"/>

Some questions about the plugin:
- are the "global" template variables (everything that is not contained in the passed variable "elements") available in the function too? ( i don't need it for my problem but for a general solution it would be good)
- can i use the plugin this way:

{fun name="testrecursion" list=$element}

{defun name="testrecursion" list=$element}
<li>{$element.name}</li>
{if $element.element}
<ul>
{foreach from=$element.element item=element}
{fun name="testrecursion" list=$element}</ul>
{/foreach}
{/if}
{/defun}

Quote:
(the defined function is called implicitely ones after definition)


i think an explicit call would be better. So you can define this function (or include it from another template?) but you don't have to use it if you don't need it in a special case.

Thanks again for this code.
I hope it will be released in the next smarty version after a little finetuning. :-)

Transistor
Back to top
View user's profile Send private message
messju
Administrator


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

PostPosted: Wed May 21, 2003 9:40 pm    Post subject: Reply with quote

boots wrote:
What do you think of a shared sourceforge (or similar) project where experimental plugins and hacks can be shared?


hmm, we have the forum, the wiki, the contrib-section on the website and some guys putting effort in smarty.sf.net, AFAIR. i don't know which is the best way to go, but i'd love to see if this could be organized under one hood, or cross-linked at least, so people don't miss contributed plugins when they search at a central point.
Back to top
View user's profile Send private message Send e-mail Visit poster's website
messju
Administrator


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

PostPosted: Wed May 21, 2003 9:55 pm    Post subject: Re: Thanks Reply with quote

Transistor wrote:
@messju

Thanks for the plugin. I'll test it on weekend.

Quote:
i don't know if this is overall good, as a little test i did 2 compiler-functions.


I tried to write this plugin too, but i stumbled over the missing compiler-block function in smarty.

Is there any chance that this plugin will be added to the smarty package?


i don't know, the philosophy behind these recursive/functional blocks is far different to the mostly imperative smarty.

Quote:

...

Maybe the tags can be named similar to the xslt tags?

{template name="xxxx"}
{/template}

{call-template name="xxxx"}

This is how xslt handles "call template" calls:

<xsl:template name="xxxx">
hello
<xsl:call-template name="xxxx"/>
</xsl:template>

<xsl:call-template name="xxxx"/>


yes, there are definately better naming schemes than my one. my "defun" is borrowed from scheme, overall the names where just meant as *fun* Smile

Quote:

Some questions about the plugin:
- are the "global" template variables (everything that is not contained in the passed variable "elements") available in the function too? ( i don't need it for my problem but for a general solution it would be good)


the defun-blocks variable-scope follows mostly what you expect by {include}:
- all template-variables are available
- new variables can be supplied as parameters
- all changes to template-variables are gone when the defun-block is done/left.


Quote:

- can i use the plugin this way:

{fun name="testrecursion" list=$element}

{defun name="testrecursion" list=$element}
<li>{$element.name}</li>
{if $element.element}
<ul>
{foreach from=$element.element item=element}
{fun name="testrecursion" list=$element}</ul>
{/foreach}
{/if}
{/defun}


{fun} would not be autoloaded, but if you register it explicitely, the above should work.

Quote:

Quote:
(the defined function is called implicitely ones after definition)


i think an explicit call would be better. So you can define this function (or include it from another template?) but you don't have to use it if you don't need it in a special case.

yep. i did this, to make the defun more look like a smarty-block than a function. just the call to smarty_compiler_fun has to be removed in the closing tag to omit this.

Quote:

Thanks again for this code.
I hope it will be released in the next smarty version after a little finetuning. Smile

Transistor

as i said above: this goes far away from smarty's original scope. i don't know if the need for such a thing is in relation to the effort that has to be done in maintaining it forever once it is bundled and released. i'd prefer such hacks to stay third party, a repository for experimental/extreme-smarty-stuff would be nice, though. Wink
Back to top
View user's profile Send private message Send e-mail Visit poster's website
boots
Administrator


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

PostPosted: Wed May 21, 2003 11:04 pm    Post subject: Reply with quote

I tend to agree--I'm very happy that Smarty can be MADE to do these things, but it would be very difficult to support this type of feature. Besides, while I don't mind some declarative syntax, the inching towards an XSLT look-and-feel makes me lose my lunch. It really does.

Further, recursion can be accomplished in many ways, though this compiler method is a particularly sexy one.

On-the-other-hand, I wouldn't be surprised to see a few framework projects started that were built around ideas similar and complementary to this. As a matter-of-fact, a little birdy I know is working on just such a project Smile
Back to top
View user's profile Send private message
Transistor
Smarty Rookie


Joined: 20 May 2003
Posts: 9

PostPosted: Thu May 22, 2003 5:55 pm    Post subject: Reply with quote

@messju

Quote:
as i said above: this goes far away from smarty's original scope.


Ok, I just saw the possibilities (first of all the imo only clever way to handle a recursion with smarty). But I understand that this is a different approach.

Quote:
i don't know if the need for such a thing is in relation to the effort that has to be done in maintaining it forever once it is bundled and released. i'd prefer such hacks to stay third party, a repository for experimental/extreme-smarty-stuff would be nice, though.


Yes, that could be a solution. Maybe smarty can throw better error messages later? Something like:
"Tag xyz not recognized. Search the smarty plugin database (smarty.php.net/pluginfinder.php?plugin=xyz)"


@boots
Quote:
I tend to agree--I'm very happy that Smarty can be MADE to do these things, but it would be very difficult to support this type of feature.


Why? There are only 30 lines of code necessary and the plugin works already. But I don't want to convince you of this approach. I just thougt it could be helpful for other smarty users too. ...ok,ok,ok, it would make my life easier a little bit if users of my board can just install smarty and it works (including the plugin) out of the box Wink

Quote:
Besides, while I don't mind some declarative syntax, the inching towards an XSLT look-and-feel makes me lose my lunch. It really does.

Only because of this plugin? Maybe other people need more xslt - like features but I'm happy with this plugin.

Quote:
Further, recursion can be accomplished in many ways, though this compiler method is a particularly sexy one.

But how? Smarty inlcude? Yes but this can not be used for real recursions without a depth limit. Hundreds of php includes slow down every server.
Maybe you can prepare the recursion array for smarty in the php script but this is just a workaround for a missing smarty feature.
Back to top
View user's profile Send private message
boots
Administrator


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

PostPosted: Thu May 22, 2003 7:47 pm    Post subject: Reply with quote

@Transistor: not to get me wrong -- I love this work. Its in my test stable right now Smile My main point was that I prefer Smarty being the enabler of different implementation strategies instead of the specifier of those same strategies. That is part of why I balk at XSLT -- recursion is good, but not because XSLT uses it and certainly NOT good for everything Wink
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Smarty Forum Index -> Tips and Tricks All times are GMT
Goto page 1, 2, 3 ... 9, 10, 11  Next
Page 1 of 11

 
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