foreachgroup Plugin

Author: Dan Culley

Like XSLT 2.0's for-each-group tag, this block function sorts an array or iterator into groups and iterates over each group. The grouping key is available via the $current_grouping_key variable and the items in the group are available via the $current_group array. I have found this useful for doing things such as alphabetical breakdowns as well as creating table headers for city groups. Currently, php code must be used in the group_by attribute, as the function uses the php eval function to execute it; I would be happy to modify this to use Smarty code if someone would be kind enough to post an explanation of how the $smarty->_eval() function works, as I have been unsuccessful in trying to use it.

Example 1:

{foreachgroup from=$array_or_iterator group_by='strtoupper(substr($current, 0, 1))'}
	<ul>
		<li>{$current_grouping_key}
			<ul>
			{foreach from=$current_group item=item}
				<li>{$item}</li>
			{/foreach}
			</ul>
		</li>
	</ul>
{/foreachgroup}

Sample Output 1:

* A
	*Alice
	*Anna
* B
	*Barbara
	*Betty

Example 2:

<table>
{foreachgroup from=$customers group_by='$customers->homeAddress->city'}
	<tr>
		<th colspan="3">{$current_grouping_key}</th>
	</tr>
	{foreach from=$current_group item=$customer}
	<tr>
		<td>{$customer->name</td>
		<td>{$customer->status}</td>
		<td>{$customer->getBalance()|string_format:'$%.2f'}</td>
	</tr>
	{/foreach}
{/foreachgroup}
</table>

Sample Ouput 2:

------------------------------
| Washington                 |
------------------------------
| Joe     | Current  |  $0.00|
------------------------------
| Mike    | Inactive | $20.00|
------------------------------
| New York                   |
------------------------------
| Polly   | Inactive |  $0.00|
------------------------------
| Molly   | Current  | $80.00|
------------------------------

Code:

function smarty_block_foreachgroup($params, $content, $smarty, &$repeat)
{
	static $grouparray = array();
	
	//Check required parameters
	if (!isset($params['from']))
		$smarty->trigger_error('foreachgroup: missing "from" parameter.');
	if (!isset($params['group_by']))
		$smarty->trigger_error('foreachgroup: missing "groupby" parameter');
		
	//If this is the first pass, sort into groups
	if (is_null($content))
	{
		$from = &$params['from'];
		foreach ($from as $current)
		{
			$key = eval('return '.$params['group_by'].';');
			if (!isset($grouparray[$key]))
				$grouparray[$key] = array();
			$grouparray[$key][] = $current;
		}
	}
	
	//For all other passes, get the next group
	//and set special variables.
	if (list($key, $item) = each($grouparray))
	{
		$smarty->assign('current_grouping_key', $key);
		$smarty->assign('current_group', $item);
		$repeat = true;
	}
	//If no more groups, stop the cycle.
	else
	{
		$repeat = false;
	}
	
	if (!is_null($content))
		return $content;
}