منبع اصلی نوشتار زیر در این لینک قرار دارد

Mysql Menu قسمت سوم

چند وقت پیش در باره منو و طریقه ایجاد آن با mysql نوشتم. منظورم بیشتر روش دومی بود که معرفی کردم. خودم تا همین روزها نیاز نشده بود که از این منو استفاده کنم، تا امروز برای کاری ار همان پست استفاده کردم. (این وبلاگ بیشتر از هر کسی گویا به درد خودم میخورد) میخواستم از همان کوئری ها استفاده کنم و یک ساختار تشکیل شده از ul و li های تو در تو درست کنم. اول سعی کردم اطلاعات را داخل آرایه بریزم که بعد به صورت html دربیاورم که متوجه شدم دارم لقمه دور سر میچرخانم.
با توجه به اینکه ساختار منو (لطفا پست MySQL , Menu قسمت دوم رو حتما بخونید) دقیقا شبیه ساحتار تو در توی html هست میشه از این خاصیت استفاده کرد :)‌ یعنی اونجا همه منو های یه سمت چپ داشتن یه سمت راست، تو html هم هر تگی یه سمت چپ داره یه سمت راست. من میخوام یه ساختار منوی ساده با ul و li به وجود بیارم طوری که :

  • عنصر دور تا دور فقط یه ul داره.
  • عناصری که زیر مجموعه ندارن دورشون li میفته
  • عناصری که زیر مجموعه دارن هم li میخوان هم ul .
  • اگه آیتمی هیچ زیر منو نداشت اونوقت متن اون آیتم هم نشون داده بشه (شما اینو خودتون میتونید گسترش بدید، یا برای همه منوها آیتم رو نشون بدید، من ترجیح دادم ساده‌تر کار کنم.)

نتیجه خیلی سادست. فقط باید حالات مختلف رو بنویسم.ساختار دیتابیس اینه (مثل مثال قبلی ، فقط فیلد name به صورت unique در اومده برای اینکه توی کد باید به یه چیزی تکیه کرد ;) )

CREATE TABLE IF NOT EXISTS <code>adv_menu</code> (
  <code>id</code> int(11) NOT NULL AUTO_INCREMENT,
  <code>name</code> varchar(60) NOT NULL,
  <code>data</code> varchar(255) NOT NULL,
  <code>lside</code> int(11) NOT NULL,
  <code>rside</code> int(11) NOT NULL,
  PRIMARY KEY (<code>id</code>),
  UNIQUE KEY <code>name</code> (<code>name</code>)
) ENGINE=MyISAM;

اینبار میخوام از PDO استفاده کنم برای اتصال به mysql . ایده خیلی سادست. فقط در نظر بگیرید که همونطور که قبلا گفتم (تو پست قبلی در این مورد)‌ هر منو یه چپ داره یه راست.
خوب چی میشه اگه سمت چپ رو شروع تگ در نظر بگیریم و سمت راست رو پایان تگ؟ چی میشه اگه یه آرایه ایجاد کنیم به تعداد دو برابر آیتمها، با ایندکس ۱ تا دوبرابر آیتمها، بعد تو آرایه ایندکس سمت چپ تگ شروع html رو بذاریم (مثلا یه li یا یه ul بعد یه li یا هر چیز دیگه ای) و در ایندکس سمت راست هم دقیقا پایان همون تگ سمت راست رو (مثلا اینبار /li )، فقط کافیه بدونیم که مثلا آیتم اگه زیر مجموعه نداشت فقط li میخواد (که این فقط در صورتیه که سمت چپی یکی کمتر از سمت راستی باشه) اگه منوی دور تا دوره فقط یه ul میخواد (که خوب این هم سمت چپش همیشه ۱ میشه)‌ و در غیر این صورت ul و li با هم.
خوب این خیلی ساده ایتمهای توی دیتابیس رو تبدیل میکنه به یه ساختار html و کافیه که اینبار فقط این آرایه رو به هم بچسبونیم و در خروجی نشون بدیم.
کد زیر کل این کارها رو به ساده ترین وجهی انجام میده، ولی باز هم جای کار داره، خیلی زیاد هم جای کار داره.

&lt;?php
/*
 * Work on this structure :
CREATE TABLE IF NOT EXISTS <code>adv_menu</code> (
  <code>id</code> int(11) NOT NULL AUTO_INCREMENT,
  <code>name</code> varchar(60) NOT NULL,
  <code>data</code> varchar(255) NOT NULL,
  <code>lside</code> int(11) NOT NULL,
  <code>rside</code> int(11) NOT NULL,
  PRIMARY KEY (<code>id</code>),
  UNIQUE KEY <code>name</code> (<code>name</code>)
) ENGINE=MyISAMs
 */
class MyMenu {
	private $_pdo;
	
	
	public function __construct($pdo){
		$this-&gt;_pdo=$pdo;
	}
	
	public function addTopMenu($name,$data=\'\'){
		try{
			$query=&quot;SELECT MAX(rside) FROM adv_menu&quot;;
			$sth=$this-&gt;_pdo-&gt;query($query);
			$max=intval($sth-&gt;fetchColumn(0));

			$q_name=$this-&gt;_pdo-&gt;quote($name);
			$q_data=$this-&gt;_pdo-&gt;quote($data);
			$left=$max+1;
			$right=$max+2;
			$query=&quot;INSERT INTO adv_menu (name,data,lside,rside) VALUES ($q_name,$q_data,$left,$right)&quot;;
			return $this-&gt;_pdo-&gt;exec($query);
		}catch (PDOException $e){
			echo &quot;failed : &quot; . $e-&gt;getMessage();
		}
	}
	
	public function insertInside($root,$name,$data){
		try {
			$query=&quot;SELECT rside FROM adv_menu WHERE name = &quot;.$this-&gt;_pdo-&gt;quote($root);
			$sth=$this-&gt;_pdo-&gt;query($query);
			$lside=intval($sth-&gt;fetchColumn(0));
			
			if (!$lside) return false; //Fail! no root menu
			
			//Its time to update...
			$query=&quot;UPDATE adv_menu SET lside=lside+2 WHERE lside&gt;=$lside&quot;;
			$this-&gt;_pdo-&gt;exec($query);
			$query=&quot;UPDATE adv_menu SET rside=rside+2  WHERE rside&gt;=$lside&quot;;
			$this-&gt;_pdo-&gt;exec($query);	
			
			//Now real insert..	
			$rside=$lside+1;
			$q_name=$this-&gt;_pdo-&gt;quote($name);
			$q_data=$this-&gt;_pdo-&gt;quote($data);	
			$query=&quot;INSERT INTO adv_menu (name,data,lside,rside) VALUES ($q_name,$q_data,$lside,$rside)&quot;;
			return $this-&gt;_pdo-&gt;exec($query);
		}catch (PDOException $e){
			echo &quot;failed : &quot; . $e-&gt;getMessage();
		}		
	}
	
	public function createMenu($parentTags,$parentClasses,$subParentTags,
						$subParentClass,$itemTags,$itemClass){
		//Parent tag ..
		$parentTagStart=$parentTagEnd=\'\';
		foreach ($parentTags as $id=&gt;$Tag){
			$ClassFull=($parentClasses[$id])?&quot; class=\'$parentClasses[$id]\' &quot;:\'\';
			$parentTagStart.=&quot;&lt;$Tag$ClassFull&gt;&quot;;
			$parentTagEnd=&quot;&lt;/$Tag&gt;&quot;.$parentTagEnd;
		}
		//Sub parent tag ..
		$subParentTagStart=$subParentTagEnd=\'\';
		foreach ($subParentTags as $id=&gt;$Tag){
			$ClassFull=($subParentClass[$id])?&quot; class=\'$subParentClass[$id]\' &quot;:\'\';
			$subParentTagStart.=&quot;&lt;$Tag$ClassFull&gt;&quot;;
			$subParentTagEnd=&quot;&lt;/$Tag&gt;&quot;.$subParentTagEnd;
		}

		//Item tag ..
		$itemTagStart=$itemTagEnd=\'\';
		foreach ($itemTags as $id=&gt;$Tag){
			$ClassFull=($itemClass[$id])?&quot; class=\'$itemClass[$id]\' &quot;:\'\';
			$itemTagStart.=&quot;&lt;$Tag$ClassFull&gt;&quot;;
			$itemTagEnd=&quot;&lt;/$Tag&gt;&quot;.$itemTagEnd;
		}
		$query=&quot;SELECT item.*,(COUNT(parent.name) - 1) AS depth
				FROM adv_menu AS item, adv_menu AS parent
				WHERE (item.lside
				BETWEEN parent.lside
				AND parent.rside)
				GROUP BY item.name
				ORDER BY item.lside&quot;;
		$sth=$this-&gt;_pdo-&gt;query($query);
		$result=array();
		foreach ($sth as $item){
			//Is this a parent?
			if ($item[\'depth\']==0){
				$result[$item[\'lside\']]=$parentTagStart;
				$result[$item[\'rside\']]=$parentTagEnd;
			}elseif (intval($item[\'lside\']+1) &lt; (intval($item[\'rside\']))){//Sub menu but also parent
				$result[$item[\'lside\']]=$subParentTagStart;
				$result[$item[\'rside\']]=$subParentTagEnd;
			}else{//Simple sub menus, use data to create link or more..
				$result[$item[\'lside\']]=$itemTagStart.$item[\'data\'];
				$result[$item[\'rside\']]=$itemTagEnd;				
			}
			
		}
		
		ksort($result);
		return implode(&quot;\\n&quot;,$result);
	}
}


try{
	$pdo=new PDO(\'mysql:dbname=test;host=127.0.0.1\',\'root\',\'bita123\');
}catch (PDOException $e){
	echo &quot;failed : &quot; . $e-&gt;getMessage();
	die();
}
$menu=new MyMenu($pdo);
/*
$menu-&gt;addTopMenu(&quot;Root&quot;,&quot;Root data&quot;);
$menu-&gt;insertInside(&quot;Root&quot;,&quot;Home&quot;,&quot;Home data&quot;);
$menu-&gt;insertInside(&quot;Root&quot;,&quot;Page&quot;,&quot;Page data&quot;);
$menu-&gt;insertInside(&quot;Page&quot;,&quot;PHP&quot;,&quot;PHP data&quot;);
$menu-&gt;insertInside(&quot;PHP&quot;,&quot;GTrans&quot;,&quot;GTrans data&quot;);
$menu-&gt;insertInside(&quot;PHP&quot;,&quot;OS&quot;,&quot;OS data&quot;);
$menu-&gt;insertInside(&quot;Page&quot;,&quot;Delphi&quot;,&quot;Delphi data&quot;);
$menu-&gt;insertInside(&quot;Root&quot;,&quot;Articles&quot;,&quot;Articles data&quot;);
$menu-&gt;insertInside(&quot;Articles&quot;,&quot;SQL&quot;,&quot;SQL data&quot;);
$menu-&gt;insertInside(&quot;Articles&quot;,&quot;Ajax&quot;,&quot;Ajax data&quot;);
$menu-&gt;insertInside(&quot;Ajax&quot;,&quot;Part1&quot;,&quot;Part1 data&quot;);
$menu-&gt;insertInside(&quot;Ajax&quot;,&quot;Part2&quot;,&quot;Part2 data&quot;);


*/
echo $menu-&gt;createMenu(			array(\'ul\'),array(\'parent\'),
								array(\'li\',\'ul\'),array(\'sub-parent\',\'parent-sub\'),
								array(\'li\'),array(\'item\')
						);

البته این یه کلاس کامله برای ثبت منو البته قابلیت حذف رو براش ننوشتم چون وقت نبود :)+



برچسب ها : , ,