Всичко, което някога сте искали да знаете за групирането
При работа с данни в шаблони често можете да срещнете нуждата от тяхното групиране или специфично показване според определени критерии. Latte за тази цел предлага няколко силни инструмента.
Филтърът и функцията |group
позволяват ефективно групиране на
данни според зададен критерий, филтърът |batch
пък улеснява
разделянето на данни на предварително зададени партиди, а тагът
{iterateWhile}
предоставя възможност за по-сложно управление на
протичането на цикли с условия. Всеки от тези тагове предлага
специфични възможности за работа с данни, което ги прави незаменими
инструменти за динамично и структурирано показване на информация в Latte
шаблони.
Филтър и функция group
Представете си таблица в база данни items
с елементи, разделени
на категории:
id | categoryId | name |
---|---|---|
1 | 1 | Apple |
2 | 1 | Banana |
3 | 2 | PHP |
4 | 3 | Green |
5 | 3 | Red |
6 | 3 | Blue |
Прост списък на всички елементи с помощта на Latte шаблон би изглеждал така:
Ако обаче искахме елементите да бъдат подредени в групи според категорията, трябва да ги разделим така, че всяка категория да има свой собствен списък. Резултатът тогава трябва да изглежда по следния начин:
Задачата може лесно и елегантно да се реши с помощта на |group
.
Като параметър посочваме categoryId
, което означава, че елементите
ще се разделят на по-малки масиви според стойността на
$item->categoryId
(ако $item
беше масив, ще се използва
$item['categoryId']
):
Филтърът може в Latte да се използва и като функция, което ни дава
алтернативен синтаксис: {foreach group($items, categoryId) ...}
.
Ако искате да групирате елементи според по-сложни критерии, можете в параметъра на филтъра да използвате функция. Например, групиране на елементи според дължината на името би изглеждало така:
Важно е да се осъзнае, че $categoryItems
не е обикновен масив, а обект,
който се държи като итератор. За достъп до първия елемент на групата
можете да използвате функцията first()
.
Тази гъвкавост в групирането на данни прави group
изключително
полезен инструмент за представяне на данни в шаблони Latte.
Вложени цикли
Представете си, че имаме база данни с допълнителна колона
subcategoryId
, която дефинира подкатегориите на отделните елементи.
Искаме да покажем всяка основна категория в отделен списък
<ul>
и всяка подкатегория в отделен вложен списък
<ol>
:
Връзка с Nette Database
Нека покажем как ефективно да използваме групирането на данни в
комбинация с Nette Database. Да предположим, че работим с таблицата items
от уводния пример, която чрез колоната categoryId
е свързана с тази
таблица categories
:
categoryId | name |
---|---|
1 | Fruits |
2 | Languages |
3 | Colors |
Данните от таблицата items
зареждаме с помощта на Nette Database Explorer с
командата $items = $db->table('items')
. По време на итерацията над тези
данни имаме възможност да достъпваме не само атрибути като
$item->name
и $item->categoryId
, но благодарение на връзката с
таблицата categories
също и свързания ред в нея чрез
$item->category
. На тази връзка може да се демонстрира интересно
използване:
В този случай използваме филтъра |group
за групиране според
свързания ред $item->category
, а не само според колоната categoryId
.
Благодарение на това в променливата ключ имаме директно ActiveRow
на дадената категория, което ни позволява директно да изписваме
нейното име с {$category->name}
. Това е практичен пример за това как
групирането може да изясни шаблоните и да улесни работата с данни.
Филтър |batch
Филтърът позволява да се раздели списък от елементи на групи с предварително определен брой елементи. Този филтър е идеален за ситуации, когато искате да представите данните в няколко по-малки групи, например за по-добра прегледност или визуално подреждане на страницата.
Представете си, че имаме списък с елементи и искаме да ги покажем в
списъци, където всеки съдържа максимум три елемента. Използването на
филтъра |batch
в такъв случай е много практично:
В този пример списъкът $items
е разделен на по-малки групи, като
всяка група ($batch
) съдържа до три елемента. Всяка група след това
се показва в отделен <ul>
списък.
Ако последната група не съдържа достатъчно елементи за достигане на желания брой, вторият параметър на филтъра позволява да се дефинира с какво ще бъде допълнена тази група. Това е идеално за естетическо подравняване на елементите там, където непълният ред би могъл да изглежда неподреден.
Таг {iterateWhile}
Същите задачи, които решавахме с филтъра |group
, ще покажем с
използването на тага {iterateWhile}
. Основната разлика между двата
подхода е в това, че group
първо обработва и групира всички входни
данни, докато {iterateWhile}
управлява протичането на цикли с условия,
така че итерацията протича постепенно.
Първо ще рендираме таблицата с категориите с помощта на iterateWhile:
Докато {foreach}
обозначава външната част на цикъла, т.е.
рендирането на списъци за всяка категория, тагът {iterateWhile}
обозначава вътрешната част, т.е. отделните елементи. Условието в
крайния таг казва, че повторението ще продължи дотогава, докато
текущият и следващият елемент принадлежат към същата категория
($iterator->nextValue
е следващият елемент).
Ако условието беше изпълнено винаги, тогава във вътрешния цикъл ще се рендират всички елементи:
Резултатът ще изглежда така:
За какво е полезно такова използване на iterateWhile? Когато таблицата е
празна и не съдържа никакви елементи, няма да се изпише празно
<ul></ul>
.
Ако посочим условие в отварящия таг {iterateWhile}
, тогава
поведението се променя: условието (и преходът към следващия елемент) се
изпълнява още в началото на вътрешния цикъл, а не в края. Тоест, докато в
{iterateWhile}
без условие се влиза винаги, в {iterateWhile $cond}
само
при изпълнение на условието $cond
. И същевременно с това в
$item
се записва следващият елемент.
Което е полезно например в ситуация, когато искаме първия елемент във всяка категория да рендираме по различен начин, например така:
Ще променим оригиналния код така, че първо да рендираме първия
елемент и след това във вътрешния цикъл {iterateWhile}
да рендираме
другите елементи от същата категория:
В рамките на един цикъл можем да създаваме повече вътрешни цикли и дори да ги влагаме. Така биха могли да се групират например подкатегории и т.н.
Да предположим, че в таблицата има още една колона subcategoryId
и
освен това, че всяка категория ще бъде в отделен <ul>
, всяка
подкатегория в отделен <ol>
: