Jump to content

PHP comment system, handling replies of replies using a loop of some sort.


Recommended Posts

Hey.

Today I've been working on an important part of my website, the Comments section! It handles replies, but not sure how to handle replies of replies etc..I know that it involves a loop, but I'm really scratching my head with this one.

<?php require_once "../config.php"; ?>
<?php
if (isset($_POST['comment'])){
    echo true;
    //$sql = "INSERT INTO users (name, surname, sex) VALUES (?,?,?)";
    //$stmt= $pdo->prepare($sql);
    //$stmt->execute([$name, $surname, $sex]);
}
?>
<form action="" method="POST">
<label for="comment">Comment</label><br>
<textarea id="comment" name="comment" rows="4" cols="50" placeholder="remember to be polite!"></textarea>
<input type="submit" value="Submit">
</form><br><br>

<?php
$news_id = $_GET['id'];
$parent = 0; 
$stmt = $pdo->prepare("SELECT * FROM comment where news_id = ? AND parent = ? ORDER BY `comment`.`date` DESC");
$stmt->execute([$news_id, $parent]); 
while ($row = $stmt->fetch()) {
    echo "<br>";
    echo $row['content'];
    echo getReplies($pdo, $news_id, $row['comment_id']);
    echo getRepliesOfReplys($pdo, $news_id, $row['comment_id']);
    //getCountReplies($pdo, $parent);
}
?>
<br><br>
<?php
function getReplies($pdo, $news_id, $parent){
    $stmt2 = $pdo->prepare("SELECT comment_id, news_id, parent, user_id, content, karma, removed, reference, date, aproved, anonymous, image_upld 
    FROM `comment` WHERE news_id = ? AND parent = ? GROUP BY comment_id ORDER BY `comment`.`date` DESC");
    $stmt2->execute([$news_id, $parent]); 
    while ($row2 = $stmt2->fetch()) {
        echo "<br> - ".$row2['content']." [Comment ID:".$row2['comment_id']."], [Parent: ".$row2['parent']."]\n";
    }
}
function getCountReplies($pdo, $parent){
    $stmt = $pdo->prepare("SELECT COUNT(*) FROM `comment` where parent = ?");
    $stmt->execute([$parent]); 
    $count = $stmt->fetch();
    echo $count['COUNT(*)'];
}
function getRepliesOfReplys($pdo, $news_id, $parent){
    $stmt = $pdo->prepare("SELECT comment_id, news_id, parent, user_id, content, karma, removed, reference, date, aproved, anonymous, image_upld 
    FROM `comment` WHERE news_id = ? AND parent = ? GROUP BY comment_id ORDER BY `comment`.`date` DESC");
    $stmt->execute([$news_id, $parent+1]); 
    while ($row = $stmt->fetch()) {
        echo "<br> -- ".$row['content']." [Comment ID:".$row['comment_id']."], [Parent: ".$row['parent']."]\n";
    }
}
?>

 

Any free help, advice or code writers appreciated. 

 

 

Screenshot from 2022-07-30 17-00-29.png

Screenshot from 2022-07-30 17-00-15.png

Edited by oz11

That's a lot of queries to run.

Start off with a single query that gets all the replies for that post or whatever it is. All of them. Then shove them into an array based on their parent ID.

$comment_parents = [];
$count = 0;
/* get each $row from the query { */
	if (!isset($comment_parents[$row['parent']])) {
		$comment_parents[$row['parent']] = [];
	}
	$comment_parents[$row['parent']][] = $row;
	$count++;
/* } */

That also gets you a count of the number of comments, which it seems you want.

Now you display them. What's the markup? I don't know. But you're pretty much guaranteed take a recursive approach: show one comment, then immediately show all the comments below it, and repeat.

function showComments(array $comment_parents, array $comment, int $level = 0) {
	/* show the $comment */

	foreach ($comment_parents[$comment['id']] ?? [] as $child) {
		showComments($comment_parents, $child, $level + 1);
	}
}

foreach ($comment_parents[0] as $comment) {
	showComments($comment_parents, $comment);
}

 

  • Great Answer 1

Hello requinix! The code has been edited and looks a lot better now. Big thanks! However I'm stuck on the line "<---- not sure what to put here" not sure what i'm doing with Arrays as I'm a little foggy. Could you check my code again and see whether i have it in order and describe what i need to do on this line? Thanks! 

 

<?php require_once "../config.php"; ?>
<?php
if (isset($_POST['comment'])){
    echo true;
    //$sql = "INSERT INTO users (name, surname, sex) VALUES (?,?,?)";
    //$stmt= $pdo->prepare($sql);
    //$stmt->execute([$name, $surname, $sex]);
}
?>
<form action="" method="POST">
<label for="comment">Comment</label><br>
<textarea id="comment" name="comment" rows="4" cols="50" placeholder="remember to be polite!"></textarea>
<input type="submit" value="Submit">
</form><br><br>

<?php
$comment_parents = [];
$count = 0;


$news_id = $_GET['id'];
$parent = 0; 
$stmt = $pdo->prepare("SELECT * FROM comment WHERE news_id = ? ORDER BY `date` DESC");
$stmt->execute([$news_id]); 
    while ($row = $stmt->fetch()) {
        echo "<br>";
        if (!isset($comment_parents[$row['parent']])) {
            $comment_parents[$row['parent']] = [];
        }
        $comment_parents[$row['parent']][] = $row;
        $count++;

        foreach ($comment_parents[0] as $comment) {
            showComments($comment_parents, $comment);
        }
    }

    function showComments(array $comment_parents, array $comment, int $level = 0) {
         // <---- not sure what to put here
    
        foreach ($comment_parents[$comment['id']] ?? [] as $child) {
            showComments($comment_parents, $child, $level + 1);
        }
    }
?>

 

:)

 

Is there any way of doing this by counting a loop instead of an Array, because i would be more familiar with that approach. I was thinking I could count the rows (replies) for each comment and then loop through that number, recursively... 

My current/recent code: 

<?php require_once "../config.php"; ?>
<?php
$news_id = $_GET['id'];
$parent = 0; 
$reply_commid = $_GET['reply'];

if (!empty($_POST['comment']) && isset($_POST['reply_to'])){
    echo "sent!";
    if (isset($_POST['anon'])){
        $anon = 1;
    } elseif (!isset($_POST['anon'])) {
        $anon = 0;
    } else {
        $anon = 0;
    }
    // default "Hicks" user (for testing)
    $sql = "INSERT INTO `comment` (`comment_id`, `parent`, `news_id`, `user_id`, `content`, `karma`, `removed`, `reference`, `date`, `last_update`, 
    `aproved`, `anonymous`, `image_upld`) VALUES (NULL, ?, ?, '2', ?, '0', '0', '', CURRENT_TIMESTAMP, NULL, '1', ?, NULL);";
    $stmt= $pdo->prepare($sql);
    $stmt->execute([$_POST['reply_to'], $news_id, $_POST['comment'], $anon]);
    //$stmt->execute([$news_id, $_POST['reply_to'], $_POST['comment']]);
}
?>
<form action="" method="POST">


<label for="comment">Comment: </label><br>
<textarea id="comment" name="comment" rows="4" cols="50" placeholder="remember to be polite!"></textarea><br>
<label for="reply_to">Reply to (comment id): </label>
<input name="reply_to" id="reply_to" value="<?php if(isset($_GET['reply'])){ echo $_GET['reply']; } else { echo "0"; } ?>"><br>
<label for="anon">Post as Anonymous?</label>
<input type="checkbox" id="anon" name="anon" value="0"><br>

<input type="submit" value="Submit">
</form><br>

<?php
$comment_parents = [];
$count = 0;
echo "<h3>".countComments($pdo, $news_id)." Comments</h3><a href='?id=".$news_id."&reply=0'>Reply to thread</a><br><br>";
getAllComments($pdo, $news_id);
?>

<?php
function getAllComments($pdo, $news_id){
    $stmt = $pdo->prepare("SELECT `comment`.*, users.name FROM `comment` LEFT JOIN `users` ON `comment`.`user_id` = `users`.`user_id` 
     WHERE news_id = ?  AND parent = '0' ORDER BY comment_id DESC");
    $stmt->execute([$news_id]); 
    while ($row = $stmt->fetch()) {
        echo "<div style='padding-bottom: 7px;'><b>";
        if($row['anonymous'] !=1) {
            echo "--> ".countComments($pdo, $row['comment_id']);
            echo $row['content'] . "</b>, by <a href='profile.php?id=".$row['name']."'>".$row['name']."</a> [Comment ID:".$row['comment_id']."] [Parent ID: ".$row['parent']. "] [Date: ".$row['date']."] [Anon?: ".$row['anonymous']."]
            <br> <span style='font-size: 13px;'><a href='?id=".$news_id."&reply=".$row['comment_id']."'>Reply</a></span></div>
            <br> Replies: <ul style='list-style-type: katakana-iroha;'>
            <li>1</li><li>2</li><li>3, etc.</li>
            </ul><hr>";
        } elseif ($row['anonymous'] ==1) {
            echo "--> ".countComments($pdo, $row['comment_id']);
            echo $row['content'] . "</b>, by Anonymous [Comment ID:".$row['comment_id']."] [Parent ID: ".$row['parent']. "] [Date: ".$row['date']."] [Anon?: ".$row['anonymous']."]
            <br> <span style='font-size: 13px;'><a href='?id=".$news_id."&reply=".$row['comment_id']."'>Reply</a></span></div>
            <br> Replies: <ul style='list-style-type: katakana-iroha;'>
            <li>1</li><li>2</li><li>3, etc.</li>
            </ul><hr>";
            
        }
    }
}
function countComments($pdo, $comment_id){
    $stmt = $pdo->prepare("SELECT count(*) FROM comment WHERE parent = ?");
    $stmt->execute([$comment_id]); 
    $counter = $stmt->fetch();
    return $counter['count(*)'];
}

?>

For a start, my count doesn't count the correct number of replies for each post??
- Edit: count now works!! Just used comment_id as a parameter to fetch the number of replies.

Screenshot:
1140611167_Screenshotfrom2022-08-0112-44-07.thumb.png.0abb1efcc94c08ae591b027f515b4b4c.png

When amending your code it looks like this:
 

<?php require_once "../config.php"; ?>
<?php
$news_id = $_GET['id'];
$parent = 0; 
$reply_commid = $_GET['reply'];

if (!empty($_POST['comment']) && isset($_POST['reply_to'])){
    echo "sent!";
    if (isset($_POST['anon'])){
        $anon = 1;
    } elseif (!isset($_POST['anon'])) {
        $anon = 0;
    } else {
        $anon = 0;
    }
    // default "Hicks" user (for testing)
    $sql = "INSERT INTO `comment` (`comment_id`, `parent`, `news_id`, `user_id`, `content`, `karma`, `removed`, `reference`, `date`, `last_update`, 
    `aproved`, `anonymous`, `image_upld`) VALUES (NULL, ?, ?, '2', ?, '0', '0', '', CURRENT_TIMESTAMP, NULL, '1', ?, NULL);";
    $stmt= $pdo->prepare($sql);
    $stmt->execute([$_POST['reply_to'], $news_id, $_POST['comment'], $anon]);
    //$stmt->execute([$news_id, $_POST['reply_to'], $_POST['comment']]);
}
?>
<form action="" method="POST">


<label for="comment">Comment: </label><br>
<textarea id="comment" name="comment" rows="4" cols="50" placeholder="remember to be polite!"></textarea><br>
<label for="reply_to">Reply to (comment id): </label>
<input name="reply_to" id="reply_to" value="<?php if(isset($_GET['reply'])){ echo $_GET['reply']; } else { echo "0"; } ?>"><br>
<label for="anon">Post as Anonymous?</label>
<input type="checkbox" id="anon" name="anon" value="0"><br>

<input type="submit" value="Submit">
</form><br>

<?php
$comment_parents = [];
$count = 0;
echo "<h3>".countComments($pdo, $news_id)." Comments</h3><a href='?id=".$news_id."&reply=0'>Reply to thread</a><br><br>";
getAllComments($pdo, $news_id);
?>

<?php
function getAllComments($pdo, $news_id){
    $stmt = $pdo->prepare("SELECT `comment`.*, users.name FROM `comment` LEFT JOIN `users` ON `comment`.`user_id` = `users`.`user_id` 
     WHERE news_id = ?  AND parent = '0' ORDER BY comment_id DESC");
    $stmt->execute([$news_id]); 
    $comment_parents = [];
    $count = 0;
    while ($row = $stmt->fetch()) {
        if (!isset($comment_parents[$row['parent']])) {
            $comment_parents[$row['parent']] = [];
        }
        $comment_parents[$row['parent']][] = $row;
        $count++;
    }
}
function showComments(array $comment_parents, array $comment, int $level = 0) {
	/* show the $comment */

	foreach ($comment_parents[$comment['id']] ?? [] as $child) {
		showComments($comment_parents, $child, $level + 1);
	}
}

foreach ($comment_parents[0] as $comment) {
	showComments($comment_parents, $comment);
}
function countComments($pdo, $news_id){
    $stmt = $pdo->prepare("SELECT count(*) FROM comment WHERE news_id = ?");
    $stmt->execute([$news_id]); 
    $counter = $stmt->fetch();
    return $counter['count(*)'];
}

?>

Sorry I'm not super in php yet. I'm stuck here, maybe you could look at the code and tell me what to do next to sort it out?

 

This is the hardest thing i have coded after turtle graphics. :P

Edited by oz11
count now works!
<?php require_once "../config.php"; ?>
<?php
$news_id = $_GET['id'];
$parent = 0; 
$reply_commid = $_GET['reply'];

if (!empty($_POST['comment']) && isset($_POST['reply_to'])){
    echo "sent!";
    if (isset($_POST['anon'])){
        $anon = 1;
    } elseif (!isset($_POST['anon'])) {
        $anon = 0;
    } else {
        $anon = 0;
    }
    // default "Hicks" user (for testing)
    $sql = "INSERT INTO `comment` (`comment_id`, `parent`, `news_id`, `user_id`, `content`, `karma`, `removed`, `reference`, `date`, `last_update`, 
    `aproved`, `anonymous`, `image_upld`) VALUES (NULL, ?, ?, '2', ?, '0', '0', '', CURRENT_TIMESTAMP, NULL, '1', ?, NULL);";
    $stmt= $pdo->prepare($sql);
    $stmt->execute([$_POST['reply_to'], $news_id, $_POST['comment'], $anon]);
    //$stmt->execute([$news_id, $_POST['reply_to'], $_POST['comment']]);
}
?>
<form action="" method="POST">


<label for="comment">Comment: </label><br>
<textarea id="comment" name="comment" rows="4" cols="50" placeholder="remember to be polite!"></textarea><br>
<label for="reply_to">Reply to (comment id): </label>
<input name="reply_to" id="reply_to" value="<?php if(isset($_GET['reply'])){ echo $_GET['reply']; } else { echo "0"; } ?>"><br>
<label for="anon">Post as Anonymous?</label>
<input type="checkbox" id="anon" name="anon" value="0"><br>

<input type="submit" value="Submit">
</form><br>

<?php
$comment_parents = [];
$count = 0;
echo "<h3>".countComments($pdo, $news_id)." Comments</h3><a href='?id=".$news_id."&reply=0'>Reply to thread</a><br><br>";
getAllComments($pdo, $news_id);
?>

<?php
function getAllComments($pdo, $news_id){
    $stmt = $pdo->prepare("SELECT `comment`.*, users.name FROM `comment` LEFT JOIN `users` ON `comment`.`user_id` = `users`.`user_id` 
     WHERE news_id = ?  AND parent = '0' ORDER BY comment_id DESC");
    $stmt->execute([$news_id]); 
    while ($row = $stmt->fetch()) {
        echo "<div style='padding-bottom: 7px;'>";
        if($row['anonymous'] !=1) {
            echo " ".countComments($pdo, $row['comment_id'])." <-- number of replies to reply <br><b>";
            echo $row['content'] . "</b>, by <a href='profile.php?id=".$row['name']."'>".$row['name']."</a> [Comment ID:".$row['comment_id']."] [Parent ID: ".$row['parent']. "] [Date: ".$row['date']."] [Anon?: ".$row['anonymous']."]
            <br> <span style='font-size: 13px;'><a href='?id=".$news_id."&reply=".$row['comment_id']."'>Reply</a></span></div>
            <br> Replies:<br>";
            grabReplies(countComments($pdo, $row['comment_id']));
            echo "<hr>";
        } elseif ($row['anonymous'] ==1) {
            echo " ".countComments($pdo, $row['comment_id'])." <-- number of replies to reply<br><b>";
            echo $row['content'] . "</b>, by Anonymous [Comment ID:".$row['comment_id']."] [Parent ID: ".$row['parent']. "] [Date: ".$row['date']."] [Anon?: ".$row['anonymous']."]
            <br> <span style='font-size: 13px;'><a href='?id=".$news_id."&reply=".$row['comment_id']."'>Reply</a></span></div>
            <br> Replies:<br>";
            grabReplies(countComments($pdo, $row['comment_id']));
            echo "<hr>";
            
        }
    }
}
function countComments($pdo, $comment_id){
    $stmt = $pdo->prepare("SELECT count(*) FROM comment WHERE parent = ?");
    $stmt->execute([$comment_id]); 
    $counter = $stmt->fetch();
    return $counter['count(*)'];
}
function grabReplies($numberOfReplies) {
    for ($x = 0; $x <= $numberOfReplies; $x++) {
        echo "Reply #: $x <br>";
      }
}

?>

I added a loop which outputs something or nothing. What can I do next?

Screenshot from 2022-08-01 12-54-29.png

Edited by oz11
sorry to spam the forum, just chipping away at a block.

Sorry to be rude and spam, but i'm making progress but cannot manage the loop yet...

 

<?php require_once "../config.php"; ?>
<?php
$news_id = $_GET['id'];
$parent = 0; 
$reply_commid = $_GET['reply'];

if (!empty($_POST['comment']) && isset($_POST['reply_to'])){
    echo "sent!";
    if (isset($_POST['anon'])){
        $anon = 1;
    } elseif (!isset($_POST['anon'])) {
        $anon = 0;
    } else {
        $anon = 0;
    }
    // default "Hicks" user (for testing)
    $sql = "INSERT INTO `comment` (`comment_id`, `parent`, `news_id`, `user_id`, `content`, `karma`, `removed`, `reference`, `date`, `last_update`, 
    `aproved`, `anonymous`, `image_upld`) VALUES (NULL, ?, ?, '2', ?, '0', '0', '', CURRENT_TIMESTAMP, NULL, '1', ?, NULL);";
    $stmt= $pdo->prepare($sql);
    $stmt->execute([$_POST['reply_to'], $news_id, $_POST['comment'], $anon]);
    //$stmt->execute([$news_id, $_POST['reply_to'], $_POST['comment']]);
}
?>
<form action="" method="POST">


<label for="comment">Comment: </label><br>
<textarea id="comment" name="comment" rows="4" cols="50" placeholder="remember to be polite!"></textarea><br>
<label for="reply_to">Reply to (comment id): </label>
<input name="reply_to" id="reply_to" value="<?php if(isset($_GET['reply'])){ echo $_GET['reply']; } else { echo "0"; } ?>"><br>
<label for="anon">Post as Anonymous?</label>
<input type="checkbox" id="anon" name="anon" value="0"><br>

<input type="submit" value="Submit">
</form><br>

<?php
$comment_parents = [];
$count = 0;
echo "<h3>".countComments($pdo, $news_id)." Comments</h3><a href='?id=".$news_id."&reply=0'>Reply to thread</a><br><br>";
getAllComments($pdo, $news_id);
?>

<?php
function getAllComments($pdo, $news_id){
    $stmt = $pdo->prepare("SELECT `comment`.*, users.name FROM `comment` LEFT JOIN `users` ON `comment`.`user_id` = `users`.`user_id` 
     WHERE news_id = ?  AND parent = '0' ORDER BY comment_id DESC");
    $stmt->execute([$news_id]); 
    while ($row = $stmt->fetch()) {
        echo "<div style='padding-bottom: 7px;'>";
        if($row['anonymous'] !=1) {
            echo " ".countComments($pdo, $row['comment_id'])." <-- number of replies to reply <br><b>";
            echo $row['content'] . "</b>, by <a href='profile.php?id=".$row['name']."'>".$row['name']."</a> [Comment ID:".$row['comment_id']."] [Parent ID: ".$row['parent']. "] [Date: ".$row['date']."] [Anon?: ".$row['anonymous']."]
            <br> <span style='font-size: 13px;'><a href='?id=".$news_id."&reply=".$row['comment_id']."'>Reply</a></span></div>
            <br> Replies:<br>";
            grabReplies($pdo, countComments($pdo, $row['comment_id']), $row['comment_id'], $news_id);
            echo "<hr>";
        } elseif ($row['anonymous'] ==1) {
            echo " ".countComments($pdo, $row['comment_id'])." <-- number of replies to reply<br><b>";
            echo $row['content'] . "</b>, by <u>Anonymous</u> [Comment ID:".$row['comment_id']."] [Parent ID: ".$row['parent']. "] [Date: ".$row['date']."] [Anon?: ".$row['anonymous']."]
            <br> <span style='font-size: 13px;'><a href='?id=".$news_id."&reply=".$row['comment_id']."'>Reply</a></span></div>
            <br> Replies:<br>";
            grabReplies($pdo, countComments($pdo, $row['comment_id']), $row['comment_id'], $news_id);
            echo "<hr>";
            
        }
    }
}
function countComments($pdo, $comment_id){
    $stmt = $pdo->prepare("SELECT count(*) FROM comment WHERE parent = ?");
    $stmt->execute([$comment_id]); 
    $counter = $stmt->fetch();
    return $counter['count(*)'];
}
function grabReplies($pdo,$numberOfReplies, $comment_id, $news_id) {
    $stmt = $pdo->prepare("SELECT users.name, `comment`.* FROM `users` LEFT JOIN `comment` ON `comment`.`user_id` = `users`.`user_id` WHERE parent = ?");
    $stmt->execute([$comment_id]); 
    while ($row = $stmt->fetch()) {

        if($row['anonymous'] == 0) {
            echo "<div style='padding-left: 20px;'>";
            echo $row['content']." by <a href='profile?id=".$row['name']."'>".$row['name']."</a> // ".$row['date'];
            echo " -- <a href='?id=".$news_id."&reply=".$row['comment_id']."'>Reply</a><br>";
            echo "</div>";
        } else if($row['anonymous'] ==1) {
            echo "<div style='padding-left: 20px;'>";
            echo $row['content']." by <u>Anonymous</u> // ".$row['date'];
            echo " -- <a href='?id=".$news_id."&reply=".$row['comment_id']."'>Reply</a><br>";
            echo "</div>";
        }
    }
}


?>

Output:
 

 

 

Screenshot from 2022-08-01 14-20-18.png

 

I feel like I've hit a dead end. Help plz. :shrug:

Edited by oz11
<?php require_once "../config.php"; ?>
<?php
$news_id = $_GET['id'];
$parent = 0; 
$reply_commid = $_GET['reply'];

if (!empty($_POST['comment']) && isset($_POST['reply_to'])){
    echo "sent!";
    if (isset($_POST['anon'])){
        $anon = 1;
    } elseif (!isset($_POST['anon'])) {
        $anon = 0;
    } else {
        $anon = 0;
    }
    // default "Hicks" user (for testing)
    $sql = "INSERT INTO `comment` (`comment_id`, `parent`, `news_id`, `user_id`, `content`, `karma`, `removed`, `reference`, `date`, `last_update`, 
    `aproved`, `anonymous`, `image_upld`) VALUES (NULL, ?, ?, '2', ?, '0', '0', '', CURRENT_TIMESTAMP, NULL, '1', ?, NULL);";
    $stmt= $pdo->prepare($sql);
    $stmt->execute([$_POST['reply_to'], $news_id, $_POST['comment'], $anon]);
    //$stmt->execute([$news_id, $_POST['reply_to'], $_POST['comment']]);
}
?>
<form action="" method="POST">


<label for="comment">Comment: </label><br>
<textarea id="comment" name="comment" rows="4" cols="50" placeholder="remember to be polite!"></textarea><br>
<label for="reply_to">Reply to (comment id): </label>
<input name="reply_to" id="reply_to" value="<?php if(isset($_GET['reply'])){ echo $_GET['reply']; } else { echo "0"; } ?>"><br>
<label for="anon">Post as Anonymous?</label>
<input type="checkbox" id="anon" name="anon" value="0"><br>

<input type="submit" value="Submit">
</form><br>

<?php
$comment_parents = [];
$count = 0;
echo "<h3>".countComments($pdo, $news_id)." Comments</h3><a href='?id=".$news_id."&reply=0'>Reply to thread</a><br><br>";
getAllComments($pdo, $news_id);
?>

<?php
function getAllComments($pdo, $news_id){
    $stmt = $pdo->prepare("SELECT `comment`.*, users.name FROM `comment` LEFT JOIN `users` ON `comment`.`user_id` = `users`.`user_id` 
     WHERE news_id = ?  AND parent = '0' ORDER BY comment_id DESC");
    $stmt->execute([$news_id]); 
    while ($row = $stmt->fetch()) {
        echo "<div style='padding-bottom: 7px;'>";
        if($row['anonymous'] !=1) {
            echo " ".countComments($pdo, $row['comment_id'])." <-- number of replies to reply <br><b>";
            echo $row['content'] . "</b>, by <a href='profile.php?id=".$row['name']."'>".$row['name']."</a> [Comment ID:".$row['comment_id']."] [Parent ID: ".$row['parent']. "] [Date: ".$row['date']."] [Anon?: ".$row['anonymous']."]
            <br> <span style='font-size: 13px;'><a href='?id=".$news_id."&reply=".$row['comment_id']."'>Reply</a></span></div>
            <br> Replies:<br>";
            grabReplies($pdo, countComments($pdo, $row['comment_id']), $row['comment_id'], $news_id);
            echo "<hr>";
        } elseif ($row['anonymous'] ==1) {
            echo " ".countComments($pdo, $row['comment_id'])." <-- number of replies to reply<br><b>";
            echo $row['content'] . "</b>, by <u>Anonymous</u> [Comment ID:".$row['comment_id']."] [Parent ID: ".$row['parent']. "] [Date: ".$row['date']."] [Anon?: ".$row['anonymous']."]
            <br> <span style='font-size: 13px;'><a href='?id=".$news_id."&reply=".$row['comment_id']."'>Reply</a></span></div>
            <br> Replies:<br>";
            grabReplies($pdo, countComments($pdo, $row['comment_id']), $row['comment_id'], $news_id);
            echo "<hr>";
            
        }
    }
}
function countComments($pdo, $comment_id){
    $stmt = $pdo->prepare("SELECT count(*) FROM comment WHERE parent = ?");
    $stmt->execute([$comment_id]); 
    $counter = $stmt->fetch();
    return $counter['count(*)'];
}
function grabReplies($pdo,$numberOfReplies, $comment_id, $news_id) {
    $stmt = $pdo->prepare("SELECT users.name, `comment`.* FROM `users` LEFT JOIN `comment` ON `comment`.`user_id` = `users`.`user_id` WHERE parent = ?");
    $stmt->execute([$comment_id]); 
    while ($row = $stmt->fetch()) {

        if($row['anonymous'] == 0) {
            echo "<div style='padding-left: 20px;'>";
            echo $row['content']." by <a href='profile?id=".$row['name']."'>".$row['name']."</a> // ".$row['date'];
            echo " -- <a href='?id=".$news_id."&reply=".$row['comment_id']."'>Reply</a><br>";
            echo countComments($pdo, $row['comment_id']);
            echo "<-- number of replies</div>";

        } else if($row['anonymous'] ==1) {
            echo "<div style='padding-left: 20px;'>";
            echo $row['content']." by <u>Anonymous</u> // ".$row['date'];
            echo " -- <a href='?id=".$news_id."&reply=".$row['comment_id']."'>Reply</a><br>";
            echo countComments($pdo, $row['comment_id']);
            echo "<-- number of replies</div>";

        }
    }
}
function getRecursive($numberOfReplies){
    for ($x = 0; $x <= $numberOfReplies; $x++) {
        echo "-- >The number of replies is: $x <br>";
      }
      
}


?>

Bit more chipping away.. now it shows a integer for the number of replies to replies. Still stuck with the loop though, thanks. :rolleyes:

Screenshot from 2022-08-01 14-54-25.png

I think i just need one loop to go through the remaining comments i have, using using the counters i have, not sure if this is straight forward as i think it is though...? I could go on forever adding more levels of comments in sequence, but obviously it shouldn't be done that way. - That actually brings up a good word, "levels"... still stuck. Maybe I could .. erm . idk. Help?

Edited by oz11
On 7/30/2022 at 5:24 PM, requinix said:

That's a lot of queries to run.

Start off with a single query that gets all the replies for that post or whatever it is. All of them. Then shove them into an array based on their parent ID.

$comment_parents = [];
$count = 0;
/* get each $row from the query { */
	if (!isset($comment_parents[$row['parent']])) {
		$comment_parents[$row['parent']] = [];
	}
	$comment_parents[$row['parent']][] = $row;
	$count++;
/* } */

That also gets you a count of the number of comments, which it seems you want.

Now you display them. What's the markup? I don't know. But you're pretty much guaranteed take a recursive approach: show one comment, then immediately show all the comments below it, and repeat.

function showComments(array $comment_parents, array $comment, int $level = 0) {
	/* show the $comment */

	foreach ($comment_parents[$comment['id']] ?? [] as $child) {
		showComments($comment_parents, $child, $level + 1);
	}
}

foreach ($comment_parents[0] as $comment) {
	showComments($comment_parents, $comment);
}

 

I've been looking at your code, and is making a lot more sense now since i have been working on it.  However, i can implement the first bit (see screenshot bellow), bu the second bit i don't know what i'm doing. Could you write it up for me and check my first bit if it is ok..?

 

2INt4gE.png
[first bit of code placed in and looks fine, to me ..?]

 

Full code atm (with edits):  [ https://pastebin.com/xZ1318hz ]

Without edits: [https://pastebin.com/NmKA17rh]

Edited by oz11

the first section of code is just indexing/pivoting the data, using the parent id, when fetching it. there's actually a PDO fetch mode that will do this for you if you select the parent_id as the first column in the SELECT list - PDO::FETCH_GROUP

next, you need a recursive function to loop over the data and output it the way you want. see the following example (should be close to what your db naming is) -

<?php

// create/display nested comments

// init
require 'pdo_connection.php';

// fake some data
$user_id = 1;
$_GET['news_id'] = 1;

$post = []; // array to hold a trimmed working copy of the form data
$errors = []; // array to hold user/valdiation errors

// post
if($_SERVER['REQUEST_METHOD'] == 'POST')
{
	// trim all the data at once
	$post = array_map('trim',$_POST); // if any input is an array, use a recursive trim call-back function here instead of php's trim
	
	// validate inputs here...
	
	// if no errors, use the form data
	if(empty($errors))
	{
		$sql = "INSERT comment (news_id, parent_id, user_id, comment, datetime) VALUE (?,?,?,?,NOW())";
		$stmt = $pdo->prepare($sql);
		$stmt->execute([ $_GET['news_id'], $post['parent_id'], $user_id, $post['comment'] ]);
	}
	
	// if no errors, success
	if(empty($errors))
	{
		die(header("Refresh:0"));
	}
}

// get all the rows of data for the requested news id
$sql = "SELECT parent_id, id, news_id, user_id, comment
 FROM comment
 WhERE news_id = ?
 ORDER BY datetime";
$stmt = $pdo->prepare($sql);
$stmt->execute([ $_GET['news_id'] ]);
$comment_data = $stmt->fetchAll(PDO::FETCH_GROUP);

// recursive function to output parent/child data
function list_comments($parent_id, $data, $level=0)
{
	// this just supplies a visual part to the output so you can see what the code does
	$indent = str_repeat("---- ", $level);
	
	// loop over data for the current parent_id
	foreach($data[$parent_id] as $arr)
	{
		// output the comment and any other information
		echo "$indent{$arr['comment']}<br>";
		// determine and output any child count
		$count = isset($data[$arr['id']]) ? count($data[$arr['id']]) : 0;
		$pl = $count == 0 || $count > 1 ? 'ies' : 'y';
		echo "$indent$count Repl$pl<br>";
		// allow a comment for the current parent
		// you would probably want to use a javascript 'show' operation for this
		?>
		<form method="post">
		<input type='hidden' name='parent_id' value='<?=$arr['id']?>'>
		<?=$indent?><label>Comment:<br>
		<?=$indent?><textarea name="comment" rows="4" cols="50" placeholder="remember to be polite!"></textarea></label>
		<input type="submit">
		</form><br>
		<?php
		// recurse if there are children of the current parent
		if(isset($data[$arr['id']]))
		{
			list_comments($arr['id'], $data, $level+1);
		}
	}
} 

// html
?>

<?php
// display any errors
if(!empty($errors))
{
	echo implode('<br>',$errors);
}
?>

<?php
// allow a comment on the main article
?>
<form method="post">
<input type='hidden' name='parent_id' value='0'>
<label>Comment:<br>
<textarea name="comment" rows="4" cols="50" placeholder="remember to be polite!"><?=$post['comment']??''?></textarea></label>
<input type="submit">
</form><br>

<?php
// list comments, starting with parent 0
list_comments(0, $comment_data, 0);

 

  • Great Answer 1

Hey mac_gyver. Thanks for typing it up for me. My sql PDO query looks like this:

SELECT comment_id, parent, news_id, user_id, content, karma, removed, date, last_update, aproved, 
anonymous, image_upld FROM comment WHERE news_id = ?  AND parent = '0' ORDER BY comment_id DESC

Should i just replace the 

Quote

$arr['comment']

to 

Quote

$arr['content']

etc. With $arr['id'] to $arr['comment_id'], etc.

I made some changes .. 

<?php require_once "../config.php";
// create/display nested comments

// init


// fake some data
$user_id = 1;
$_GET['news_id'] = 0;

$post = []; // array to hold a trimmed working copy of the form data
$errors = []; // array to hold user/valdiation errors

// post
if($_SERVER['REQUEST_METHOD'] == 'POST')
{
	// trim all the data at once
	$post = array_map('trim',$_POST); // if any input is an array, use a recursive trim call-back function here instead of php's trim
	
	// validate inputs here...
	
	// if no errors, use the form data
	if(empty($errors))
	{
		$sql = "INSERT comment (news_id, parent_id, user_id, comment, datetime) VALUE (?,?,?,?,NOW())";
		$stmt = $pdo->prepare($sql);
		$stmt->execute([ $_GET['news_id'], $post['parent_id'], $user_id, $post['comment'] ]);
	}
	
	// if no errors, success
	if(empty($errors))
	{
		die(header("Refresh:0"));
	}
}

// get all the rows of data for the requested news id
$sql = "SELECT comment_id, comment_id, parent, news_id, user_id, content, karma, removed, date, last_update, aproved, 
anonymous, image_upld FROM comment WHERE news_id = ?  AND parent = '0' ORDER BY comment_id DESC";
$stmt = $pdo->prepare($sql);
$stmt->execute([ $_GET['news_id'] ]);
$comment_data = $stmt->fetchAll(PDO::FETCH_GROUP);

// recursive function to output parent/child data
function list_comments($parent_id, $data, $level=0)
{
	// this just supplies a visual part to the output so you can see what the code does
	$indent = str_repeat("---- ", $level);
	
    //echo "<pre>";
    //print_r($data);
    //echo "</pre>";
	// loop over data for the current parent_id
	foreach($data[$parent_id] as $arr)
	{
		// output the comment and any other information
		echo "$indent{$arr['content']}<br>";
		// determine and output any child count
		$count = isset($data[$arr['comment_id']]) ? count($data[$arr['comment_id']]) : 0;
		$pl = $count == 0 || $count > 1 ? 'ies' : 'y';
		echo "$indent$count Repl$pl<br>";
		// allow a comment for the current parent
		// you would probably want to use a javascript 'show' operation for this
		?>
		<form method="post">
		<input type='hidden' name='parent_id' value='<?=$arr['comment_id']?>'>
		<?=$indent?><label>Comment:<br>
		<?=$indent?><textarea name="comment" rows="4" cols="50" placeholder="remember to be polite!"></textarea></label>
		<input type="submit">
		</form><br>
		<?php
		// recurse if there are children of the current parent
		if(isset($data[$arr['comment_id']]))
		{
			list_comments($arr['comment_id'], $data, $level+1);
		}
	}
} 

// html
?>

<?php
// display any errors
if(!empty($errors))
{
	echo implode('<br>',$errors);
}
?>

<?php
// allow a comment on the main article
?>
<form method="post">
<input type='hidden' name='parent_id' value='0'>
<label>Comment:<br>
<textarea name="comment" rows="4" cols="50" placeholder="remember to be polite!"><?=$post['content']??''?></textarea></label>
<input type="submit">
</form><br>

<?php
// list comments, starting with parent 0
list_comments(0, $comment_data, 0);

?>

876191841_Screenshotfrom2022-08-0223-31-35.thumb.png.3ff25277fad712d980000bb70d6589a5.png

I used bellow print_r code to test if the data is coming from the database correctly and it is, so no problem there.

So i commented out the code bellow to move on... Now though i'm not getting any data returned back at me

Quote

echo "<pre>";
print_r($data);
echo "</pre>";

..Just a white page and comment box
1948539002_Screenshotfrom2022-08-0223-28-07.png.8ee3b736ab7d5948a1f5b57aee2c6da0.png

It actually works perfectly now. Love you mac_gyver :wub:. I'll look through the code until I understand how it works fully, bit by bit.

The code was beautifully written and I hope one day to be able to write as eloquently. Also, great idea to use JavaScript show(), I did that and it works using some code I found on Stack Overflow. 

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.