q3d
q3d

Reputation: 3523

How do I implement nested comments?

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')
);

Upvotes: 4

Views: 5347

Answers (3)

H&#252;seyin BABAL
H&#252;seyin BABAL

Reputation: 15550

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

Upvotes: 4

Nicol&#225;s Torres
Nicol&#225;s Torres

Reputation: 1345

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!

Upvotes: 0

Your Common Sense
Your Common Sense

Reputation: 157839

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

Upvotes: 2

Related Questions