kreoton web development

[PHP] building recursive menu with MySQL and without it

Today I decided to share with you with two my function that I use in my code to build navigation menu for websites. First function is to build menu formated in PHP array. First we must format our menu in array like this way:

$menu = array(
	'Home' => $base.'/',
	'Videos' => array (
		'_link' => $base.'/videos/',
		'_submenu' => array (
			'Categories' => array (
				'_link' => $base.'/videos/categories',
				'_submenu' => array (
					'Fun videos' => $base.'/videos/categories/fun_videos',
					'Home videos' => $base.'/videos/categories/home_videos',
				),
			),
			'Popular' => $base.'/videos/popular',
			'Best rated' => $base.'/videos/best-rated',
		),
	),
	'Articles' => array (
		'_link' => $base.'/articles',
		'_submenu' => array (
			'Newest' => $base.'/articles/newest',
			'Archive' => $base.'/articles/archive',
		),
	),
	'Contact Us'=> $base.'/contact_us'
);

Variable $base is holding url to our website and is defined like this:

$base = 'http://www.example.com';

Next function witch would parse menu array and return formated html:

function formatMenu ($menu)
{
	// check if given segment is array if not there is nothing to do
	if (!is_array($menu))
		return false;
	//opening base url formating element ul if you like you can applay here style you use for your menu
	$html = '<ul>';
 
	//now we must format each array element
	foreach ($menu as $item => $link)
	{
		//how you see every element witch has submenu has property _link witch hold link base of page section and
		// property _submenu holds submenu links
		if ($item != '_link')
		{
			$html .= '<li>';
			//if element is array, it is a submenu too :)
			if (is_array($link))
			{
				if ($item != '_submenu')
					$html .= '<a href="'.$link['_link'].'">'.$item.'</a>';
				//colling same function where we are (recursive)
				$html .= formatMenu($link['_submenu']);
			}
			else
				$html .= '<a href="'.$link.'">'.$item.'</a>';
			$html .= '</li>';
		}
	}
 
	$html .= '</ul>';
	// at the end we close all opened tags and return what this function has made
	return $html;
}

To format menu call function in this way:

echo formatMenu ($menu);

Next function is used when you are formating menu from database, here is how my database looks:

CREATE TABLE `menu` (
  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `parent_id` int(10) UNSIGNED NOT NULL,
  `title` varchar(255) collate latin1_general_ci NOT NULL,
  `link` varchar(255) collate latin1_general_ci NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `parent_id` (`parent_id`)
);
 
INSERT INTO `menu` (`id`, `parent_id`, `title`, `link`) VALUES 
(1, 0, 'Home', '/'),
(2, 0, 'Videos', '/videos/'),
(3, 2, 'Categories', '/videos/categories/'),
(4, 3, 'Fun Videos', '/videos/categories/fun_videos'),
(5, 3, 'Home videos', '/videos/categories/home_videos'),
(6, 2, 'Popular', '/videos/popular'),
(7, 2, 'Best rated', '/videos/best_rated'),
(8, 0, 'Articles', '/articles/'),
(9, 8, 'Newest', '/articles/newest'),
(10, 8, 'Archive', '/articles/archive'),
(11, 0, 'Contact us', '/contact_us');

For better performance i wrote a function witch fetches data form sql server grab it ;) you can use it everywhere in your code . It returns associative array of data.

$link = false;
global $link; //we should define to avoid establish new connection when one is open
 
function getRows ($sql)
{
	global $link;
	if ($link == false)
	{
		$link = mysql_connect('localhost', 'root', '') or die(mysql_error());
		mysql_select_db('test', $link) or die(mysql_error());
	}
 
	$res = mysql_query($sql) or die(mysql_error());
	if (mysql_num_rows($res) > 0)
	{
		while ($row = mysql_fetch_assoc($res))
		{
			$data[] = $row;
		}
	}
 
	return $data;
}

And finally function witch would do all dirty job for as. I recommend to use some kind of cache system if you want to boost a script generation time and server resources.

function formatSQLMenu ($parent = 0)
{
	//execute query witch will return us part of our menu
	$menu = getRows("SELECT * FROM menu WHERE parent_id = ".(int)$parent);
	if (!is_array($menu))
		return false;
 
	$html = '<ul>';
 
	foreach ($menu as $item)
	{
		$html .= '<li>';
		$html .= '<a href="'.$item['link'].'">'.$item['title'].'</a>';
		//colling same function where we are (recursive) to check if menu item has submenu
		$html .= formatSQLMenu($item['id']);
		$html .= '</li>';
	}
 
	$html .= '</ul>';
	return $html;
}

One Response to “[PHP] building recursive menu with MySQL and without it”


  1. Great howto :D Keep it going! Regards from Serbia

Leave a Reply

This is a captcha-picture. It is used to prevent mass-access by robots. (see: www.captcha.net)

You must read and type the 5 chars within 0..9 and A..F, and submit the form.

  

Oh no, I cannot read this. Please, generate a