Smarty templates are a very useful tool and I'm addicted to Smarty for a couple of years now. All projects I did use Smarty templates. Now it's 2009 and PHP 5.2 is stable and has a good performance. Therefore I decided to use any of PHP 5's features when they come along my way.
Recently, Iterators came to close and I had to implement one. It's usefull for proxying and also for dynamically presenting views of lists. Therefore my implementation looks like:
class Foo { var $childs; function __construct(){ $this->childs = new Bar(); } } class Bar implements Iterator { // ...iterator code... }
Back to Smarty: I passed the Foo instance to my template...
$foo = new Foo(); $tpl->assign( 'Foo', $foo );
{foreach from=$Foo->childs item=FooChild} {$FooChild} {/foreach}
As Smarty is optimized for PHP 4 and Iterators are PHP 5, one should expect this doesn't work. I had to debug a lot to find out the reason why, but I'm to curious to just accept it without knowing details. So a thorough look into the compiled smarty template file uncovered PHP code like that:
$From = (array)$Foo->childs; // cast the foreach source to array foreach( $From ... ){ //... }
Well as an iterator actually shouldn't be so much different from arrays, maybe it is PHP's responsibility to cast Iterator gently to an array, but it doesn't. The only reason I can think of for Smarty to work that way is to protect template designers from foreach warnings. On the other hand it is pretty much useless to cast anything to array. For example, casting an object to array results in an array of properties. No template designer would expect that. Actually Smarty shouldn't touch that value in such a way! Instead they should just test the variable and accept nothing but an array. The simple if block would do it:
if( is_array($Foo->childs) ){ $From = $Foo->childs; foreach( $From ... ){ // ... } }
With the knowledge of this Smarty flaw, the PHP solution is even more simple. Convert the iterator before passing it to Smarty. PHP 5 provides a brand new function for converting an iterator to an array called (guess what) iterator_to_array()!
$tpl->assign('Childs', iterator_to_array($foo->Childs) );
Post new comment