3

I need to build a table of categories by recursion through an array. It works fine as long as the depth goes deeper but as soon as the depth decreases the HTML output misses the start of a table.

PHP code to build the array:

       if($query->rowCount() > 0) {
        while($result = $query->fetch(PDO::FETCH_OBJ)) {
            $tree[] = $result;
        }
        $childs = array();

        foreach($tree as $item) {
            $childs[$item->parent_id][] = $item;
        }


        foreach($tree as $item) {
            if (isset($childs[$item->id])) {
               $item->childs = $childs[$item->id];
            }
        }

        $tree = $childs[0];
    }
    else {
        // no category blabla
    }

Here is the function to build the table. It fails to work correctly.

    function draw($tree) {
    echo "<table border='1' width='300'>";
    echo "<tr>";
    echo "<td>Name</td><td>Depth</td><td>Parent</td>";
    echo "</tr>";
    foreach($tree as $key => $value) {
        echo "<tr>";
        echo "<td>".$value->name."</td>";
        echo "<td>".$value->depth."</td>";
        echo "<td>".$value->parent_id."</td>";
        echo "</tr>";
        if(isset($value->childs)) {
            draw($value->childs);
        }
    }
    echo "</table>";

}

As requested the HTML Output snippet:

<table border='1' width='300'>
    <tr>
        <td>Name</td>
        <td>Depth</td>
        <td>Parent</td>
    </tr>
    <tr>
        <td>Bad</td>
        <td>5</td>
        <td>5</td>
    </tr>
    <tr>
        <td>Good</td>
        <td>5</td>
        <td>5</td>
    </tr>
</table>
    <!--- BREAK HAPPENS HERE----->
    <tr>
        <td>Both?</td>
        <td>4</td>
        <td>3</td>
    </tr>
    <table border='1' width='300'>
        <tr>
            <td>Name</td>
            <td>Depth</td>
            <td>Parent</td>
        </tr>
        <tr>
            <td>dsadas</td>
            <td>5</td>
            <td>16</td>
        </tr>
    </table>
12
  • Do you mind checking that it works as intended by adding curly braces around your foreach and if statements in the above to clarify exactly what you meant? Having an IF right after a FOREACH could be an accident or deliberate. Please clarify with braces {} ?
    – MyStream
    Commented Feb 28, 2012 at 23:16
  • Why do you have the echo "</table>"; above the draw($value->childs);? get rid of that closing table tag
    – hackartist
    Commented Feb 28, 2012 at 23:18
  • @MyStream the array creation works as intendet. the var_dump of the tree array is exactly as it should be so that isnt the problem. hackartist: i forgot to add that everytime the table jumps into a new depth it should repost the table header with it. that is why the closing table is there. edit: even after removing it the same table breaks happens so that wasnt the problem either
    – Sepix
    Commented Feb 28, 2012 at 23:20
  • @Sepix: It's still hard to read (and not good practice for maintainability (sidepoint)) - and " should be ', but where exactly (what level) do you get unexpected html output? first loop through with no children?
    – MyStream
    Commented Feb 28, 2012 at 23:26
  • html tags come in pairs. in draw you have 1 table open, and at least one but probably more table closes.. that's not going to be balanced. Commented Feb 28, 2012 at 23:27

2 Answers 2

2

do this:

    echo "<tr><td colspan='3'>";
    if(isset($value->childs)) {
        draw($value->childs);
    }
    echo "</td></tr>"

Do this instead:

    if(isset($value->childs)) {
        echo "<tr><td colspan='3'>";
        draw($value->childs);
        echo "</td></tr>"
    }

You are creating a new table within the body of a table. That is invalid HTML. You have to put it in its own TD.

5
  • I am not creating that. the script is which is the problem. I know how the HTML code is supposed to look like the problem is to teach that to the recursive PHP function. :)
    – Sepix
    Commented Feb 29, 2012 at 0:21
  • @Sepix: Based on what Daan Timmer said, though, try adding same code, but put the tr/td colspan=3 inside the if(isset()) {} block, which should wrap the internal output with a single td - this should next them?
    – MyStream
    Commented Feb 29, 2012 at 0:34
  • that actually works almost! cant believe it. the only problem now is that the there is no header over the table when he goes into the outer layers. Picture: link
    – Sepix
    Commented Feb 29, 2012 at 1:05
  • okay. i solved it different in the end but this here definitly gave me the hint i neeeded to understand this recursive stuff. thanks alot ... after 40 hours of struggling i can finally sleep normal again!
    – Sepix
    Commented Feb 29, 2012 at 2:05
  • @Sepix, no problem. I will alter my answer with what MyStream said. He is correct indeed, my bad! Commented Feb 29, 2012 at 23:15
0
  function draw($tree) {
    if(!$tree) return;
    $nextLevel = array();
    echo "<table border='1' width='300'>";
    echo "<tr>";
    echo "<td>Name</td><td>Depth</td><td>Parent</td>";
    echo "</tr>";
    foreach($tree as $key => $value) {
        echo "<tr>";
        echo "<td>".$value->name."</td>";
        echo "<td>".$value->depth."</td>";
        echo "<td>".$value->parent_id."</td>";
        echo "</tr>";
        if(isset($value->childs) && $value->childs){
           $nextLevel = array_merge($nextLevel, $value->childs);
        }
    }
    echo "</table>";
    draw($nextLeveL);
}
1
  • this one works without breaking but prints a table that is not really a tree. it first lists all of layer1 then all of layer 2 then all of layer 2. i have the outcome of yours and how it should look in the end here: link link the 2nd should of course occur without the breaking in the bottom :).
    – Sepix
    Commented Feb 29, 2012 at 0:12

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.