PHP ile sınırsız alt kategori mantığı

Date09 / Ağustos / 2008 Author İsa Engiz    Category php     Tags , Yorumlar14 Yorum Yapilmis.

PHP ile yazılan içerik yönetimi uygulamalarının vazzgeçilmez parçasıdır kategorilendirme. Eğer her bir içerik tek bir kategoriye ait olacaksa ve bütün kategoriler birbiri ile aynı önemdeyse kolay şekilde bir kategorilendirme yapabilirsiniz. Ancak kategoriler arasında ast-üst ilişkisi oluşturmaya başladığınızda, yani “alt kategori” mantığına geçtiğinizde aklınıza gelecek ilk soru şu olacaktır: “ne kadar alt kategori olacak?”

Tabi ki alt kategori sayısını belrleyip ona göre uygulamanızı hazırlayabilirsiniz ancak ileride yeni bir alt kategori eklemek isterseniz ne olacak? Bütün uygulamayı baştan yazamayacağınıza göre, hazırladığınız program bir şekilde yeni alt kategoriler eklenmesini destekliyor olmalıdır.

İsterseniz burada böyle bir alt kategorilendirme sistemini nasıl oluşturacağımızı tartışalım. Uygulamamız netice itibariyle sınırsız sayıda alt kategoriyi destekliyor olacak.

Kategoriler tablosu

Kategoriler tablomuz şu şekilde olsun:

id isim ustu
1 dunya null
2 avrupa 1
3 asya 1
4 amerika 1
5 ingiltere 2
6 türkiye 2
7 rusya 3
8 istanbul 6
9 taksim 8

Burada gördüğünüz üzere düşündüğümüz temel mantık şu şekilde, bütün kategorileri tek bir tabloda tutuyoruz, her kategoriye ait bir id bulunmakta (yazıların hangi kategoriye ait olduğunu bu id ile belirtebilirsiniz) ve her kategori için, o kategorinin üstü bulunmakta. Örnek olarak “türkiye” kategorisinin üstü, 2 nolu id’ye sahip olan “avrupa”, yani türkiye, avrupanın alt kategorisi, aynı şekilde istanbul türkiyenin alt kategorisi ve taksim de istanbul’un alt kategorisi.

Bu tablonun sınırsız sayıda alt kategoriye izin verdiğini hemen farkedebilirsiniz, yeni bir alt kategori eklemek için tek yapmanız gereken, o kategorinin bağlanacağı yeri, yani üstünü belirtmek.

Kategorileri Listelemek

Geldik bu kategorileri tablomuzdan nasıl çekeceğimize. Görüldüğü üzere kategoriler belli bir sırayla girilmemiş, bu nedenle bir kategorinin altında yer alan bütün kategorileri listelemek istersek, tüm tabloyu taramamız gerekiyor. Hedefimiz bunu yapacak kodu yazmak!

Mantık

Yazacağımız fonksiyon şu işi yapsın; biz ona alt kategorilerini listeletmek istediğimiz kategorinin id’sini yollayalım, o da bize bütün alt kategorileri yollasın.

Alt kategorileri listeleyecek olan fonksiyon

Sonuç itibariyle aşağıdaki gibi bir fonksiyon yazmış olacağız:

 
function katListele($katid, $onek = 1)
{
	$sql = mysql_query("SELECT * FROM kategoriler WHERE ustu='$katid'");
 
	while($sonuc = mysql_fetch_array($sql))
	{
		if(!empty($sonuc))
		{
			echo str_repeat('#', $onek);
			echo $sonuc['isim'];
			echo '<br />';
			katListele($sonuc['id'], ($onek+1));
		}
	}
}

Ve bu fonksiyonun da kullanım şekli aşağıdaki gibi olabilir:

mysql_connect('localhost', 'kullaniciadi', 'parola') or die('vertabanı bağlantı hatası');
mysql_select_db('veritabani_ismi') or die('veritabanı seçim hatası');
 
katListele(1);

Ekran çıktısı ise şu şekilde olacaktır:

#avrupa
##ingiltere
##turkiye
###istanbul
####taksim
#asya
##rusya
#amerika

Görüldüğü üzere fonksiyon parametre olarak astlarını istediğiniz kategorinin id’sini alıyor. Biz burada ‘dünya’ kategorisinin idsi olan 1′i gönderdik altındaki bütün kategorileri listelettik.

Fonksiyon kendisine gelen parametreyi alyor ve vertabanından o kategorinin astlarını çekiyor, yalnız astlarını çekerken, bu kategorinin de astı varmı diye kontrol ediyor, varsa fonksiyon kendisini tekrar çağırıyor. Kendisini çağırırken ise $onek değişkenini yolluyor, bu değişkenin yaptığı iş, kategori ismini yazdırırken başında derinliğini belirtecek bir işaret koymak: ‘#’ Böylece ekran çıktısında olduğu gibi hangi kategori hangiisinin altında, rahatlıkla belli oluyor.

Bir adım ileri

Yazdığımız fonksiyon bu şekilde de işimizi görecektir ama fonksiyonu çağırır çağırmaz ekrana direkt olarak yazdırması pek kullanışlı olmayabilir. Bu noktada bir adım daha atalım ve fonksiyonumuzu daha kullanışlı hale getirecek bir kaç değişiklik yapalım:

 
function katListele($katid, $onek = 1, $x='')
{
	$sql = mysql_query("SELECT * FROM kategoriler WHERE ustu='$katid'");
 
	while($sonuc = mysql_fetch_array($sql))
	{
		if(!empty($sonuc))
		{
			$x = $x.str_repeat('#', $onek).$sonuc['isim'].'&';
			$x = katListele($sonuc['id'], ($onek+1), $x);
		}
	}
	return $x;
}

Burada yaptığımız temel değişiklik, fonksiyonun ekrana bir şey yazmak yerine sonucu $x değişkenine eklemesi. Böylece $x değişkeni bütün kategorileri ‘&’ işaretiyle ayrılmış şekilde tutuyor olacak.

bu fonksiyonun kullanım şekli ise şöyle olabilir:

$satir = katListele($katid);
$dizi = explode('&', $satir);
unset($dizi[count($dizi)-1]);
echo '<pre>';
print_r($dizi);
echo '< /pre>';

Fonksiyonun gönderdiği sonucu $satir değişkenine yüklüyoruz ve ‘&’ karakterine göre ayırdığımızda karşımıza kategoriler dizi değişkeni çıkıyor:

Array
(
[0] => #avrupa
[1] => ##ingiltere
[2] => ##turkiye
[3] => ###istanbul
[4] => ####taksim
[5] => #asya
[6] => ##rusya
[7] => #amerika
)

Artık bu dizi değişkenini istediğimiz şekilde işlemlerde kullanabiliriz, direkt olarak ekrana yazdırmamıza gerek kalmadı.

Bir adım daha ileri gitmek

“Teknolojinin gelişmesi tembel insanlar yüzündendir” desek yanlış demiş olmayız, bu fonksiiyonu her çağırışımızdan sonra geri dönen yazıyı explode() fonksiyonu ile dizi haline getirmek pek kullanışlı olmayabilir, o halde bunun içinde bir fonksiyon hazırlayalım ve sadece o fonksiyonu çağırarak kategoriler dizisine erişelim:

function kategoriDizisiVer($katid)
{
	$satir = katListele($katid);
	$dizi = explode('&', $satir);
	unset($dizi[count($dizi)-1]);
	return $dizi;
}

Gördüğünüz gibi tüm işi yapan kategoriDizisiVer() fonksiyonu da hazırlamış olduk, sonuç itibariyle sınırsız sayıda alt kategorisi olabileceğini varsaydığımız bir kategorinin bütün astlarını listeletmek istersek şu şekilde kullanacağız:

 
$kategoriler = kategoriDizisiVer(1);
print_r($kategoriler);

Sonuç

Özetlemek gerekirse, yaptığımız ilk iş bütün kategorileri tek bir tabloda topluyoruz ve her kategorinin üstünü belirtiyoruz. Daha sonra bir kategorinin altında yer alan bütün kategorileri çekmek için hazırladığımız fonksiyonu çağırıyoruz ve bu fonksiyon bize alt kategorileri bir dizi şeklinde döndürüyor.

Dönen bu diziyi ne yapacaksınız? Aslında orası size kalmış, ne yaparsanız yapın! Değerlerin başında yer alan ‘#’ karakterinin sayısını değerlendirerek ve < li> < /li> etiketlerini kullanarak bir kategori ağacı oluşturabilirsiniz, menü hazırlayabilirsiniz, ‘#’ karakterini hizalamada (intendation) kullanabilirsiniz. Tabi ekrana yazdırırken str_replace() ile # karaterlerinden temizlemeyi unutmayın!

Bir sonraki PHP yazımızda görüşmek üzere.

- Bu blogda yer alan yazıları RSS ile takip edebilirsiniz. RSS aboneliği için tıklayın.

- Ya da bu blogda yer alan bütün yazıları içindekiler sayfasında görüntüleyebilirsiniz. Tıklayın!

PHP ile sınırsız alt kategori mantığı yazısına 14 Yorum yapılmış.

  • melan 09 Ağustos 2008, 20:39

    teşekkürler kodla.net tam aradığım bir şey

  • İsa Engiz 10 Ağustos 2008, 10:07

    İlginiz için teşekkürler, ama koodla.com demek istediniz galiba :)

  • eburhan 10 Ağustos 2008, 15:03

    Buna “rekürsif kategorileme” deniliyordu sanırım. Kolay bir yöntem fakat birçok kişi tarafından, fazla SQL sorgulaması yapmasından dolayı bu yöntem yavaş bulunuyor. (burada birçok farklı yöntem var)

    Fakat bu yöntem kullanılsa bile mutlaka “data serialization” ve “caching” kullanılarak kategorileri bir önbellek dosyasına kaydetmek lâzım ki bunu yapmak kritik derecede önemli. Sonuçta kategoriler her zaman değişen şeyler değil :)

    Yazı için de teşekkürler. Gerçekten güzel konulara değiniyorsunuz.

  • melan 11 Ağustos 2008, 18:04

    @İsa Engiz kusura bakma yanlışlık oldu…

  • point3r 17 Ekim 2008, 02:02

    Teşekkürler, php rekürsif fonksiyonlarda stack yapısı kullanmıyor yanılmıyorsam, php de ki rekürsif yapısını açıklayabilirmisiniz.

  • serkan 25 Ekim 2008, 19:06

    Bir adım ileri
    kısmı bende calısmadı sornasınıda denemedin zaten :p

  • Murat Gazioğlu 06 Kasım 2008, 18:49

    şöyle birşeye ne dersiniz, tek bir sql sorgusu ile tüm kategorileri alalım , bir sınıfa yada çok boyutlu diziye tamponlayalım. Sonra istediğimiz noktada dizi yada sınıfı çağıralım.
    Basitçe ;

    id = $sonuc['id'];
    $k[$s]->isim = $sonuc['isim'];
    $k[$s]->ustu = $sonuc['ustu'];
    $s++;
    }
    mysql_free_result($sorgu);
    unset($sonuc);
    ?>

    Artık elimizde bir nesne dizisi ($k) var, istediğimiz ana kategorinin alt kategorilerine ulaşabilir, istediğimiz gibi ekrana basabilir, istediğimiz gibi sıralayabiliriz.Tabi tek bir sorgu ile.
    Ama asıl önemli olan veritabanında ebeveyn bağı ile kategorileri birbirine bağlamak, bu mantığı bildikten sonra elli şekilde ekrana basarsın.
    Askerde her alt dal için yeni tablo yaratan programcılar görmüştüm, komikti :)

  • İsa Engiz 07 Kasım 2008, 10:01

    Kulağa daha hoş geliyor ;)

  • Murat Gazioğlu 07 Kasım 2008, 13:18

    kodum kırılmış tam çıkmamış ne yazıkki, veritabanından bakarsan sanırım orada kodun full hali olmalı, arada php tagları olduğu için ekrana basarken kırılıyor olmalı.

  • serkan ak 27 Şubat 2009, 14:18

    function kategoriDizisiVer($katid)
    {
    $satir = katListele($katid);
    $dizi = explode(‘&’, $satir);
    unset($dizi[count($dizi)-1]);
    return $dizi;
    }

  • ozi 07 Mart 2009, 15:28

    bilgi için teşekkürler, konu biraz eskimiş ama bu tabloya aşağıdaki gibi yeni kategori eklerken sorun yaşıyorum yardımcı olursanız sevinirim,

    // ekleme formu
    $kat_sorgu = mysql_query(“SELECT * FROM kategoriler ORDER BY id”);
    while ($yaz = mysql_fetch_array($kat_sorgu)) {

    $kategorilerr .= “”. $yaz['isim'] .”";

    }
    ?>

    Üst Kategori Seç

    Kategori Seç :

    Alt Kategori Adı

    Ekle

    // ekleme formu onay

    $id = $_REQUEST["id"];
    $isim = $_REQUEST["isim"];
    $ustu = $_REQUEST["ustu"];

    $yaz= mysql_query(“INSERT INTO kategoriler (id, isim, ustu) values (‘$id’,'$isim’,'$ustu’)”);

    if (! $yaz) {

    echo “Hata. Bilgleri Ekelenemedi”;
    }else
    {
    echo “Bilgileriniz Veri Tabanına Kaydedildi.”;
    }

  • uskudar12 09 Mayıs 2009, 00:49

    herşey güzel peki bu kategorileri ve bağlı alt kategorileri nasıl sileceğiz

  • İsa Engiz 10 Mayıs 2009, 16:33

    delete from kategoriler where id = 5 and ustu = 5

  • omer 31 Ocak 2010, 16:29

    delete from kategoriler where id = 5 and ustu = 5

    sanırım küçük bi hata yaptınız AND yerine OR olacak

    DELETE FROM kategoriler WHERE id = 5 OR ustu = 5

    mantığa göre id si 5 olan ve kategorisi 5 olan bi satır olmayacaktır.

    tabi ustu 5 olanlarında birer alt kategorileri varsa yani ustu 5 olanların id leri 6-7-8 olursa ustu 6 ,7,8 olan id leride silmesi lazım ki onlarında alt kategorilere sahip olduklarını varsayarsak biraz kompleks bir kod yazmak gerekebilir.

    yani tek satırda olmayacaktır zamanım yok şu an aklıma gelen en basit çözümü anlatayım çözüm denebilirse

    SELECT id FROM kategoriler WHERE ust=5

    sonra burdan çıkan id iler ile tekrar sorgulattırabilirsiniz 6-7-8 olduğunu var sayalım

    SELECT id FROM kategoriler WHERE ust=6 OR ust=7 OR ust=8

    burdanda id ler çıkacaktır . sorgudan sıfır satır dönene kadar yani id değeri çıkmayıncaya

    kadar bu şekilde tüm id leri toplayıp en son o id ler ile silme işlemi yapabilirsiniz .

    DELETE FROM kategoriler WHERE id =5 OR ust=6 OR ust=7 OR ust=8 OR …

    bu en basit hali SQL i derinlemesine bilirseniz daha güzel çözümler çıkacaktır..

görüşünü belirt

Spam Protection by WP-SpamFree

Arama


E-Posta Aboneliği


RSS Aboneliği

En Çok Yorumlanan Yazılar

Etiketler

404 ajax apache arama butonu as astrofizik açık kaynak banner blogger blogger/blogspot Blogger / Blogspot blogspot case chmod css date dosya yükleme editör etiket etkinlik favicon featured form ftp galeri Genel gimp hata sayfası header htaccess htpasswd ilişkisel veritabanı index innodb javascript join JQuery kategori koodla linux mysql opacity php resim url

Son Yorumlar

  • isa engiz: Yazı için teşekkürler. sabit ip 2.75 tl. bu ücreti verip kendi web sunucumuzu kurabiliriz… En yakın...
  • osman: Yazı için teşekkürler. Pardus projesinin Türkiye için çok önemli olduğunu düşünüyorum. Ancak yazıda da...
  • Mustinet: siblings kullanarak da yazılabilir. Teşekkürler
  • is: CSS kullanmadan sadece HTML kodlarıyla yanyana iki sütun (tablo kullanmadan) oluşturulabilir mi?
  • Doğan Yılmaz: verdiğiniz bilgiler için çok ama çok teşekkür ederim. artık sıkı bir takipçiniz olmaya karar verdim

Sayfalar


Faydalı Bağlantılar