Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursive function for comment and reply PHP application

I am having difficulty conceptualizing a recursive function for appending replies to comments, replies to replies, replies to replies to replies, etc.

This is my comments table:

enter image description here

Which SHOULD look something like this when rendered:

enter image description here

As it stands I can render each comment associated with the article_id (excluding those that are NOT NULL, of course):

$comments = $commentClass->fetch_article_comments($article_id);

foreach($comments as $comment) {

        $comment_id = $comment['comment_id'];   
        $member_id = $comment['member_id'];
        $comment_text = $comment['comment_text'];
        $comment_timestamp = timeAgo($comment['comment_timestamp']);  //get time ago

        //render comment using above variables
    }

Now I'm assuming I need to add a recursive function at the end of the above foreach statement, but I have yet to come up with anything remotely successful in appending the comments replies and the replies to each reply.

Can anyone help me accomplish this or perhaps point me in the right direction. I am not entirely familiar with recursive functions. I have done some scanning of the internet and on stackoverflow looking for something that helps, but haven't found anything helpful yet.

I did come across this post which recommended using a hierarchical database system, but I think I would prefer to use a php recursive function for this.

Thanks.


edit


By using the below answers I am only returning the results first comment and then it iterates and displays that one comment indefinitely. I can't figure out why?

My php:

function display_comments($article_id, $parent_id=0, $level=0) {
    global $comment;
    global $member;
    global $signed_in;
    global $username;

    $comments = $comment->fetch_article_comments($article_id, $parent_id);

    foreach($comments as $data) {
        $comment_id = $data['comment_id'];   
        $c_member_id = $data['member_id'];
        $comment_text = $data['comment_text'];
        $comment_timestamp = timeAgo($data['comment_timestamp']);  //get time ago

        $member_data = $member->fetch_member_data($c_member_id);
        $c_member_username = $member_data['member_username'];
        $c_member_avatar = $member_data['member_avatar'];

                //render HTML here

                $parent = $data['comment_parent'];
                display_comments($article_id, $parent, $level+1);

    }//end foreach

}//end display_comments()

and my PDO query:

public function fetch_article_comments($article_id, $parent_id) { //$page = (int)(!isset($_GET['page'])) ? 0 : $_GET['page'];

    if ($parent_id > 0) {
        $parent_id = "= $parent_id";
    } else {
        $parent_id = "IS NULL";
    }

    $query = $this->db->prepare("SELECT * FROM `comments2` WHERE `article_id` = $article_id AND `comment_parent` $parent_id ORDER BY `comment_timestamp` DESC");

    try{
        $query->execute();
        $comments = $query->fetchAll();                                     //returns an array
        $query->closeCursor();

        return $comments;

    } catch(PDOException $e){
        die($e->getMessage());
    }
}
like image 833
Nick Law Avatar asked Dec 08 '13 22:12

Nick Law


2 Answers

The core of the problem is this:

$comments = $commentClass->fetch_article_comments($article_id);

I assume, this function somwhere creates and runs SQL, that is similar to SELECT ... WHERE comments.article_id=$article_id. This is not sufficient - you need something like

$comments = $commentClass->fetch_article_comments($article_id, $parent_id);

that translates into SQL similar to SELECT ... WHERE comments.article_id=$article_id AND comments.comment_parent ($parent_id>0)?"=$parent_id":"IS NULL"

Now you can write your PHP function:

function display_comments ($article_id, $parent_id=0, $level=0) {
  $comments = $commentClass->fetch_article_comments($article_id, $parent_id);
  foreach($comments as $comment) {
        $comment_id = $comment['comment_id'];   
        $member_id = $comment['member_id'];
        $comment_text = $comment['comment_text'];
        $comment_timestamp = timeAgo($comment['comment_timestamp']);  //get time ago

        //render comment using above variables
        //Use $level to render the intendation level

        //Recurse
        display_comments ($article_id, $comment_id, $level+1);
    }
}

And finally call it with display_comments ($article_id);

like image 165
Eugen Rieck Avatar answered Nov 02 '22 20:11

Eugen Rieck


You could do something like:

function getCommentsForParent($parent="") {
   echo "<div class=\"comment\">";
   $db = get("select your db logics where parent = $parent");
   foreach ($db as $comment) {
      echo "print your comment in a box and make a div around the hole comments"
      getCommentsForParent($comment['parent_id']);
   }
   echo "</div>";
}

invoke function with getCommentsForParent()

With your code it should be something like:

function getCommentForParent($parent="") {
   global $commentsClass, $article_id;
   $comments = $commentClass->fetch_article_comments($article_id,$parent);
   foreach($comments as $comment) {
        $comment_id = $comment['comment_id'];   
        $member_id = $comment['member_id'];
        $comment_text = $comment['comment_text'];
        $comment_timestamp = timeAgo($comment['comment_timestamp']);  //get time ago
        getCommentForParent($comment['parent']);
    }
}

Look closely, ive adjusted your fetch article_comments. It now has a listener for $parent. Make sure that when your $parent = "", the class will only select the comments with empty parent.

invoke with getCommentsForParent()

It will automatically loop through the parent. Ofcourse this is highly conceptual but given your code you should get the hang of it.

like image 1
Benjamin de Bos Avatar answered Nov 02 '22 19:11

Benjamin de Bos