Gruplama Hakkında Bilmek İstediğiniz Her Şey
Şablonlardaki verilerle çalışırken, bunları belirli kriterlere göre gruplama veya özel olarak görüntüleme ihtiyacıyla sık sık karşılaşabilirsiniz. Latte bu amaçla birkaç güçlü araç sunar.
|group
filtresi ve fonksiyonu, verileri belirtilen kritere göre verimli bir şekilde gruplamayı sağlar,
|batch
filtresi verileri sabit boyutlu gruplara ayırmayı kolaylaştırır ve {iterateWhile}
etiketi,
koşullarla döngülerin ilerleyişini daha karmaşık bir şekilde kontrol etme imkanı sunar. Bu etiketlerin her biri, verilerle
çalışmak için özel seçenekler sunar, bu da onları Latte şablonlarında bilgilerin dinamik ve yapılandırılmış bir
şekilde görüntülenmesi için vazgeçilmez araçlar haline getirir.
group
Filtresi ve Fonksiyonu
Kategorilere ayrılmış öğeleri içeren bir items
veritabanı tablosu hayal edin:
id | categoryId | name |
---|---|---|
1 | 1 | Apple |
2 | 1 | Banana |
3 | 2 | PHP |
4 | 3 | Green |
5 | 3 | Red |
6 | 3 | Blue |
Latte şablonu kullanarak tüm öğelerin basit bir listesi şöyle görünür:
<ul>
{foreach $items as $item}
<li>{$item->name}</li>
{/foreach}
</ul>
Ancak öğelerin kategoriye göre gruplar halinde düzenlenmesini isteseydik, her kategorinin kendi listesine sahip olacak şekilde onları bölmemiz gerekirdi. Sonuç şöyle görünmelidir:
<ul>
<li>Apple</li>
<li>Banana</li>
</ul>
<ul>
<li>PHP</li>
</ul>
<ul>
<li>Green</li>
<li>Red</li>
<li>Blue</li>
</ul>
Görev, |group
kullanarak kolayca ve zarif bir şekilde çözülebilir. Parametre olarak categoryId
belirtiriz, bu da öğelerin $item->categoryId
değerine göre daha küçük dizilere bölüneceği anlamına
gelir (eğer $item
bir dizi olsaydı, $item['categoryId']
kullanılır):
{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, bu da bize alternatif bir sözdizimi sunar:
{foreach group($items, categoryId) ...}
.
Öğeleri daha karmaşık kriterlere göre gruplamak istiyorsanız, filtre parametresinde bir fonksiyon kullanabilirsiniz. Örneğin, öğeleri ad uzunluğuna göre gruplamak şöyle görünür:
{foreach ($items|group: fn($item) => strlen($item->name)) as $items}
...
{/foreach}
$categoryItems
'ın sıradan bir dizi değil, bir iteratör gibi davranan bir nesne olduğunu unutmamak önemlidir.
Grubun ilk öğesine erişmek için first()
fonksiyonunu
kullanabilirsiniz.
Verileri gruplamadaki bu esneklik, group
'u Latte şablonlarında verileri sunmak için son derece kullanışlı
bir araç haline getirir.
İç İçe Döngüler
Tek tek öğelerin alt kategorilerini tanımlayan ek bir subcategoryId
sütununa sahip bir veritabanı tablomuz
olduğunu varsayalım. Her ana kategoriyi ayrı bir <ul>
listesinde ve her alt kategoriyi ayrı bir iç içe
<ol>
listesinde görüntülemek istiyoruz:
{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 Database ile Bağlantı
Veri gruplamayı Nette Database ile birlikte nasıl verimli bir şekilde kullanacağımızı gösterelim. Giriş örneğindeki
items
tablosuyla çalıştığımızı varsayalım, bu tablo categoryId
sütunu aracılığıyla şu
categories
tablosuna bağlıdır:
categoryId | name |
---|---|
1 | Fruits |
2 | Languages |
3 | Colors |
items
tablosundaki verileri Nette Database Explorer kullanarak $items = $db->table('items')
komutuyla okuruz. Bu veriler üzerinde iterasyon yaparken, $item->name
ve $item->categoryId
gibi
niteliklere erişmenin yanı sıra, categories
tablosuyla olan bağlantı sayesinde ilgili satıra
$item->category
üzerinden de erişebiliriz. Bu bağlantı üzerinde ilginç bir kullanım gösterilebilir:
{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, |group
filtresini yalnızca categoryId
sütununa göre değil, bağlantılı
$item->category
satırına göre gruplamak için kullanıyoruz. Bu sayede, anahtar değişkeninde doğrudan ilgili
kategorinin ActiveRow
'unu alırız, bu da bize doğrudan {$category->name}
kullanarak adını
yazdırmamızı sağlar. Bu, gruplamanın şablonları nasıl netleştirebileceğine ve verilerle çalışmayı nasıl
kolaylaştırabileceğine dair pratik bir örnektir.
|batch
Filtresi
Filtre, bir öğe listesini önceden belirlenmiş sayıda öğe içeren gruplara ayırmayı sağlar. Bu filtre, verileri daha iyi netlik veya sayfada görsel düzenleme gibi nedenlerle birden fazla küçük grupta sunmak istediğiniz durumlar için idealdir.
Bir öğe listemiz olduğunu ve bunları her biri en fazla üç öğe içeren listelerde görüntülemek istediğimizi
varsayalım. |batch
filtresinin kullanımı bu durumda çok pratiktir:
<ul>
{foreach ($items|batch: 3) as $batch}
{foreach $batch as $item}
<li>{$item->name}</li>
{/foreach}
{/foreach}
</ul>
Bu örnekte, $items
listesi daha küçük gruplara ayrılmıştır ve her grup ($batch
) en fazla üç
öğe içerir. Her grup daha sonra ayrı bir <ul>
listesinde görüntülenir.
Son grup istenen sayıya ulaşmak için yeterli öğe içermiyorsa, filtrenin ikinci parametresi bu grubun neyle tamamlanacağını tanımlamanıza olanak tanır. Bu, eksik bir sıranın düzensiz görünebileceği yerlerde öğeleri estetik olarak hizalamak için idealdir.
{foreach ($items|batch: 3, '—') as $batch}
...
{/foreach}
{iterateWhile}
Etiketi
|group
filtresiyle çözdüğümüz aynı görevleri {iterateWhile}
etiketini kullanarak
göstereceğiz. İki yaklaşım arasındaki temel fark, group
'un önce tüm giriş verilerini işlemesi ve
gruplaması, {iterateWhile}
'ın ise koşullarla döngülerin ilerleyişini kontrol etmesi, böylece iterasyonun
aşamalı olarak gerçekleşmesidir.
Önce iterateWhile kullanarak kategorilerle tabloyu oluşturalım:
{foreach $items as $item}
<ul>
{iterateWhile}
<li>{$item->name}</li>
{/iterateWhile $item->categoryId === $iterator->nextValue->categoryId}
</ul>
{/foreach}
{foreach}
döngünün dış kısmını, yani her kategori için listelerin oluşturulmasını işaret ederken,
{iterateWhile}
etiketi iç kısmı, yani tek tek öğeleri işaret eder. Bitiş etiketindeki koşul, tekrarın
geçerli ve sonraki öğe aynı kategoriye ait olduğu sürece ($iterator->nextValue
sonraki öğe) devam edeceğini söyler.
Koşul her zaman karşılanırsa, iç döngüde tüm öğeler oluşturulur:
{foreach $items as $item}
<ul>
{iterateWhile}
<li>{$item->name}
{/iterateWhile true}
</ul>
{/foreach}
Sonuç şöyle görünecektir:
<ul>
<li>Apple</li>
<li>Banana</li>
<li>PHP</li>
<li>Green</li>
<li>Red</li>
<li>Blue</li>
</ul>
Böyle bir iterateWhile kullanımının ne faydası var? Tablo boşsa ve hiçbir öğe içermiyorsa, boş
<ul></ul>
yazdırılmaz.
Açılış etiketinde {iterateWhile}
bir koşul belirtirsek, davranış değişir: koşul (ve sonraki öğeye
geçiş) iç döngünün sonunda değil, başında zaten yürütülür. Yani, koşulsuz {iterateWhile}
'a her zaman
girilirken, {iterateWhile $cond}
'a yalnızca $cond
koşulu karşılandığında girilir. Ve aynı
zamanda, sonraki öğe $item
'a yazılır.
Bu, örneğin her kategorideki ilk öğeyi farklı bir şekilde, örneğin şöyle 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ç {iterateWhile}
döngüsünde aynı kategoriden
diğer öğeleri oluşturacak şekilde değiştiririz:
{foreach $items as $item}
<h1>{$item->name}</h1>
<ul>
{iterateWhile $item->categoryId === $iterator->nextValue->categoryId}
<li>{$item->name}</li>
{/iterateWhile}
</ul>
{/foreach}
Tek bir döngü içinde birden fazla iç döngü oluşturabilir ve hatta bunları iç içe geçirebiliriz. Bu şekilde alt kategoriler vb. gruplandırılabilir.
Tabloda ek bir subcategoryId
sütunu olduğunu ve her kategorinin ayrı bir <ul>
içinde
olmasının yanı sıra, her alt kategorinin ayrı bir <ol>
içinde olacağını varsayalım:
{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}