PHP ile sınırsız alt kategori mantığı
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.
- 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ış.
görüşünü belirt
Arama
E-Posta Aboneliği
RSS Aboneliği
En Çok Yorumlanan Yazılar
- Blogger’da “devamını oku” bağlantısı (21)
- Ajax ile dinamik listeleme (21)
- MySQL’de Transaction ve PHP ile kullanımı (16)
- PHP ile sınırsız alt kategori mantığı (14)
- Kullanıcı dostu url hazırlamak (12)
- PHP’nin (muhtemelen) az bilinen 10 özelliği (12)
- Kullandığınız programlama dili ne kadar popüler? (12)
- MySQL’de “join” kullanımı (11)
- .htaccess konuları [Giriş] (11)
- Blogger’da arama kutusu ekleme (10)
Etiketler
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
09 / Ağustos / 2008
teşekkürler kodla.net tam aradığım bir şey
İlginiz için teşekkürler, ama koodla.com demek istediniz galiba
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.
@İsa Engiz kusura bakma yanlışlık oldu…
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.
Bir adım ileri
kısmı bende calısmadı sornasınıda denemedin zaten :p
şö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
Kulağa daha hoş geliyor
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ı.
function kategoriDizisiVer($katid)
{
$satir = katListele($katid);
$dizi = explode(‘&’, $satir);
unset($dizi[count($dizi)-1]);
return $dizi;
}
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.”;
}
herşey güzel peki bu kategorileri ve bağlı alt kategorileri nasıl sileceğiz
delete from kategoriler where id = 5 and ustu = 5
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..