1

Problem:

I am trying to build a recursive tree using a function and data from a MySQL. However, the results are not as expected.

PHP code:

function buildTree($root, $next = array()) 
{
 // Sanitize input
 $root = (int) $root;
 // Do query
 $query = "SELECT CID, Item, Parent FROM betyg_category WHERE Status = '1' AND Parent = '{$root}'";
 $result = mysql_query($query) or die ('Database Error (' . mysql_errno() . ') ' . mysql_error());
 // Loop results
 while ($row = mysql_fetch_assoc($result)) 
 {
 $next[$row['CID']] = array (
 'CID' => $row['CID'], 
 'Item' => $row['Item'], 
 'Parent' => $row['Parent'], 
 'Children' => buildTree($row['CID'], $next)
 );
 }
 // Free mysql result resource
 mysql_free_result($result);
 // Return new array
 return $next;
}
$testTree = buildTree(0);
echo "<xmp>".print_r($testTree, true)."</xmp>";

The table in the database look like this:

enter image description here

I would like the array to be like this:

Array
(
 [1] => Array
 (
 [CID] => 1
 [Item] => Litteratur
 [Parent] => 0
 [Children] => Array
 (
 [2] => Integration av källorna
 [3] => Belysning av egna resultat
 [4] => Referenser
 )
 )
 and so forth..
)

That is to say, for each parent => produce children, then move on to next parent, etc. Thank you in advance for any advice.

asked Jun 8, 2012 at 15:45
4
  • 1
    why don't you provide the results your getting so people can see what your currently producing from your code Commented Jun 8, 2012 at 15:50
  • @Lee I would like to but the results just keep looping in all eternity and I have to press escape so the browser won't crash. In other words, the list is too long and I felt it is not adequate to include it. Commented Jun 8, 2012 at 15:51
  • change buildTree($row['CID'], $next) to buildTree($row['CID']) ... now what happens ? Commented Jun 8, 2012 at 15:55
  • How about adding a counter for how many rows have passed, and just return after that point, for debugging purposes. Also, you should really be using prepared statements. I know you're mostly safe from SQL Injection by casting the argument to an integer, but it's the principle of the thing. Also, I'm assuming that php allows you to use whatever for array indicies, or the top level of your array is likely to be too sparse (it's been too long). Commented Jun 8, 2012 at 15:58

3 Answers 3

2

You do not need recursion here. In fact, it will be very inefficent since you end up with a SELECT N+1 issue. Just order the result set by parent:

$query = "SELECT CID, Item, Parent FROM betyg_category WHERE Status = '1' ORDER BY Parent";
$result = mysql_query($query);
$tree = array();
while($row = mysql_fetch_assoc($result)) {
 if($row['Parent'] == 0) {
 $row['Children'] = array();
 $tree[$row['CID']] = $row;
 } else {
 $tree[$row['Parent']]['Children'][] = $row;
 }
}

This will produce the following:

Array
(
 [1] => Array
 (
 [CID] => 1
 [Item] => Litteratur
 [Parent] => 0
 [Children] => Array
 (
 [0] => Array
 (
 [CID] => 2
 [Item] => Integration av källorna
 [Parent] => 1
 )
 [1] => Array
 (
 [CID] => 3
 [Item] => Belysning
 [Parent] => 1
 )
 [2] => Array
 (
 [CID] => 4
 [Item] => Referenser
 [Parent] => 1
 )
 )
 )
 [5] => Array
 (
 [CID] => 5
 [Item] => Validitet
 [Parent] => 0
 [Children] => Array
 (
 [0] => Array
 (
 [CID] => 6
 [Item] => Huvudsyfte
 [Parent] => 5
 )
 )
 )
)

If you only want the name of each children, change, use $tree[$row['Parent']]['Children'][] = $row['Item']; instead.

answered Jun 8, 2012 at 15:53
3
  • This works great, except I had to change it to: $tree[$row['Parent']]['Children'][$row['CID']] = $row['Item']; - but a problem remains. How do I sort the array index and more importantly, the index of Children? Commented Jun 8, 2012 at 16:05
  • @kexxcream How do you want to sort it? Commented Jun 8, 2012 at 16:19
  • I wanted it sorted by index key, but @sephoy08 provided an answer to that problem. Commented Jun 8, 2012 at 16:29
2

Try this one:

$array = array();
while ($row = mysql_fetch_assoc($result)) 
{
 if($row['parent'] == '0')
 {
 $array[$row['parent']] = '';
 $array[$row['parent']]['CID'] = $row['CID'];
 $array[$row['parent']]['Item'] = $row['item'];
 $array[$row['parent']]['Parent'] = $row['parent'];
 $array[$row['parent']]['Children'] = '';
 }
 else
 {
 $array[$row['parent']]['Children'][$row['CID']] = $row['item'];
 }
}
echo "<pre>";
print_r($array);

First in your query. Add ORDER BY CID ASC then

$count = array_keys($array);
foreach($count as $arr)
{
 ksort($array[$arr]['Children']);
}
answered Jun 8, 2012 at 16:05
2
  • Thanks, thanks to @alexn code I managed to arrive at this solution as well. But now I am only missing a way to sort the $array and Children by their index. Commented Jun 8, 2012 at 16:07
  • Great, this works well. I have posted the final solution below. Commented Jun 8, 2012 at 16:28
0

Final solution from all comments:

$query = "SELECT * FROM betyg_category WHERE Status = '1' ORDER BY CID ASC";
$result = mysql_query($query) or die ('Database Error (' . mysql_errno() . ') ' . mysql_error());
$tree = array();
while($row = mysql_fetch_assoc($result)) 
{
 if($row['Parent'] == 0) 
 {
 $row['Children'] = array();
 $tree[$row['CID']] = array(
 'CID' => $row['CID'], 
 'Item' => $row['Item'], 
 'Parent' => $row['Parent']
 );
 } 
 else 
 {
 $tree[$row['Parent']]['Children'][$row['CID']] = $row['Item'];
 }
}
$count = array_keys($tree);
foreach ($count as $array)
{
 ksort($tree[$array]['Children']);
}
echo "<xmp>".print_r($tree, true)."</xmp>";
answered Jun 8, 2012 at 16:27

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.