Automatic Column Layout in Smarty

The Problem: You have a list of X items of information that you want to lay out in rows. Each row must contain X columns. It's easy to lay-out things in two columns, but when you want to use a large or indeterminate number of columns in your layout you need to write some more flexible smarty code. This is my solution.

Solution for three columns

Line 2: Causes this entire block to be ignored if the source variable is not present.

Lines 5-25: Loop through the input variable.

Line 6: We capture the value which indicates the column number.

Line 26-29: We need to make sure that the table is properly closed otherwise this will cause a bug in the HTML.

<!-- lc_horizontalIcons.html -->
{if $horizontal_icons != null}
{include file="lc/lc_sausage.html" sausage_heading="Activities" sausage_anchor="Activities"}

{foreach from=$horizontal_icons item=datum key=key}
{capture name="column"}{math equation="x % 3" x=$key}{/capture}
{if $smarty.capture.column == "0"}
<table border="0" cellpadding="0" cellspacing="0" class="sectionTable">
	<tr>
		<td width="33%" align="center" valign="middle">
		{include file="lc/lc_linked_img.html}
		</td>
{elseif  $smarty.capture.column == "1"}
		<td width="33%" align="center" valign="middle">
		{include file="lc/lc_linked_img.html}
		</td>
{elseif $smarty.capture.column == "2"}
		<td width="33%" align="center" valign="middle">
		{include file="lc/lc_linked_img.html}
		</td>
	</tr>
</table>
{/if}
{/foreach}

{if $smarty.capture.column != 2}
<!-- Close the table! -->
</tr></table>
{/if}


{/if}
<!-- end lc_centreAbout.html -->

If you want to see an example of this effect in use, take a look at the home page of the new [Leisure Connection] website when it launches in March 2003.

Alternate Solution for X columns where X > 2

Here's another one:

{* columnsExample.tpl                        *}
{* ----------------------------------------- *}
{* Example for using column layout in Smarty *}

{* First we check if there are some entries to display *}
{if count($entries) > 0}
  {* begin of table *}
  <table>

    {* $lastcol will be needed to check if we are outputting the last column *}
    {math assign="lastcol" equation="x-1" x=$columns}

    {* $width is the column width *}
    {math assign="width" equation="100 / x" x=$columns}
  
    {* now loop through all entries *}
    {section name="idx" loop=$entries}
      {* $col is the current column *}
      {math assign="col" equation="x % y" x=$smarty.section.idx.rownum y=$columns}
      
      {if $col == 0}<tr>{/if} {* begin of new row *}

      <td width="{$width}%">
        {* Output cell content here *}
        {$entries[idx]}
      </td>

      {if $col == $lastcol || $smarty.section.idx.index_last == true }</tr>{/if} {* end of row *}
    {/section}
  
  {* close table *}
  </table>
{/if}
  /**
   * columnsExample.php
   *
   * Example for using column layout in Smarty
   */
  $entries = array("a","b","c","d","e","f","g","h","i","j","k","l","m","n");
  $columns = 7;
  
  $smarty = new Smarty();
  $smarty->assign("entries", $entries); // Assign the table entries
  $smarty->assign("columns", $columns); // Assign the number of columns we want to display
  $smarty->display("columnsExample.tpl");

Simple Solution for any number of columns

This is for any number of columns, and its short and painless:

{* Monte Möhrt March 4, 2002 *}
{* $cols is the number of columns you want *}
<TABLE border=1>
    <TR>
    {section name=numloop loop=$data}
        <TD>{$data[numloop]}</TD>
        {* see if we should go to the next row *}
        {if not ($smarty.section.numloop.rownum mod $cols)}
                {if not $smarty.section.numloop.last}
                        </TR><TR>
                {/if}
        {/if}
        {if $smarty.section.numloop.last}
                {* pad the cells not yet created *}
                {math equation = "n - a % n" n=$cols a=$data|@count assign="cells"}
                {if $cells ne $cols}
                {section name=pad loop=$cells}
                        <TD>&nbsp;</TD>
                {/section}
                {/if}
                </TR>
        {/if}
    {/section}
</TABLE>

http://smarty.php.net/contribs/examples/dynamic_table_columns/table.tpl.txt

FYI, Smarty 2.5.0 will have an html_table function that will help automate this process.

Simpler Solution Using Smarty 2.6 Embedded Math

This is also for any number of columns, but made easier by using a new feature of Smarty version 2.6.0: using math expressions directly in templates.

{* Requires Smarty 2.6.0 or later *}
{* $data is the array you want to display *}
{* $numCols is the number of columns *}
<table>
    <tr>
    {assign var="col" value="0"}
    {section name=element loop=$data}
        {if $col == $numCols}
            </tr><tr>{assign var="col" value="0"}
        {/if}
        <td>{$data[element]}</td> 
        {assign var="col" value="`$col+1`"}
    {/section}
    {assign var="remainder" value="`$numCols-$col`"}
    {section name=emptyElement loop=$remainder}
        <td>&nbsp;</td>
    {/section}
    </tr>
</table>

Plugin solution Without Embedded Math

Because I saw that Embedded Math can be hard to deal because it uses php function eval()

I tried another solution. I created a plugin that can jump next record in a section so

I can print as many itens as I want in 1 loop thru the {section} I will post it at the

website www.phpbrasil.com in the scripts section. Here you will have the source of the plugin

and two example files.

save this as function.section_next.php in your smarty/plugins folder
<?php
/**
 * Smarty plugin
 * @package Smarty
 * @subpackage plugins
 */


/**
 * Smarty {section_next} function plugin
 *
 * Type:     function<br>
 * Name:     section_next<br>
 * Author:   Tadeu Ferreira Oliveira 
 * Contact:  tadeu_fo@yahoo.com.br
 * Purpose:  jump to the next element in a section
 * @param array parameters
 * @param Smarty
 * @return null
 */
function smarty_function_section_next($params, &$smarty)
{

    if (!isset($smarty->_sections[$params["name"]])){
		$smarty->trigger_error("section_next: section '".$params["name"]."' not found");
        return;
	}	
	$smarty->_sections[$params["name"]]['index'] 		+= $smarty->_sections[$params["name"]]['step'];
	$smarty->_sections[$params["name"]]['iteration']++;
	$smarty->_sections[$params["name"]]['rownum'] 		= $smarty->_sections[$params["name"]]['iteration'];
	$smarty->_sections[$params["name"]]['index_prev'] 	= $smarty->_sections[$params["name"]]['index'] - $smarty->_sections[$params["name"]]['step'];
	$smarty->_sections[$params["name"]]['index_next'] 	= $smarty->_sections[$params["name"]]['index'] + $smarty->_sections[$params["name"]]['step'];
	$smarty->_sections[$params["name"]]['first']      	= ($smarty->_sections[$params["name"]]['iteration'] == 1);
	$smarty->_sections[$params["name"]]['last']       	= ($smarty->_sections[$params["name"]]['iteration'] == $smarty->_sections[$params["name"]]['total']);
}

?>
///////////////////////////////////////////////////////
    teste.tpl
      <html>
         (* Mais de uma coluna por linha agora facinho facinho*)
         <table border="1">
         {section name=cont loop=$teste}
            <tr>
               <td>{$teste[cont]}</td> (* Uma Coluna*)
               {section_next name=cont}
               <td>{$teste[cont]}</td> (* Duas Colunas*)
            </tr>
         {/section}
         </table>
      </html>
///////////////////////////////////////////////////////
    teste.php 
      <?php
            require("Smarty.class.php");

            $teste[0] = "Zero";
            $teste[1] = "Um";
            $teste[2] = "Dois";
            $teste[3] = "Tres";
            $teste[4] = "Quatro";
            $teste[5] = "Cinco";
            $teste[6] = "Seis";
            $teste[7] = "Sete";

            $smarty = new Smarty();

            $smarty->assign("teste",$teste);

            $smarty->display("teste2.tpl");

      ?>