4

I would like to diplay comments on my site like this:

<li>Parent
    <ul>
        <li>child one</li>
        <li>child two
            <ul>
                <li>grandchild</li>
                <li>other grandchild</li>
            </ul>
        </li>
     </ul>
<li>Another parent with no children</li>
<li>

I have read the following article, however it doesn't use <li>. So is there a way to display comments like I've done before with an array like so? Thanks.

$comments = array(
      array('id'=>1, 'parent_id'=>NULL,   'text'=>'Parent'),
      array('id'=>2, 'parent_id'=>1,      'text'=>'Child'),
      array('id'=>3, 'parent_id'=>2,      'text'=>'Child Third level'),
      array('id'=>4, 'parent_id'=>NULL,   'text'=>'Second Parent'),
      array('id'=>5, 'parent_id'=>4,      'text'=>'Second Child')
);
Amaan Iqbal
  • 761
  • 2
  • 9
  • 25
q3d
  • 3,473
  • 8
  • 34
  • 39
  • 2
    Yes, it's perfectly possible. You'll just have to create a *recursive* function that *builds a tree*. (Google, SO search for that...) – deceze Apr 29 '12 at 08:57
  • you may also *unfold* this tree structure into a plain list and then output it using simple foreach – Your Common Sense Apr 29 '12 at 09:00
  • possible duplicate of [How can I convert a series of parent-child relationships into a hierarchical tree?](http://stackoverflow.com/questions/2915748/how-can-i-convert-a-series-of-parent-child-relationships-into-a-hierarchical-tre) - This has been asked before [And answered](http://stackoverflow.com/a/8285070/367456). It's also useful to turn your array structure into some other structure like a nested set. – hakre Apr 29 '12 at 09:09

3 Answers3

4

I asssume your comment table has id, parent_id, comment, ... and my suggestion goes like this;

Select you comments like;

$sql = "SELECT *FROM comments ORDER BY id DESC";

$rows = mysql_query($sql);

And next step is array operations.You can see the following code below and try working demo here;

$rows = your_select_result;//I assumed that you have done these stuffs
$comments = $row;
/**
This is test data, please remove this array while you are
running own application.Since you will use the data one you get your db
**/
$comments = array(
    1 => array('id' => 1, 'parent_id' => 0, 'childs' => array()),
    2 => array('id' => 2, 'parent_id' => 0, 'childs' => array()),
    3 => array('id' => 3, 'parent_id' => 0, 'childs' => array()),
    5 => array('id' => 5, 'parent_id' => 0, 'childs' => array()),
    11 => array('id' => 11, 'parent_id' => 0, 'childs' => array()),
    17 => array('id' => 17, 'parent_id' => 0, 'childs' => array()),
    23 => array('id' => 23, 'parent_id' => 0, 'childs' => array()),
    28 => array('id' => 28, 'parent_id' => 0, 'childs' => array()),
    4 => array('id' => 4, 'parent_id' => 1, 'childs' => array()),
    6 => array('id' => 6, 'parent_id' => 1, 'childs' => array()),
    8 => array('id' => 8, 'parent_id' => 2, 'childs' => array()),
    9 => array('id' => 9, 'parent_id' => 2, 'childs' => array()),
    7 => array('id' => 7, 'parent_id' => 3, 'childs' => array()),
    12 => array('id' =>12, 'parent_id' => 7, 'childs' => array()),
    13 => array('id' => 13, 'parent_id' => 12, 'childs' => array()),
);

/** Comment prepare start */
foreach ($comments as $k => &$v) {
    if ($v['parent_id'] != 0) {
        $comments[$v['parent_id']]['childs'][] =& $v;
    }
}
unset($v);

foreach ($comments as $k => $v) {
    if ($v['parent_id'] != 0) {
        unset($comments[$k]);
    }
}

/** Comment prepare end */

//Your indent pattern
function indent($size) {
    $string = "";
    for ($i = 0; $i < $size; $i++) {
        $string .= "#";
    }
    echo $string; 
}


function printComments($comments, $indent = 0) {
    foreach ($comments as $comment) {
        echo indent($indent + 1).' I am comment '.$comment['id']."\n";
        if (!empty($comment['childs'])) {
            printComments($comment['childs'], $indent + 1);
        }
        }
}


printComments($comments);

For demo please see here

WoMo
  • 7,136
  • 2
  • 29
  • 36
Hüseyin BABAL
  • 15,400
  • 4
  • 51
  • 73
  • Great for a two-dimensional hierarchy, but it does not work at all for arbitrarily nested entries, as asked for here. – deceze Apr 30 '12 at 00:44
  • Yeah, you are right. I change the logic of code (not much), and updated the code.Also i have added working demo.Please see the updates – Hüseyin BABAL Apr 30 '12 at 09:29
2

BTW, in case of using Materialized Path technique, you won't need no recursion nor nested array or stuff.

Just plain linear outpur from the database.

To do that just create a field named path in your database and fill it with all the parent id's, padded to some considerabe length.

Say, example tree may look like

id 1 root path 
    id 3 root 1 path 000000001
        id 5 root 1 path 000000001000000003
    id 4 root 1 path 000000001
id 2 root path 000000002
    id 6 root 2 path 

so, querying your table by simple ORDER BY root DESC, path ASC
you will get your tree as a simple already ordered list

Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
0

This function will only need the parent_id and id key present in each comment's array.

$comments = array(
            array('id'=>1, 'parent_id'=>NULL, 'text'=>'Parent'),
            array('id'=>2, 'parent_id'=>1,    'text'=>'Child'),
            array('id'=>3, 'parent_id'=>2,    'text'=>'Child Third level'),
            array('id'=>4, 'parent_id'=>NULL, 'text'=>'Second Parent'),
            array('id'=>5, 'parent_id'=>4,    'text'=>'Second Child')
        );

This will return a multidimensional array. If one item has no children, $comment['children'] will equal NULL, otherwise the respective array of children will be attached.

function arrangecomments($comments){

    $tree = array();

    /* We get all the parent into the tree array */
    foreach ($comments as &$node) {
        /* Note: I've used 0 for top level parent, you can change this to == 'NULL' */
        if($node['parent_id']=='0'){
            $tree[] = $node;
            unset($node);
        }
    }

    /* This is the recursive function that does the magic */
    /* $k is the position in the array */
    function findchildren(&$parent, &$comments, $k=0){
        if (isset($comments[$k])){
            if($comments[$k]['parent_id']==$parent['id']){
                $com = $comments[$k];
                findchildren($com, $comments); // We try to find children's children
                $parent['children'][] = $com;
            }
            findchildren($parent, $comments, $k+1); // And move to the next sibling
        }
    }

    /* looping through the parent array, we try to find the children */
    foreach ($tree as &$parent) {
        findchildren($parent, $comments);
    }

    return $tree;

}

I know it can be improved a lot, but it works, and I haven't found any bugs so far. Hope it helps!

0b10011
  • 18,397
  • 4
  • 65
  • 86
Nicolás Torres
  • 1,385
  • 8
  • 13