Display a hierarchical menu using php


<?php
// mock result set
$rows = array(
	array(
		'id'=>1
		,'parent_id'=>null
		,'name'=>'Home'
	)
	,array(
		'id'=>2
		,'parent_id'=>null
		,'name'=>'About'
	)
	,array(
		'id'=>3
		,'parent_id'=>2
		,'name'=>'Me'
	)
	,array(
		'id'=>4
		,'parent_id'=>2
		,'name'=>'Company'
	)
	,array(
		'id'=>5
		,'parent_id'=>null
		,'name'=>'Portfolio'
	)
	,array(
		'id'=>6
		,'parent_id'=>5
		,'name'=>'Web'
	)
	,array(
		'id'=>7
		,'parent_id'=>5
		,'name'=>'Writing'
	)
	,array(
		'id'=>8
		,'parent_id'=>6
		,'name'=>'Design'
	)
	,array(
		'id'=>9
		,'parent_id'=>6
		,'name'=>'Programming'
	)
);

/*
UNTESTED

$rows = array();
$sql = 'SELECT * FROM {table}'; -- replace * with proper columns and {table} w/ table name
$result = mysql_query($sql);
while($row = mysql_fetch_assoc($result) ) {
	$rows[] = $row;
}
*/

// covert raw result set to tree
$menu = convertAdjacencyListToTree(null,$rows,'id','parent_id','links');
// echo '<pre>',print_r($menu),'</pre>';

// display menu
echo themeMenu($menu,1);

/*
* ------------------------------------------------------------------------------------
* Utility functions
* ------------------------------------------------------------------------------------
*/

/*
* Convert adjacency list to hierarchical tree
*
* @param value of root level parent most likely null or 0
* @param array result
* @param str name of primary key column
* @param str name of parent_id column - most likely parent_id
* @param str name of index that children will reside ie. children, etc
* @return array tree
*/
function convertAdjacencyListToTree($intParentId,&$arrRows,$strIdField,$strParentsIdField,$strNameResolution) {
			
	$arrChildren = array();
			
	for($i=0;$i<count($arrRows);$i++) {
		if($intParentId === $arrRows[$i][$strParentsIdField]) {
			$arrChildren = array_merge($arrChildren,array_splice($arrRows,$i--,1));
		}
	}
			    
	$intChildren = count($arrChildren);
	if($intChildren != 0) {
		for($i=0;$i<$intChildren;$i++) {
			$arrChildren[$i][$strNameResolution] = convertAdjacencyListToTree($arrChildren[$i][$strIdField],$arrRows,$strIdField,$strParentsIdField,$strNameResolution);
		}        
	}
			    
	return $arrChildren;
		
}

/*
* Theme menu
*
* @param array menu
* @param runner (depth)
* @return str themed menu
*/
function themeMenu($menu,$runner) {

	$out = '';
		
	if(empty($menu)) {
		return $out;
	}
		
	$out.='<ul>';
	foreach($menu as $link) {
		$out.= sprintf(
			'<li class="depth-%u">%s%s</li>'
			,$runner
			,$link['name']
			,themeMenu($link['links'],($runner+1))
		);
	}
	
	$out.='</ul>';
	return $out;
	
}

?>

Replace mock result set with the real result set and there you go. Also, Im not sure what the root level parent is in your actual case. In the code I provided its assumed to be null, so that may need to be changed if its 0 or some other value.


// covert raw result set to tree
$menu = convertAdjacencyListToTree(null,$rows,'id','parent_id','links');

The first argument is the value for the root level menu items. So if the actual value is 0 rather than null it would need to be changed to the below instead.


// covert raw result set to tree
$menu = convertAdjacencyListToTree(0,$rows,'id','parent_id','links');