Gruplama Hakkında Her Zaman Bilmek İstediğiniz Her Şey
Şablonlardaki verilerle çalışırken, bunları gruplama veya belirli kriterlere göre özel olarak görüntüleme ihtiyacıyla sık sık karşılaşırsınız. Bu amaçla, Latte birkaç güçlü araç sunar.
Filtre ve fonksiyon |group
belirli kriterlere göre etkin veri gruplandırması sağlarken, |batch
filtresi verileri sabit gruplara ayırmayı kolaylaştırır ve {iterateWhile}
etiketi koşullarla daha karmaşık
döngü kontrolü imkanı sağlar. Bu etiketlerin her biri verilerle çalışmak için özel seçenekler sunarak Latte
şablonlarında dinamik ve yapılandırılmış bilgi gösterimi için vazgeçilmez araçlar haline getirir.
Filtre ve işlev group
Kategorilere ayrılmış öğeler içeren bir veritabanı tablosu items
hayal edin:
id | kategoriId | isim |
---|---|---|
1 | 1 | Elma |
2 | 1 | Muz |
3 | 2 | PHP |
4 | 3 | Yeşil |
5 | 3 | Kırmızı |
6 | 3 | Mavi |
Latte şablonunu kullanan tüm öğelerin basit bir listesi şöyle görünecektir:
<ul>
{foreach $items as $item}
<li>{$item->name}</li>
{/foreach}
</ul>
Ancak, öğelerin kategorilere göre gruplar halinde düzenlenmesini istiyorsak, bunları her kategorinin kendi listesi olacak şekilde bölmemiz gerekir. Bu durumda sonuç şöyle olacaktır:
<ul>
<li>Apple</li>
<li>Banana</li>
</ul>
<ul>
<li>PHP</li>
</ul>
<ul>
<li>Green</li>
<li>Red</li>
<li>Blue</li>
</ul>
Bu görev |group
kullanılarak kolayca ve zarif bir şekilde çözülebilir. Parametre olarak
categoryId
belirtiyoruz, yani öğeler $item->categoryId
değerine göre daha küçük dizilere
bölünecek ( $item
bir dizi olsaydı $item['categoryId']
):
{foreach ($items|group: categoryId) as $categoryId => $categoryItems}
<ul>
{foreach $categoryItems as $item}
<li>{$item->name}</li>
{/foreach}
</ul>
{/foreach}
Filtre, Latte'de bir fonksiyon olarak da kullanılabilir ve bize alternatif bir sözdizimi sunar:
{foreach group($items, categoryId) ...}
.
Öğeleri daha karmaşık ölçütlere göre gruplamak istiyorsanız filtre parametresinde bir işlev kullanabilirsiniz. Örneğin, öğeleri adlarının uzunluğuna göre gruplamak şu şekilde görünecektir:
{foreach ($items|group: fn($item) => strlen($item->name)) as $items}
...
{/foreach}
$categoryItems
adresinin normal bir dizi değil, yineleyici gibi davranan bir nesne olduğuna dikkat etmek
önemlidir. Gruptaki ilk öğeye erişmek için first()
fonksiyon.
Veri gruplamadaki bu esneklik, group
adresini Latte şablonlarında veri sunmak için son derece kullanışlı bir
araç haline getirmektedir.
İç İçe Döngüler
Diyelim ki her bir öğe için alt kategorileri tanımlayan subcategoryId
sütununa sahip bir veritabanı tablomuz
var. Her ana kategoriyi ayrı bir tabloda görüntülemek istiyoruz. <ul>
listesini ve her bir alt kategoriyi
ayrı bir yuvalanmış <ol>
Liste:
{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}
Nette Veritabanı ile Bağlantı
Veri gruplandırmanın Nette Database ile birlikte nasıl etkin bir şekilde kullanılacağını gösterelim. İlk örnekteki
items
tablosuyla çalıştığımızı ve categoryId
sütunu aracılığıyla bu categories
tablosuna bağlandığımızı varsayalım:
kategoriId | isim |
---|---|
1 | Meyveler |
2 | Diller |
3 | Renkler |
Nette Database Explorer komutunu kullanarak items
tablosundan veri yüklüyoruz
$items = $db->table('items')
. Bu veriler üzerinde yineleme yaparken, yalnızca $item->name
ve
$item->categoryId
gibi özniteliklere değil, categories
tablosuyla olan bağlantı sayesinde,
$item->category
aracılığıyla ilgili satıra da erişme fırsatına sahibiz. Bu bağlantı ilginç kullanımlar
sergileyebilir:
{foreach ($items|group: category) as $category => $categoryItems}
<h1>{$category->name}</h1>
<ul>
{foreach $categoryItems as $item}
<li>{$item->name}</li>
{/foreach}
</ul>
{/foreach}
Bu durumda, sadece categoryId
sütununa göre değil, bağlı $item->category
satırına göre
gruplamak için |group
filtresini kullanırız. Bu bize değişken anahtarında verilen kategorinin
ActiveRow
adresini verir ve {$category->name}
adresini kullanarak doğrudan adını
görüntülememize olanak tanır. Bu, gruplamanın şablonları nasıl basitleştirebileceğini ve veri işlemeyi nasıl
kolaylaştırabileceğini gösteren pratik bir örnektir.
Filtre |batch
Filtre, bir öğe listesini önceden belirlenmiş sayıda öğe içeren gruplara ayırmanıza olanak tanır. Bu filtre, örneğin sayfada daha iyi netlik veya görsel düzenleme için verileri birkaç küçük grup halinde sunmak istediğiniz durumlar için idealdir.
Elimizde bir öğe listesi olduğunu ve bunları her biri en fazla üç öğe içeren listeler halinde görüntülemek
istediğimizi düşünün. Böyle bir durumda |batch
filtresini kullanmak çok pratiktir:
<ul>
{foreach ($items|batch: 3) as $batch}
{foreach $batch as $item}
<li>{$item->name}</li>
{/foreach}
{/foreach}
</ul>
Bu örnekte, $items
listesi, her grup ($batch
) en fazla üç öğe içerecek şekilde daha küçük
gruplara bölünmüştür. Her grup daha sonra ayrı bir <ul>
Liste.
Son grup istenen sayıya ulaşmak için yeterli öğe içermiyorsa, filtrenin ikinci parametresi bu grubun ne ile tamamlanacağını tanımlamanıza olanak tanır. Bu, tamamlanmamış bir satırın düzensiz görünebileceği öğeleri estetik olarak hizalamak için idealdir.
{foreach ($items|batch: 3, '—') as $batch}
...
{/foreach}
Etiket {iterateWhile}
|group
filtresi ile ele aldığımız aynı görevleri {iterateWhile}
etiketini kullanarak
göstereceğiz. İki yaklaşım arasındaki temel fark, group
ilk olarak tüm girdi verilerini işler ve
gruplandırırken, {iterateWhile}
döngülerin ilerlemesini koşullarla kontrol eder, böylece yineleme sırayla
gerçekleşir.
İlk olarak, iterateWhile kullanarak kategorileri içeren bir tablo çiziyoruz:
{foreach $items as $item}
<ul>
{iterateWhile}
<li>{$item->name}</li>
{/iterateWhile $item->categoryId === $iterator->nextValue->categoryId}
</ul>
{/foreach}
{foreach}
etiketi döngünün dış kısmını, yani her bir kategori için çizim listelerini işaretlerken,
{iterateWhile}
etiketi iç kısmı, yani tek tek öğeleri işaretler. End etiketindeki koşul, mevcut ve sonraki
öğe aynı kategoriye ait olduğu sürece tekrarlamanın devam edeceğini söyler ($iterator->nextValue
sonraki öğedir).
Koşul her zaman karşılanmış olsaydı, tüm öğeler iç döngüde çizilirdi:
{foreach $items as $item}
<ul>
{iterateWhile}
<li>{$item->name}
{/iterateWhile true}
</ul>
{/foreach}
Sonuç şu şekilde görünecektir:
<ul>
<li>Apple</li>
<li>Banana</li>
<li>PHP</li>
<li>Green</li>
<li>Red</li>
<li>Blue</li>
</ul>
iterateWhile'ın bu şekilde kullanımı nedir? Tablo boş olduğunda ve hiçbir öğe içermediğinde, boş
<ul></ul>
basıldı.
Eğer koşulu {iterateWhile}
etiketinin açılışında belirtirsek, davranış değişir: koşul (ve bir sonraki
öğeye geçiş) iç döngünün sonunda değil başında gerçekleştirilir. Böylece, {iterateWhile}
adresine her
zaman koşulsuz olarak girerken, {iterateWhile $cond}
adresine yalnızca $cond
koşulu
karşılandığında girersiniz. Ve aynı zamanda, bir sonraki öğe $item
adresine yazılır.
Bu, örneğin, her kategorideki ilk öğeyi farklı şekilde oluşturmak istediğimiz bir durumda kullanışlıdır:
<h1>Apple</h1>
<ul>
<li>Banana</li>
</ul>
<h1>PHP</h1>
<ul>
</ul>
<h1>Green</h1>
<ul>
<li>Red</li>
<li>Blue</li>
</ul>
Orijinal kodu, önce ilk öğeyi oluşturacak ve ardından iç döngüde {iterateWhile}
aynı kategorideki diğer
öğeleri oluşturacak şekilde değiştiriyoruz:
{foreach $items as $item}
<h1>{$item->name}</h1>
<ul>
{iterateWhile $item->categoryId === $iterator->nextValue->categoryId}
<li>{$item->name}</li>
{/iterateWhile}
</ul>
{/foreach}
Bir döngü içinde birden fazla iç döngü oluşturabilir ve hatta bunları iç içe geçirebiliriz. Bu şekilde, örneğin alt kategoriler gruplandırılabilir.
Tabloda başka bir sütun olduğunu varsayalım subcategoryId
ve her kategorinin ayrı bir kategoride olmasının
yanı sıra <ul>
her bir alt kategori ayrı bir <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}