I recently had fun with an all-to-common issue with SQL driven websites: hierarchical data. For those who don’t like big words, think trees. Other people have already discussed storage methods, and I would actually highly suggest you read the writeup if you haven’t already.
While it is fairly straightforward to deal with, in our case we use HTML_QuickForm to handle our forms and are using QuickForm’s hierselect to select a category.
The issue starts showing its face in 2 distinct areas: (1) the client is not yet sure how deep they need their categories to go, and (2) the hierselect requires a very specific format of data to be passed in.
<?phpif(intval($depth)<1)$depth=1;$select=array();$from=array();$where=array();$order=array();for($i=1;$i<=$depth;$i++){$select[]="level".$i.".id AS level".$i."_id";$from[]="`categories` AS level".$i."";$where[]="( level".$i.".active = 1 OR level".$i.".active IS NULL )";$order[]="level".$i."_id";}//SELECT$sql="SELECT ".implode(', ',$select).", level".$depth.".title AS title ";//FROM$sql.="FROM ".$from[0]." ";unset($from[0]);if(count($select)>0){foreach($fromas$key=>$value){$from[$key]=$value." ON level".($key).".id = level".($key+1).".parent_id";}$sql.=" RIGHT JOIN ".implode(" RIGHT JOIN ",$from)." ";}//WHERE$sql.="WHERE level1.parent_id IS NULL AND ".implode(" AND ",$where)." ";//ORDER$sql.="ORDER BY ".implode(", ",$order);$rs=$this->query($sql);
The series of ( levelN.active = 1 OR levelN.active IS NULL ) guarantees that only entries with the active field turned on and that children of deactivated categories are not displayed. Fancy piece of SQL-fu if I do say so myself. The data is returned looking something like this:
level1_id level2_id level3_id level4_id level5_id title
You’ll notice that we also insert into our $categories array according to the hierselect format linked above. That in and of itself is an interesting function as, for example, our entry for Great Great Grandchild would look like $categories[4][1][6][8][10][12] = 'Great Great Grandchild'; and we need empty entries for each level.