Skip to content

Commit

Permalink
x
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed May 14, 2024
1 parent c8faa54 commit 4ba9ed7
Showing 1 changed file with 56 additions and 55 deletions.
111 changes: 56 additions & 55 deletions latte/cs/cookbook/grouping.texy
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ Filtr a funkce `|group` umožňují efektivní seskupení dat podle zadaného kr
Každá z těchto značek nabízí specifické možnosti pro práci s daty, čímž se stávají nepostradatelnými nástroji pro dynamické a strukturované zobrazení informací v Latte šablonách.


Filtr a funkce `group`
----------------------
Filtr a funkce `group` .{data-version:3.0.16}
=============================================

Dejme tomu, že máme následující databázovou tabulku, kde jsou položky rozdělené do kategorií:
Představte si databázovou tabulku `items` s položkami rozdělenou do kategorií:

| id | categoryId | name
|------------------
Expand All @@ -22,7 +22,7 @@ Dejme tomu, že máme následující databázovou tabulku, kde jsou položky roz
| 5 | 3 | Red
| 6 | 3 | Blue

Vykreslit položky ve foreach cyklu jako seznam je samozřejmě snadné:
Jednoduchý seznam všech položek pomocí Latte šablony by vypadal takto:

```latte
<ul>
Expand All @@ -32,7 +32,7 @@ Vykreslit položky ve foreach cyklu jako seznam je samozřejmě snadné:
</ul>
```

Ale co kdybychom chtěli, aby každá kategorie byla v samostatném seznamu? Jinými slovy, řešíme úkol, jak seskupit položky v lineárním seznamu ve foreach cyklu do skupin. Výstup by měl vypadat takto:
Pokud bychom ale chtěli, aby položky byly uspořádány do skupin podle kategorie, potřebujeme je rozdělit tak, že každá kategorie bude mít svůj vlastní seznam. Výsledek by pak měl vypadat následovně:

```latte
<ul>
Expand All @@ -51,111 +51,112 @@ Ale co kdybychom chtěli, aby každá kategorie byla v samostatném seznamu? Jin
</ul>
```

Rovnou si ukážeme, jak snadno a elegantně se dá úkol vyřešit pomocí `|group`:
Úkol se dá snadno a elegantně vyřešit pomocí `|group`. Jako parametr uvedeme `categoryId`, což znamená, že se položky rozdělí do menších polí podle hodnoty `$item->categoryId` (pokud by `$item` bylo pole, použije se `$item['categoryId']`):

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

Vnější `{foreach}` seskupí položky do pro každou kategorii a pak nad nimi iteruje vnitřní `{foreach}`.
Filtr lze v Latte použít i jako funkci, což nám dává alternativní syntaxi: `{foreach group($items, categoryId) ...}`.

Chcete-li seskupovat položky podle složitějších kritérií, můžete v parametru filtru použít funkci. Například, seskupení položek podle délky názvu by vypadalo takto:

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

Výsledek bude vypadat takto:
Je důležité si uvědomit, že `$categoryItems` není běžné pole, ale objekt, který se chová jako iterátor. Pro přístup k první položce skupiny můžete použít funkci [`first()`|latte:functions#first].

```latte
<ul>
<li>Apple</li>
<li>Banana</li>
<li>PHP</li>
<li>Green</li>
<li>Red</li>
<li>Blue</li>
</ul>
```
Tato flexibilita v seskupování dat činí `group` výjimečně užitečným nástrojem pro prezentaci dat v šablonách Latte.


Vnořené smyčky
--------------

Představme si, že máme databázovou tabulku s dalším sloupcem `subcategoryId`, který definuje podkategorie jednotlivých položek. Chceme zobrazit každou hlavní kategorii v samostatném seznamu `<ul>` a každou podkategorii v samostatném vnořeném seznamu `<ol>`:

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


Vnořené smyčky
--------------
Spojení s Nette Database
------------------------

V rámci jednoho cyklu můžeme vytvářet více vnitřních smyček a dokonce je zanořovat. Takto by se daly seskupovat třeba podkategorie atd.
Pojďme si ukázat, jak efektivně využít seskupování dat v kombinaci s Nette Database. Předpokládejme, že pracujeme s tabulkou `items` z úvodního příkladu, která je prostřednictvím sloupce `categoryId` spojená s touto tabulkou `categories`:

Dejme tomu, že v tabulce bude ještě další sloupec `subcategoryId` a kromě toho, že každá kategorie bude v samostatném `<ul>`, každá každý podkategorie samostatném `<ol>`:
| categoryId | name |
|------------|------------|
| 1 | Fruits |
| 2 | Languages |
| 3 | Colors |

Data z tabulky `items` načteme pomocí Nette Database Explorer příkazem `$items = $db->table('items')`. Během iterace nad těmito daty máme možnost přistupovat nejen k atributům jako `$item->name` a `$item->categoryId`, ale díky propojení s tabulkou `categories` také k souvisejícímu řádku v ní přes `$item->category`. Na tomto propojení lze demonstrovat zajímavé využití:

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

V tomto případě používáme filtr `|group` k seskupení podle propojeného řádku `$item->category`, nikoliv jen dle sloupce `categoryId`. Díky tomu v proměnné klíči přímo `ActiveRow` dané kategorie, což nám umožňuje přímo vypisovat její název pomocí `{$category->name}`. Toto je praktický příklad, jak může seskupování zpřehlednit šablony a usnadnit práci s daty.


Filtr `|batch`
==============

Filtr |batch
------------
Filtr umožňuje rozdělit seznam prvků do skupin s předem určeným počtem prvků. Tento filtr je ideální pro situace, kdy chcete data prezentovat ve více menších skupinách, například pro lepší přehlednost nebo vizuální uspořádání na stránce.

Seskupování lineárních položek obstarává také filtr `batch`, a to do dávek s pevným počtem prvků:
Představme si, že máme seznam položek a chceme je zobrazit v seznamech, kde každý obsahuje maximálně tři položky. Použití filtru `|batch` je v takovém případě velmi praktické:

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

Lze jej nahradit za iterateWhile tímto způsobem:
V tomto příkladu je seznam `$items` rozdělen do menších skupin, přičemž každá skupina (`$batch`) obsahuje až tři položky. Každá skupina je poté zobrazena v samostatném `<ul>` seznamu.

Pokud poslední skupina neobsahuje dostatek prvků k dosažení požadovaného počtu, druhý parametr filtru umožňuje definovat, čím bude tato skupina doplněna. To je ideální pro estetické zarovnání prvků tam, kde by neúplná řada mohla působit neuspořádaně.

```latte
<ul>
{foreach $items as $item}
{iterateWhile}
<li>{$item->name}</li>
{/iterateWhile $iterator->counter0 % 3}
{/foreach}
{foreach ($items|batch: 3, '—') as $batch}
...
</ul>
```


Značka `{iterateWhile}`
-----------------------
=======================

Stejné úkoly, jako jsme řešili s filtrem `|group`, si ukážeme s použitím značky `{iterateWhile}`. Hlavní rozdíl mezi oběma přístupy je v tom, že `group` nejprve zpracuje a seskupí všechny vstupní data, zatímco `{iterateWhile}` řídí průběhu cyklů s podmínkami, takže iterace probíhá postupně.
Stejné úkoly, jako jsme řešili s filtrem `|group`, si ukážeme s použitím značky `{iterateWhile}`. Hlavní rozdíl mezi oběma přístupy je v tom, že `group` nejprve zpracuje a seskupí všechna vstupní data, zatímco `{iterateWhile}` řídí průběhu cyklů s podmínkami, takže iterace probíhá postupně.

Nejprve vykreslíme tabulku s kategoriemi pomocí iterateWhile:

Expand Down Expand Up @@ -197,7 +198,7 @@ Výsledek bude vypadat takto:
</ul>
```

K čemu je takové použití iterateWhile dobré? Jak se liší od řešení, které jsme si ukázali úplně na začátku tohoto návodu? Rozdíl je v tom, že když bude tabulka prázdná a nebude obsahovat žádné prvky, nevypíše se prázdné `<ul></ul>`.
K čemu je takové použití iterateWhile dobré? Když bude tabulka prázdná a nebude obsahovat žádné prvky, nevypíše se prázdné `<ul></ul>`.

Pokud uvedeme podmínku v otevírací značce `{iterateWhile}`, tak se chování změní: podmínka (a přechod na další prvek) se vykoná už na začátku vnitřního cyklu, nikoliv na konci.
Tedy zatímco do `{iterateWhile}` bez podmínky se vstoupí vždy, do `{iterateWhile $cond}` jen při splnění podmínky `$cond`. A zároveň se s tím do `$item` zapíše následující prvek.
Expand Down

0 comments on commit 4ba9ed7

Please sign in to comment.