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')
);
3
  • 2
    Yes, it's perfectly possible. You'll just have to create a recursive function that builds a tree. (Google, SO search for that...) Commented Apr 29, 2012 at 8:57
  • you may also unfold this tree structure into a plain list and then output it using simple foreach Commented Apr 29, 2012 at 9:00
  • possible duplicate of How can I convert a series of parent-child relationships into a hierarchical tree? - This has been asked before And answered. It's also useful to turn your array structure into some other structure like a nested set. Commented Apr 29, 2012 at 9:09

3 Answers 3

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

Sign up to request clarification or add additional context in comments.

2 Comments

Great for a two-dimensional hierarchy, but it does not work at all for arbitrarily nested entries, as asked for here.
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
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

Comments

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!

Comments

Your Answer

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.