Novinka v Latte: filtr |group

David Grudl
Nette Core | 8192
+
+10
-

Přidal jsem do Latte velmi užitečný filtr, který mi připadá jako srozumitelnější alternativa pro {iteratewhile}. Jde o filtr |group.

Princip je úplně prostý: data, která vypisuju, si seskupím podle nějakého klíče.

Jako příklad si vezmu tuto tabulku, kterou pojmenuju things:

id categoryId name
1 1 Apple
2 1 Banana
3 2 PHP
4 3 Green
5 3 Red
6 3 Blue

kterou chci při výpisu pomocí foreach seskupit podle kategorií:

<ul>
	<li>Apple</li>
	<li>Banana</li>
</ul>

<ul>
	<li>PHP</li>
</ul>

<ul>
	<li>Green</li>
	<li>Red</li>
	<li>Blue</li>
</ul>

Pro porovnání sem dávám řešení pomocí {iterateWhile}:

{foreach $things as $item}
	<ul>
		{iterateWhile}
			<li>{$item->name}</li>
		{/iterateWhile $item->categoryId === $iterator->nextValue->categoryId}
	</ul>
{/foreach}

A teď totéž pomocí group (demo)

{foreach ($things|group: categoryId) as $categoryId => $items}
	<ul>
		{foreach $items as $item}
			<li>{$item->name}</li>
		{/foreach}
	</ul>
{/foreach}

Group vrátí pole polí, kde klíčem bude právě hodnota categoryId.

Hlavní rozdíl oproti iterateWhile je ten, že group zpracuje celý vstup a pak vrátí seskupený výsledek, zatímco při iterateWhile se data iterují postupně. Group proto nevadí, když kategorie nepůjdou ve vstupních datech postupně. Na výstupu pak budou v pořadí, v jakém se postupně objevily v datech.

Spojení s Nette Database

Zajímavě se dá využít při spojení s Nette Database. Máme tedy tabulku things a ta je přes sloupec categoryId propojena s tabulkou categories:

categoryId name
1 Fruits
2 Languages
3 Colors

Pomocí Nette Database Explorer vytáhnu z tabulky data pomocí $things = $db->table('things'). A jak známo, během iterace mohu přistupovat nejen k položkám $item->name a $item->categoryId, ale také rovnou do připojené tabulky přes $item->category->name. A právě podle $item->category budu data seskupovat:

{foreach ($things|group: category) as $category => $items}
	<h1>{$category->name}</h1>
	<ul>
		{foreach $items as $item}
			<li>{$item->name}</li>
		{/foreach}
	</ul>
{/foreach}

Vyměnil jsem group: categoryId za group: category, takže v klíči teď není číslo, ale řádek v odkazované tabulce. A data z něj můžu pohodlně vypsat jako {$category->name}.

Vnořené smyčky

V příkladu interateWhile je ukázka i vnořené smyčky, tedy seskupování podle podkategorií. Totéž se dá samozřejmě udělat i s group:

{foreach ($things|group: categoryId) as $categoryId => $items1}
	<ul>
		{foreach ($items1|group: subcategoryId) as $items2}
			<ol>
				{foreach $items2 as $item}
					<li>{$item->name}
				{/foreach}
			</ol>
		{/foreach}
	</ul>
{/foreach}