Nette Documentation Preview

syntax
Minden, amit mindig is tudni akartál a csoportosításról
*******************************************************

.[perex]
Amikor sablonokban dolgozik az adatokkal, gyakran találkozik azzal az igénnyel, hogy csoportosítani vagy bizonyos kritériumok szerint megjeleníteni kell őket. Erre a célra a Latte számos hatékony eszközt kínál.

A `|group` szűrő és funkció lehetővé teszi az adatok hatékony csoportosítását meghatározott kritériumok alapján, míg a `|batch` szűrő megkönnyíti az adatok rögzített tételekre való felosztását, a `{iterateWhile}` címke pedig lehetőséget biztosít a feltételek segítségével történő összetettebb ciklusszabályozásra.
E címkék mindegyike speciális lehetőségeket kínál az adatokkal való munkához, így nélkülözhetetlen eszközök az információk dinamikus és strukturált megjelenítéséhez a Latte sablonokban.


Szűrő és funkció `group` .[#toc-filter-and-function-group]
==========================================================

Képzeljünk el egy `items` adatbázis-táblát, amelyben kategóriákba sorolt tételek találhatók:

| id | categoryId | name
|------------------
| 1 | 1 | 1 | Apple
| 2 | 1 | Banán
| 3 | 2 | PHP
| 4 | 3 | Zöld
| 5 | 3 | Piros
| 6 | 3 | Kék

Az összes elem egyszerű listája a Latte sablon használatával így nézne ki:

```latte
<ul>
{foreach $items as $item}
	<li>{$item->name}</li>
{/foreach}
</ul>
```

Ha azonban azt szeretnénk, hogy az elemeket kategóriák szerint csoportosítani tudjuk, akkor úgy kell felosztanunk őket, hogy minden kategóriának saját listája legyen. Az eredmény így nézne ki:

```latte
<ul>
	<li>Apple</li>
	<li>Banana</li>
</ul>

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

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

A feladat könnyen és elegánsan megoldható a `|group` segítségével. Paraméterként megadjuk a `categoryId` címet, ami azt jelenti, hogy az elemeket a `$item->categoryId` érték alapján kisebb tömbökre osztjuk fel (ha a `$item` egy tömb lenne, akkor a következővel dolgoznánk `$item['categoryId']`):

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

A szűrő a Latte-ban függvényként is használható, így alternatív szintaxist kapunk: `{foreach group($items, categoryId) ...}`.

Ha összetettebb kritériumok szerint szeretnénk csoportosítani az elemeket, akkor a szűrő paraméterében használhatunk függvényt. Például az elemek csoportosítása a nevük hossza alapján így nézne ki:

```latte
{foreach ($items|group: fn($item) => strlen($item->name)) as $items}
	...
{/foreach}
```

Fontos megjegyezni, hogy a `$categoryItems` nem egy hagyományos tömb, hanem egy olyan objektum, amely iterátorként viselkedik. A csoport első elemének eléréséhez használhatja a [`first()` |latte:functions#first] függvényt.

Az adatok csoportosításának ez a rugalmassága teszi a `group` -t kivételesen hasznos eszközzé az adatok Latte sablonokban történő bemutatásához.


Beágyazott hurkok .[#toc-nested-loops]
--------------------------------------

Tegyük fel, hogy van egy adatbázis-táblánk egy másik `subcategoryId` oszloppal, amely az egyes tételek alkategóriáit határozza meg. Minden egyes fő kategóriát egy különálló `<ul>` listában, és minden alkategóriát egy külön beágyazott listában. `<ol>` listában:

```latte
{foreach ($items|group: categoryId) as $categoryItems}
	<ul>
		{foreach ($categoryItems|group: subcategoryId) as $subcategoryItems}
			<ol>
				{foreach $subcategoryItems as $item}
					<li>{$item->name}
				{/foreach}
			</ol>
		{/foreach}
	</ul>
{/foreach}
```


Kapcsolat a Nette adatbázissal .[#toc-connection-with-nette-database]
---------------------------------------------------------------------

Megmutatjuk, hogyan lehet hatékonyan használni az adatcsoportosítást a Nette Adatbázissal kombinálva. Tegyük fel, hogy az eredeti példában szereplő `items` táblával dolgozunk, amely a `categoryId` oszlopon keresztül kapcsolódik ehhez a `categories` táblához:

| categoryId | név |
|------------|------------|
| 1 | Gyümölcsök |
| 2 | Nyelvek |
| 3 | Színek |

Az adatokat a `items` táblából a Nette Database Explorer `$items = $db->table('items')` parancsával töltjük be. Az ezeken az adatokon való iteráció során nemcsak az olyan attribútumokhoz férhetünk hozzá, mint a `$item->name` és a `$item->categoryId`, hanem a `categories` táblával való kapcsolatnak köszönhetően a `$item->category` segítségével a tábla kapcsolódó sorához is. Ez a kapcsolat érdekes felhasználási lehetőségeket mutathat fel:

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

Ebben az esetben a `|group` szűrővel a `$item->category` kapcsolódó sora szerint csoportosítunk, nem csak a `categoryId` oszlop szerint. Ezáltal a változó kulcsában megkapjuk az adott kategória `ActiveRow` címét, így a `{$category->name}` segítségével közvetlenül megjeleníthetjük a nevét. Ez egy gyakorlati példa arra, hogy a csoportosítás hogyan egyszerűsítheti a sablonokat és könnyítheti meg az adatkezelést.


Szűrő `|batch` .[#toc-filter-batch]
===================================

A szűrő lehetővé teszi, hogy az elemek listáját előre meghatározott számú elemet tartalmazó csoportokra ossza. Ez a szűrő ideális olyan helyzetekben, amikor az adatokat több kisebb csoportban szeretné megjeleníteni, például a jobb áttekinthetőség vagy az oldalon való vizuális rendezés érdekében.

Képzeljük el, hogy van egy elemeket tartalmazó listánk, és azokat listákban szeretnénk megjeleníteni, amelyek mindegyike legfeljebb három elemet tartalmazhat. A `|batch` szűrő használata ilyen esetben nagyon praktikus:

```latte
<ul>
{foreach ($items|batch: 3) as $batch}
	{foreach $batch as $item}
		<li>{$item->name}</li>
	{/foreach}
{/foreach}
</ul>
```

Ebben a példában a `$items` listát kisebb csoportokra osztjuk, és minden csoport (`$batch`) legfeljebb három elemet tartalmaz. Ezután minden csoport egy különálló `<ul>` listában.

Ha az utolsó csoport nem tartalmaz elegendő elemet a kívánt szám eléréséhez, a szűrő második paramétere lehetővé teszi annak meghatározását, hogy mivel egészüljön ki ez a csoport. Ez ideális az elemek esztétikai összehangolására, ahol egy hiányos sor rendezetlennek tűnhet.

```latte
{foreach ($items|batch: 3, '—') as $batch}
	...
{/foreach}
```


Címke `{iterateWhile}` .[#toc-tag-iteratewhile]
===============================================

A `{iterateWhile}` címkével ugyanazokat a feladatokat mutatjuk be, mint amiket a `|group` szűrővel kezeltünk. A fő különbség a két megközelítés között az, hogy a `group` először feldolgozza és csoportosítja az összes bemeneti adatot, míg a `{iterateWhile}` a feltételekkel rendelkező ciklusok előrehaladását vezérli, így az iteráció szekvenciálisan történik.

Először egy kategóriákat tartalmazó táblázatot rajzolunk az iterateWhile segítségével:

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

Míg a `{foreach}` a ciklus külső részét jelöli, azaz az egyes kategóriákhoz tartozó listák rajzolását, addig a `{iterateWhile}` címke a belső részt, azaz az egyes elemeket.
Az end tagben lévő feltétel azt mondja, hogy az ismétlés addig folytatódik, amíg az aktuális és a következő elem ugyanahhoz a kategóriához tartozik (`$iterator->nextValue` a [következő elem |/tags#$iterator]).

Ha a feltétel mindig teljesülne, akkor a belső ciklusban minden elem kirajzolódna:

```latte
{foreach $items as $item}
	<ul>
		{iterateWhile}
			<li>{$item->name}
		{/iterateWhile true}
	</ul>
{/foreach}
```

Az eredmény így fog kinézni:

```latte
<ul>
	<li>Apple</li>
	<li>Banana</li>
	<li>PHP</li>
	<li>Green</li>
	<li>Red</li>
	<li>Blue</li>
</ul>
```

Mi a haszna az iterateWhile-nak ebben a formában? Ha a táblázat üres, és nem tartalmaz elemeket, nincs üres `<ul></ul>` kerül kiírásra.

Ha a feltételt a nyitó `{iterateWhile}` címkében adjuk meg, a viselkedés megváltozik: a feltétel (és a következő elemre való átmenet) a belső ciklus elején történik, nem pedig a végén.
Így míg a `{iterateWhile}` mindig feltétel nélkül lép be, addig a `{iterateWhile $cond}` csak akkor lép be, ha a `$cond` feltétel teljesül. És ezzel egyidejűleg a következő elemet írja be a `$item`.

Ez hasznos például olyan helyzetben, amikor az egyes kategóriák első elemét másképp akarjuk megjeleníteni, például így:

```latte
<h1>Apple</h1>
<ul>
	<li>Banana</li>
</ul>

<h1>PHP</h1>
<ul>
</ul>

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

Az eredeti kódot úgy módosítjuk, hogy először az első elemet rendereljük, majd a belső ciklusban `{iterateWhile}` rendereljük a többi elemet ugyanabból a kategóriából:

```latte
{foreach $items as $item}
	<h1>{$item->name}</h1>
	<ul>
		{iterateWhile $item->categoryId === $iterator->nextValue->categoryId}
			<li>{$item->name}</li>
		{/iterateWhile}
	</ul>
{/foreach}
```

Egy cikluson belül több belső hurkot is létrehozhatunk, és akár egymásba is ágyazhatjuk őket. Így például az alkategóriákat is csoportosíthatjuk.

Tegyük fel, hogy a táblázatnak van egy másik oszlopa is: `subcategoryId`, és amellett, hogy minden kategória egy különálló `<ul>`, minden alkategória egy külön `<ol>`:

```latte
{foreach $items as $item}
	<ul>
		{iterateWhile}
			<ol>
				{iterateWhile}
					<li>{$item->name}
				{/iterateWhile $item->subcategoryId === $iterator->nextValue->subcategoryId}
			</ol>
		{/iterateWhile $item->categoryId === $iterator->nextValue->categoryId}
	</ul>
{/foreach}
```


{{leftbar: /@left-menu}}

Minden, amit mindig is tudni akartál a csoportosításról

Amikor sablonokban dolgozik az adatokkal, gyakran találkozik azzal az igénnyel, hogy csoportosítani vagy bizonyos kritériumok szerint megjeleníteni kell őket. Erre a célra a Latte számos hatékony eszközt kínál.

A |group szűrő és funkció lehetővé teszi az adatok hatékony csoportosítását meghatározott kritériumok alapján, míg a |batch szűrő megkönnyíti az adatok rögzített tételekre való felosztását, a {iterateWhile} címke pedig lehetőséget biztosít a feltételek segítségével történő összetettebb ciklusszabályozásra. E címkék mindegyike speciális lehetőségeket kínál az adatokkal való munkához, így nélkülözhetetlen eszközök az információk dinamikus és strukturált megjelenítéséhez a Latte sablonokban.

Szűrő és funkció group

Képzeljünk el egy items adatbázis-táblát, amelyben kategóriákba sorolt tételek találhatók:

id categoryId name
1 1 1 Apple
2 1 Banán  
3 2 PHP  
4 3 Zöld  
5 3 Piros  
6 3 Kék  

Az összes elem egyszerű listája a Latte sablon használatával így nézne ki:

<ul>
{foreach $items as $item}
	<li>{$item->name}</li>
{/foreach}
</ul>

Ha azonban azt szeretnénk, hogy az elemeket kategóriák szerint csoportosítani tudjuk, akkor úgy kell felosztanunk őket, hogy minden kategóriának saját listája legyen. Az eredmény így nézne ki:

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

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

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

A feladat könnyen és elegánsan megoldható a |group segítségével. Paraméterként megadjuk a categoryId címet, ami azt jelenti, hogy az elemeket a $item->categoryId érték alapján kisebb tömbökre osztjuk fel (ha a $item egy tömb lenne, akkor a következővel dolgoznánk $item['categoryId']):

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

A szűrő a Latte-ban függvényként is használható, így alternatív szintaxist kapunk: {foreach group($items, categoryId) ...}.

Ha összetettebb kritériumok szerint szeretnénk csoportosítani az elemeket, akkor a szűrő paraméterében használhatunk függvényt. Például az elemek csoportosítása a nevük hossza alapján így nézne ki:

{foreach ($items|group: fn($item) => strlen($item->name)) as $items}
	...
{/foreach}

Fontos megjegyezni, hogy a $categoryItems nem egy hagyományos tömb, hanem egy olyan objektum, amely iterátorként viselkedik. A csoport első elemének eléréséhez használhatja a first() függvényt.

Az adatok csoportosításának ez a rugalmassága teszi a group -t kivételesen hasznos eszközzé az adatok Latte sablonokban történő bemutatásához.

Beágyazott hurkok

Tegyük fel, hogy van egy adatbázis-táblánk egy másik subcategoryId oszloppal, amely az egyes tételek alkategóriáit határozza meg. Minden egyes fő kategóriát egy különálló <ul> listában, és minden alkategóriát egy külön beágyazott listában. <ol> listában:

{foreach ($items|group: categoryId) as $categoryItems}
	<ul>
		{foreach ($categoryItems|group: subcategoryId) as $subcategoryItems}
			<ol>
				{foreach $subcategoryItems as $item}
					<li>{$item->name}
				{/foreach}
			</ol>
		{/foreach}
	</ul>
{/foreach}

Kapcsolat a Nette adatbázissal

Megmutatjuk, hogyan lehet hatékonyan használni az adatcsoportosítást a Nette Adatbázissal kombinálva. Tegyük fel, hogy az eredeti példában szereplő items táblával dolgozunk, amely a categoryId oszlopon keresztül kapcsolódik ehhez a categories táblához:

categoryId név
1 Gyümölcsök
2 Nyelvek
3 Színek

Az adatokat a items táblából a Nette Database Explorer $items = $db->table('items') parancsával töltjük be. Az ezeken az adatokon való iteráció során nemcsak az olyan attribútumokhoz férhetünk hozzá, mint a $item->name és a $item->categoryId, hanem a categories táblával való kapcsolatnak köszönhetően a $item->category segítségével a tábla kapcsolódó sorához is. Ez a kapcsolat érdekes felhasználási lehetőségeket mutathat fel:

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

Ebben az esetben a |group szűrővel a $item->category kapcsolódó sora szerint csoportosítunk, nem csak a categoryId oszlop szerint. Ezáltal a változó kulcsában megkapjuk az adott kategória ActiveRow címét, így a {$category->name} segítségével közvetlenül megjeleníthetjük a nevét. Ez egy gyakorlati példa arra, hogy a csoportosítás hogyan egyszerűsítheti a sablonokat és könnyítheti meg az adatkezelést.

Szűrő |batch

A szűrő lehetővé teszi, hogy az elemek listáját előre meghatározott számú elemet tartalmazó csoportokra ossza. Ez a szűrő ideális olyan helyzetekben, amikor az adatokat több kisebb csoportban szeretné megjeleníteni, például a jobb áttekinthetőség vagy az oldalon való vizuális rendezés érdekében.

Képzeljük el, hogy van egy elemeket tartalmazó listánk, és azokat listákban szeretnénk megjeleníteni, amelyek mindegyike legfeljebb három elemet tartalmazhat. A |batch szűrő használata ilyen esetben nagyon praktikus:

<ul>
{foreach ($items|batch: 3) as $batch}
	{foreach $batch as $item}
		<li>{$item->name}</li>
	{/foreach}
{/foreach}
</ul>

Ebben a példában a $items listát kisebb csoportokra osztjuk, és minden csoport ($batch) legfeljebb három elemet tartalmaz. Ezután minden csoport egy különálló <ul> listában.

Ha az utolsó csoport nem tartalmaz elegendő elemet a kívánt szám eléréséhez, a szűrő második paramétere lehetővé teszi annak meghatározását, hogy mivel egészüljön ki ez a csoport. Ez ideális az elemek esztétikai összehangolására, ahol egy hiányos sor rendezetlennek tűnhet.

{foreach ($items|batch: 3, '—') as $batch}
	...
{/foreach}

Címke {iterateWhile}

A {iterateWhile} címkével ugyanazokat a feladatokat mutatjuk be, mint amiket a |group szűrővel kezeltünk. A fő különbség a két megközelítés között az, hogy a group először feldolgozza és csoportosítja az összes bemeneti adatot, míg a {iterateWhile} a feltételekkel rendelkező ciklusok előrehaladását vezérli, így az iteráció szekvenciálisan történik.

Először egy kategóriákat tartalmazó táblázatot rajzolunk az iterateWhile segítségével:

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

Míg a {foreach} a ciklus külső részét jelöli, azaz az egyes kategóriákhoz tartozó listák rajzolását, addig a {iterateWhile} címke a belső részt, azaz az egyes elemeket. Az end tagben lévő feltétel azt mondja, hogy az ismétlés addig folytatódik, amíg az aktuális és a következő elem ugyanahhoz a kategóriához tartozik ($iterator->nextValue a következő elem).

Ha a feltétel mindig teljesülne, akkor a belső ciklusban minden elem kirajzolódna:

{foreach $items as $item}
	<ul>
		{iterateWhile}
			<li>{$item->name}
		{/iterateWhile true}
	</ul>
{/foreach}

Az eredmény így fog kinézni:

<ul>
	<li>Apple</li>
	<li>Banana</li>
	<li>PHP</li>
	<li>Green</li>
	<li>Red</li>
	<li>Blue</li>
</ul>

Mi a haszna az iterateWhile-nak ebben a formában? Ha a táblázat üres, és nem tartalmaz elemeket, nincs üres <ul></ul> kerül kiírásra.

Ha a feltételt a nyitó {iterateWhile} címkében adjuk meg, a viselkedés megváltozik: a feltétel (és a következő elemre való átmenet) a belső ciklus elején történik, nem pedig a végén. Így míg a {iterateWhile} mindig feltétel nélkül lép be, addig a {iterateWhile $cond} csak akkor lép be, ha a $cond feltétel teljesül. És ezzel egyidejűleg a következő elemet írja be a $item.

Ez hasznos például olyan helyzetben, amikor az egyes kategóriák első elemét másképp akarjuk megjeleníteni, például így:

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

<h1>PHP</h1>
<ul>
</ul>

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

Az eredeti kódot úgy módosítjuk, hogy először az első elemet rendereljük, majd a belső ciklusban {iterateWhile} rendereljük a többi elemet ugyanabból a kategóriából:

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

Egy cikluson belül több belső hurkot is létrehozhatunk, és akár egymásba is ágyazhatjuk őket. Így például az alkategóriákat is csoportosíthatjuk.

Tegyük fel, hogy a táblázatnak van egy másik oszlopa is: subcategoryId, és amellett, hogy minden kategória egy különálló <ul>, minden alkategória egy külön <ol>:

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