Tot ceea ce ați vrut să știți întotdeauna despre grupare
Atunci când lucrați cu date în șabloane, vă confruntați adesea cu necesitatea de a le grupa sau de a le afișa în mod specific în funcție de anumite criterii. În acest scop, Latte oferă mai multe instrumente puternice.
Filtrul și funcția |group
permit gruparea eficientă a datelor pe baza unor criterii specificate, în timp ce
filtrul |batch
facilitează împărțirea datelor în loturi fixe, iar eticheta {iterateWhile}
oferă
posibilitatea unui control mai complex al ciclului cu condiții. Fiecare dintre aceste etichete oferă opțiuni specifice de lucru
cu datele, ceea ce le face instrumente indispensabile pentru afișarea dinamică și structurată a informațiilor în
șabloanele Latte.
Filtru și funcție group
Imaginați-vă un tabel de bază de date items
cu articole împărțite în categorii:
id | categoryId | categoryId | name |
---|---|---|---|
1 | 1 | 1 | Apple |
2 | 1 | 1 | Banană 3 | 2 | 2 | PHP 4 | 3 | 3 | Verde
5 | 3 | Roșu |
6 | 3 | 3 | Albastru
O listă simplă a tuturor elementelor folosind un șablon Latte ar arăta astfel:
<ul>
{foreach $items as $item}
<li>{$item->name}</li>
{/foreach}
</ul>
Cu toate acestea, dacă am dori ca articolele să fie organizate în grupuri pe categorii, trebuie să le împărțim astfel încât fiecare categorie să aibă propria listă. Rezultatul ar arăta astfel:
<ul>
<li>Apple</li>
<li>Banana</li>
</ul>
<ul>
<li>PHP</li>
</ul>
<ul>
<li>Green</li>
<li>Red</li>
<li>Blue</li>
</ul>
Sarcina poate fi rezolvată ușor și elegant folosind |group
. Specificăm categoryId
ca parametru,
ceea ce înseamnă că elementele vor fi împărțite în array-uri mai mici pe baza valorii $item->categoryId
(dacă $item
ar fi un array, am folosi $item['categoryId']
):
{foreach ($items|group: categoryId) as $categoryId => $categoryItems}
<ul>
{foreach $categoryItems as $item}
<li>{$item->name}</li>
{/foreach}
</ul>
{/foreach}
Filtrul poate fi utilizat și ca o funcție în Latte, oferindu-ne o sintaxă alternativă:
{foreach group($items, categoryId) ...}
.
Dacă doriți să grupați elemente în funcție de criterii mai complexe, puteți utiliza o funcție în parametrul de filtrare. De exemplu, gruparea elementelor în funcție de lungimea numelui lor ar arăta în felul următor:
{foreach ($items|group: fn($item) => strlen($item->name)) as $items}
...
{/foreach}
Este important să rețineți că $categoryItems
nu este o matrice obișnuită, ci un obiect care se comportă ca
un iterator. Pentru a accesa primul element din grup, puteți utiliza funcția first()
funcție.
Această flexibilitate în gruparea datelor face din group
un instrument extrem de util pentru prezentarea datelor
în șabloanele Latte.
Bucle imbricate
Să presupunem că avem un tabel de bază de date cu o altă coloană subcategoryId
care definește
subcategoriile pentru fiecare articol. Dorim să afișăm fiecare categorie principală într-o coloană separată
<ul>
și fiecare subcategorie într-o listă separată, iar fiecare subcategorie într-o
<ol>
listă separată:
{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}
Conexiune cu baza de date Nette
Să arătăm cum să folosim în mod eficient gruparea datelor în combinație cu Nette Database. Să presupunem că lucrăm cu
tabelul items
din exemplul inițial, care este conectat prin coloana categoryId
la acest tabel
categories
:
categoryId | categoryId | name |
|------------|------------| 1 | Fructe | Fructe |
2 | Limbi |
3 | Culori |
Încărcăm datele din tabelul items
folosind comanda Nette Database Explorer
$items = $db->table('items')
. În timpul iterației asupra acestor date, avem posibilitatea nu numai de a accesa
atribute precum $item->name
și $item->categoryId
, ci, datorită conexiunii cu tabelul
categories
, și rândul aferent din acesta prin intermediul $item->category
. Această conexiune poate
demonstra utilizări interesante:
{foreach ($items|group: category) as $category => $categoryItems}
<h1>{$category->name}</h1>
<ul>
{foreach $categoryItems as $item}
<li>{$item->name}</li>
{/foreach}
</ul>
{/foreach}
În acest caz, folosim filtrul |group
pentru a grupa după rândul conectat $item->category
, nu
doar după coloana categoryId
. Acest lucru ne oferă ActiveRow
din categoria dată în cheia variabilă,
ceea ce ne permite să afișăm direct numele acesteia folosind {$category->name}
. Acesta este un exemplu practic
al modului în care gruparea poate simplifica șabloanele și facilita manipularea datelor.
Filtru |batch
Filtrul vă permite să împărțiți o listă de elemente în grupuri cu un număr prestabilit de elemente. Acest filtru este ideal pentru situațiile în care doriți să prezentați datele în mai multe grupuri mai mici, de exemplu, pentru o mai bună claritate sau organizare vizuală în pagină.
Imaginați-vă că avem o listă de elemente și dorim să le afișăm în liste, fiecare conținând maximum trei elemente.
Utilizarea filtrului |batch
este foarte practică într-un astfel de caz:
<ul>
{foreach ($items|batch: 3) as $batch}
{foreach $batch as $item}
<li>{$item->name}</li>
{/foreach}
{/foreach}
</ul>
În acest exemplu, lista $items
este împărțită în grupuri mai mici, fiecare grup ($batch
)
conținând cel mult trei elemente. Fiecare grup este apoi afișat într-o fereastră separată <ul>
listă
separată.
În cazul în care ultimul grup nu conține suficiente elemente pentru a ajunge la numărul dorit, al doilea parametru al filtrului vă permite să definiți cu ce va fi completat acest grup. Acest lucru este ideal pentru alinierea estetică a elementelor în cazul în care un rând incomplet ar putea părea dezordonat.
{foreach ($items|batch: 3, '—') as $batch}
...
{/foreach}
Etichetă {iterateWhile}
Vom demonstra aceleași sarcini pe care le-am abordat cu filtrul |group
folosind eticheta
{iterateWhile}
. Principala diferență între cele două abordări este că group
procesează și
grupează mai întâi toate datele de intrare, în timp ce {iterateWhile}
controlează progresul ciclurilor cu
condiții, astfel încât iterația are loc secvențial.
Mai întâi, desenăm un tabel cu categorii folosind iterateWhile:
{foreach $items as $item}
<ul>
{iterateWhile}
<li>{$item->name}</li>
{/iterateWhile $item->categoryId === $iterator->nextValue->categoryId}
</ul>
{/foreach}
În timp ce {foreach}
marchează partea exterioară a ciclului, adică desenarea listelor pentru fiecare
categorie, eticheta {iterateWhile}
marchează partea interioară, adică elementele individuale. Condiția din tag-ul
end spune că repetiția va continua atâta timp cât elementul curent și cel următor aparțin aceleiași categorii
($iterator->nextValue
este următorul element).
Dacă această condiție ar fi întotdeauna îndeplinită, toate elementele ar fi desenate în ciclul interior:
{foreach $items as $item}
<ul>
{iterateWhile}
<li>{$item->name}
{/iterateWhile true}
</ul>
{/foreach}
Rezultatul va arăta astfel:
<ul>
<li>Apple</li>
<li>Banana</li>
<li>PHP</li>
<li>Green</li>
<li>Red</li>
<li>Blue</li>
</ul>
Care este utilizarea iterateWhile în acest mod? Atunci când tabelul este gol și nu conține niciun element, nu este
necesară o operațiune de tip "empty <ul></ul>
este tipărit.
Dacă specificăm condiția în deschiderea etichetei {iterateWhile}
, comportamentul se schimbă: condiția (și
tranziția la următorul element) se realizează la începutul ciclului interior, nu la sfârșitul acestuia. Astfel, în timp ce
întotdeauna se introduce {iterateWhile}
fără condiții, se introduce {iterateWhile $cond}
numai
atunci când este îndeplinită condiția $cond
. Și, în același timp, următorul element este scris în
$item
.
Acest lucru este util, de exemplu, în situația în care dorim să redăm primul element din fiecare categorie în mod diferit, astfel:
<h1>Apple</h1>
<ul>
<li>Banana</li>
</ul>
<h1>PHP</h1>
<ul>
</ul>
<h1>Green</h1>
<ul>
<li>Red</li>
<li>Blue</li>
</ul>
Modificăm codul original astfel încât să redăm mai întâi primul element și apoi, în ciclul interior
{iterateWhile}
, să redăm celelalte elemente din aceeași categorie:
{foreach $items as $item}
<h1>{$item->name}</h1>
<ul>
{iterateWhile $item->categoryId === $iterator->nextValue->categoryId}
<li>{$item->name}</li>
{/iterateWhile}
</ul>
{/foreach}
În cadrul unui ciclu, putem crea mai multe bucle interioare și chiar le putem anina. În acest fel, subcategoriile ar putea fi grupate, de exemplu.
Să presupunem că tabelul are o altă coloană subcategoryId
, și pe lângă faptul că fiecare categorie se
află într-o coloană separată <ul>
, fiecare subcategorie într-o coloană separată
<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}