Salı, Ağustos 03, 2010

Adjacency List Model Veri Tabanlarından Veri Çekme

Forumlarda veya sitelerde sıklıkla rastlarsınız bu modele ama bende olduğu gibi bir gün kullanmanız gerekene kadar bunun farkına varmazsınız :) "HİYERARŞİK" sistemlerden bahsediyorum. Bunlara menulerde,forumlardaki yorum larda rastlarsınız. Kafanızda canlanması açısından soy ağacını düşünebilirsiniz.

Bense bu tip bir yapıyla fakültemizin(Necatibey Eğitim Fakültesi) web sitesinin menülerini veri tabanından çekmeye kararverince karşılaştım. Google'da bir kaç siteyi ziyaret ettikten sonra Adjacency List Model kullanarak bunu yapa bileceğimi öğrendim. Tabi burda mesele bu modele uygun veri tabanı oluşturmak değil. PHP ile veriyi, kullandığımız javascript menüsünün html yapısına uygun bir şekilde çekmek. İşin içine yeni yeni öğrenmeye başladığımız Zend Framework de girince olayın rengi iyice değişti.

Menu olarak mootools js kütüphanesi kullanarak yapılmış "Menumatic"'i kullandık. Menünün html yapısı aşağıdaki gibi:


<ul id="nav">
<li><a href="#" >Link 1</a></li>
<li><a href="#" >Link 2</a>
<ul>
<li><a href="#" >Link3</a></li>
<li><a href="#" >Link4</a>
<ul>
<li><a href="#" >Link5</a></li>
<li><a href="#" >Link6</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#" >Link 7</a></li>
</ul>



Bu şekilde tagları oluşturacak recursive bir fonksiyon yazarak veri tabanından menü adlarını çekebiliriz. Bunun için veri tabanında 4 alanı olan bir tablo oluşturuyoruz. Bunlar "id,menu_adi,aitik,sira". Burada bizim için önemli olan "aitlik" alanı. Buraya, ilgili menü hangi menünün alt menüsü ise onun id si yazılır. Örneğin:


+----+----------------------+-----------+----+
| id | menu_adi | aitlik |sira|
+----+----------------------+-----------+----+
| 1 | Anasayfa | -1 | 1 |
| 2 | Hızlı Erişim | -1 | 3 |
| 3 | İletişim | -1 | 2 |
| 4 | Bilgi Edinme | 3 | 1 |
| 5 | Foto Galeri | 2 | 1 |
| 6 | Faydalı Linkler | 2 | 2 |
| 7 | Asd | 6 | 2 |
| 8 | Dsa | 6 | 1 |
+----+----------------------+-----------+----+

Tabloda "Foto Galerinin" aitliği 2=> 2 numaralı id kime ait "Hızlı Erişim"=> Demekki "Foto Galeri" "Hızlı Erişim" menüsünün alt menüsü.

Sıra alanı ise menülerden hangilerinin önce ve sonra gösterileceğine karar vermek için. "Asd" ve "Dsa" aynı menünün alt menüleri. İlk sırada "sira" alanıdaki değeri 1 olan Dsa gösterilecek ardında Asd.

Aşağıdaki kod bütün bunları dikkate alarak menüyü oluşturur.


<?php
$baglan = mysql_connect("localhost","root","");
mysql_select_db(
"web", $baglan);
mysql_query(
"set names utf8");

//Herhangi bir linkin alt linkleri varmı diye kontrol eder
function varmisinYokmusun($aitlik)
{
$select =
"select * from menuler where aitlik = $aitlik";
$sorgu = mysql_query($select);
$veri=mysql_fetch_array($sorgu);

//Alt linkleri varsa true yoksa false değerini döndürüyorum
if($veri)
return true;
else
return false;
}

/*$aitliğin varsayılan değerini -1 yapıyoruz.
Bu sayede ana başlıklar görünecek.
Veri tabanında da ana başlıkların aitliklerini -1
olarak atamıştık*/
function menuGetir($aitlik = -1,&$menuler)
{
$select =
"select * from menuler where aitlik = $aitlik order by sira ASC";
$sorgu = mysql_query($select);
while($veri=mysql_fetch_array($sorgu))
{
$menuler .=
"<li><a href='#'>".$veri['menu_adi']."</a>\n";
if(varmisinYokmusun($veri['id']))
{
//Varım diyor
$menuler .=
"<ul>\n";
menuGetir($veri['id'],$menuler);
$menuler .=
"</ul>\n</li>\n";
}
else
{
//Yokum diyorrrrrrrrrrr
$menuler .=
"</li>\n";
}
}
}
?>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server" >
<title>MenuMatic Horizontal Example</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

<link rel="stylesheet" href="css/MenuMatic.css" type="text/css" media="screen" charset="utf-8" />
<!--[if lt IE 7]>
<link rel="stylesheet" href="css/MenuMatic-ie6.css" type="text/css" media="screen" charset="utf-8" />
<![endif]-->

<!-- Load the Mootools Framework -->
<script src="http://www.google.com/jsapi"></script><script>google.load("mootools", "1.2.1");</script>

<!-- Load the MenuMatic Class -->
<script src="js/MenuMatic_0.68.3.js" type="text/javascript" charset="utf-8"></script>

<!-- Create a MenuMatic Instance -->
<script type="text/javascript" >
window.addEvent('domready', function() {
var myMenu = new MenuMatic();
});
</script>

<!-- begin google tracking code -->
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape(
"%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
</head>
<body>

<div id="container" >
<ul id="nav">
<?php
$menuler="";
menuGetir(-1,$menuler);
echo $menuler;
?>
</ul>
</div>

</body>
</html>



Bu kodun şöyle bir dezavantajı var her bir menü için yeni bir sorgu gönderiyor. Buda cache kullanımı açısından iyi bir yöntem değil. Ben çok fazla menü başlığı olmadığından kullanmayı tercih ettim. Örneğin forumlardaki yorum seçeneklerini düşünürsek. Her bir konunun bir çok yorumu olabilir. Hatta yorumun yorumununda bir çok yorumu olabilir. Böyle bir durumda bu Adjacency List Model sakıncalı. Peki böyle bir durumda ne kullanabilir derseniz "Nested Set" veri tabanı modeli işinizi görecektir. İleriki zamanlarda onunla da ilgili bir yazı yazmayı düşünüyorum.

"Adjacency List" veri tabanı modelinini ise şöyle bir avantajı var. Veri tabanını hazırlaması kolay. "Nested Set" lerde bu iş birazdaha komplex.

Bu yazınında sonuna gelmiş bulunmaktayız. Örneğin çalışır halini aşağıdaki linkten indirebilirsiniz. Kolay gelsin...

Örnek Uygulama: Adjacency List Model

4 yorum:

Mehmet Emin KORKUSUZ dedi ki...

Çok güzel bir yazı olmuş. Geliştirip diğer modelleri ve uygulamalarını da anlatırsan çok memnun olurum :)

Esat ARSLAN dedi ki...

Sağolun hocam :). Nested set ve bunlara veri eklemeyle ilgili bir iki yazı daha yazmayı düşünüyorum.

Unknown dedi ki...

dostum aşağıdaki linkteki bilgiler için teşekkür ederim..
http://forum.ceviz.net/php/97629-sin...akkinda-3.html (sınırsız kategori listeleme, CSS menüye entegresi hakkında ??)

fakat menumatic yerleşimini yapamıyorum. menumatici tablonun içine koyup sayfanın istediğim kısmına yerleştiremiyorum. sayfayı boyutlandırdığımda menumatic in yeri değişiyor. tablodan taşıyor filan.

bu menumatic i istediğim tablonun içine istediğim yere sabitleyemezmiyiz.

Esat ARSLAN dedi ki...

@Dogan
Ben hiç tablo içinde kullanmayı denemdim. Div lerle çalıştım. Div kullanarak nasıl oynatbilirim dersen MenuMatic.css dosyasında #nav id sini bulup onda değişiklik yapabilirsin.

css dosyasında #nav başka id ler ilede kullanılmış durumda. Tek başına kullanılan da değişiklik yapman gerekli. Paylaştığım örnek te #nav için deki kodlar aşağıdaki şekilde. Zaten başında "/* main menu ul or ol elment */" gibi bir açıklama var.

#nav{
display:block;
position: absolute;
list-style:none;
margin:0 0 0 0;
z-index:5;
top:15px;
left:50%;
text-align: center;
display:block;
}