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}
versiyon: 3.0