oz11 Posted July 30, 2022 Share Posted July 30, 2022 (edited) 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. Edited July 30, 2022 by oz11 Quote Link to comment https://forums.phpfreaks.com/topic/315114-php-comment-system-handling-replies-of-replies-using-a-loop-of-some-sort/ Share on other sites More sharing options...
requinix Posted July 30, 2022 Share Posted July 30, 2022 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); } 1 Quote Link to comment https://forums.phpfreaks.com/topic/315114-php-comment-system-handling-replies-of-replies-using-a-loop-of-some-sort/#findComment-1598804 Share on other sites More sharing options...
oz11 Posted July 30, 2022 Author Share Posted July 30, 2022 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); } } ?> Quote Link to comment https://forums.phpfreaks.com/topic/315114-php-comment-system-handling-replies-of-replies-using-a-loop-of-some-sort/#findComment-1598810 Share on other sites More sharing options...
Barand Posted July 30, 2022 Share Posted July 30, 2022 Which bit of "show the comment" do you not understand? 1 Quote Link to comment https://forums.phpfreaks.com/topic/315114-php-comment-system-handling-replies-of-replies-using-a-loop-of-some-sort/#findComment-1598814 Share on other sites More sharing options...
oz11 Posted August 1, 2022 Author Share Posted August 1, 2022 (edited) 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: 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. Edited August 1, 2022 by oz11 count now works! Quote Link to comment https://forums.phpfreaks.com/topic/315114-php-comment-system-handling-replies-of-replies-using-a-loop-of-some-sort/#findComment-1598846 Share on other sites More sharing options...
oz11 Posted August 1, 2022 Author Share Posted August 1, 2022 On 7/30/2022 at 10:08 PM, Barand said: Which bit of "show the comment" do you not understand? Just not sure what to literally put there at the comment. Quote Link to comment https://forums.phpfreaks.com/topic/315114-php-comment-system-handling-replies-of-replies-using-a-loop-of-some-sort/#findComment-1598847 Share on other sites More sharing options...
oz11 Posted August 1, 2022 Author Share Posted August 1, 2022 (edited) <?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? Edited August 1, 2022 by oz11 sorry to spam the forum, just chipping away at a block. Quote Link to comment https://forums.phpfreaks.com/topic/315114-php-comment-system-handling-replies-of-replies-using-a-loop-of-some-sort/#findComment-1598851 Share on other sites More sharing options...
oz11 Posted August 1, 2022 Author Share Posted August 1, 2022 (edited) 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: I feel like I've hit a dead end. Help plz. Edited August 1, 2022 by oz11 Quote Link to comment https://forums.phpfreaks.com/topic/315114-php-comment-system-handling-replies-of-replies-using-a-loop-of-some-sort/#findComment-1598856 Share on other sites More sharing options...
oz11 Posted August 1, 2022 Author Share Posted August 1, 2022 (edited) <?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. 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 August 1, 2022 by oz11 Quote Link to comment https://forums.phpfreaks.com/topic/315114-php-comment-system-handling-replies-of-replies-using-a-loop-of-some-sort/#findComment-1598857 Share on other sites More sharing options...
oz11 Posted August 2, 2022 Author Share Posted August 2, 2022 (edited) 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..? [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 August 2, 2022 by oz11 Quote Link to comment https://forums.phpfreaks.com/topic/315114-php-comment-system-handling-replies-of-replies-using-a-loop-of-some-sort/#findComment-1598880 Share on other sites More sharing options...
mac_gyver Posted August 2, 2022 Share Posted August 2, 2022 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); 1 Quote Link to comment https://forums.phpfreaks.com/topic/315114-php-comment-system-handling-replies-of-replies-using-a-loop-of-some-sort/#findComment-1598885 Share on other sites More sharing options...
oz11 Posted August 2, 2022 Author Share Posted August 2, 2022 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. Quote Link to comment https://forums.phpfreaks.com/topic/315114-php-comment-system-handling-replies-of-replies-using-a-loop-of-some-sort/#findComment-1598886 Share on other sites More sharing options...
oz11 Posted August 2, 2022 Author Share Posted August 2, 2022 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); ?> 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 Quote Link to comment https://forums.phpfreaks.com/topic/315114-php-comment-system-handling-replies-of-replies-using-a-loop-of-some-sort/#findComment-1598893 Share on other sites More sharing options...
mac_gyver Posted August 2, 2022 Share Posted August 2, 2022 you need to do this - 6 hours ago, mac_gyver said: 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 Quote Link to comment https://forums.phpfreaks.com/topic/315114-php-comment-system-handling-replies-of-replies-using-a-loop-of-some-sort/#findComment-1598894 Share on other sites More sharing options...
oz11 Posted August 4, 2022 Author Share Posted August 4, 2022 It actually works perfectly now. Love you mac_gyver . 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. Quote Link to comment https://forums.phpfreaks.com/topic/315114-php-comment-system-handling-replies-of-replies-using-a-loop-of-some-sort/#findComment-1598942 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.