Reputation:
I am creating nested comment system with reply. comments goes longer and longer in page that is why I wanted to toggle replies.
I already do that auto adding class margins etc.
I have problem with displaying button, show replies button displays under all comments which has parent-id 0, even if it doesn't have the replies.
because of this :
if($parent_id == 0){
$marginleft = 0;
$adclass = "parent";
$adbtn = '<button type="button" class="btn btn-primary btn-xs show_reply">show replies</button>';
}else{
$marginleft = $marginleft + 15;
$adclass = "child";
$adbtn = "";
}
Which is working correct way for the class and margin etc.
Here is the php code :
$post_id = intval($_POST["comment_post_id"]);
$parent = intval('0');
$active = 'Y';
$sth = $pdo->prepare(
"SELECT * FROM comments
JOIN profiles ON comments.com_uid = profiles.ik_uid
WHERE comments.comment_post_id = ?
AND comments.comment_parent_id = ?
AND comments.active = ? ORDER BY comment_id DESC
");
$sth->execute([$post_id, $parent, $active]);
$count = $sth->rowCount();
$output = '';
if($count > 0){
while($row = $sth->fetch()){
if($row['ik_img'] !== ''){
$image = explode('.',$row['ik_img']);
$ik_img = $image[0].".webp";
$ik = $row['ik_img'];
}else{
$ik_img = 'avatar.jpg';
$ik = 'avatar.jpg';
}
if($row['comment_parent_id'] !== $row['comment_id']){
$adclass = "parent";
$adbtn = '<button type="button" class="btn btn-primary btn-xs show_reply">show replies</button>';
}else{
$adclass = "child";
$adbtn = "";
}
$output .= '
<div class="form-group border-bottom '.$adclass.'">
<div class="row">
<div class="col-12"><b>'.htmlspecialchars(ucfirst($row["comment_sender_name"])).'</b> said!</div>
<div class="row">
<div class="col-2 stimg">
<picture>
<source type="image/webp" srcset="uploads/small/'.$ik_img.'">
<img src="uploads/small/'.$ik.'" alt="'.htmlspecialchars($row['comment_sender_name']).'" class="img-fluid">
</picture>
</div>
<div class="col-10 sttext">'.htmlspecialchars($row['comment']).'</div>
</div>
<div class="col-12 sttime">'.htmlspecialchars($row["comment_date"]).'
<button type="button" class="btn btn-primary btn-xs reply" id="'.intval($row["comment_id"]).'">Reply <i class="fas fa-share"></i></button>
</div>
<div class="col-12">'.$adbtn.'</div>
</div>
</div>
';
$output .= get_comments($pdo, intval($row["comment_id"]), intval($row["comment_post_id"]));
}
}
echo $output;
function get_comments($pdo, $parent_id = 0,$post_id, $active = 'Y', $marginleft = 0){
$stmt = $pdo->prepare(
"SELECT * FROM comments
JOIN profiles ON comments.com_uid = profiles.ik_uid
WHERE comments.comment_post_id = ?
AND comments.comment_parent_id = ?
AND comments.active = ? ORDER BY comment_id DESC
");
$stmt->execute([$post_id, $parent_id, $active]);
$count = $stmt->rowCount();
$output = '';
if($count > 0){
if($parent_id == 0){
$marginleft = 0;
$adclass = "parent";
$adbtn = '<button type="button" class="btn btn-primary btn-xs show_reply">show replies</button>';
}else{
$marginleft = $marginleft + 15;
$adclass = "child";
$adbtn = "";
}
while($row = $stmt->fetch()){
if($row['ik_img'] !== ''){
$image = explode('.',$row['ik_img']);
$ik_img = $image[0].".webp";
$ik = $row['ik_img'];
}else{
$ik_img = 'avatar.jpg';
$ik = 'avatar.jpg';
}
$output .= '
<div class="form-group border-bottom '.$adclass.'" style="padding-left:'.$marginleft.'px;">
<div class="row">
<div class="col-12"><b>'.htmlspecialchars(ucfirst($row["comment_sender_name"])).'</b> said!</div>
<div class="row">
<div class="col-2 stimg">
<picture>
<source srcset="uploads/small/'.$ik_img.'" type="image/webp">
<img src="uploads/small/'.$ik.'" alt="'.htmlspecialchars($row['comment_sender_name']).'" class="img-fluid">
</picture>
</div>
<div class="col-10 sttext">'.htmlspecialchars($row['comment']).'</div>
</div>
<div class="col-12 sttime">'.htmlspecialchars($row["comment_date"]).'
<button type="button" class="btn btn-primary btn-xs reply" id="'.intval($row["comment_id"]).'">Reply <i class="fas fa-share"></i></button>
</div>
<div class="col-12">'.$adbtn.'</div>
</div>
</div>
';
$output .= get_comments($pdo, intval($row["comment_id"]), $marginleft);
}
}
return $output;
}
Solved I used multilevel recursive function (Like a multilevel menu) it works fine.
Upvotes: 0
Views: 364
Reputation: 1300
First of all I've saw few mistakes in your code:
Database structure for my example:
CREATE TABLE `comments` (
`comment_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`com_uid` int(10) unsigned DEFAULT NULL,
`comment_parent_id` int(10) unsigned DEFAULT NULL,
`comment_post_id` int(10) unsigned NOT NULL,
`comment` varchar(200) DEFAULT NULL,
`comment_sender_name` varchar(40) DEFAULT NULL,
`active` enum('Y','N') NOT NULL DEFAULT 'Y',
`comment_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`comment_id`),
KEY `com_uid` (`com_uid`),
KEY `comment_parent_id` (`comment_parent_id`),
KEY `comment_post_id` (`comment_post_id`),
KEY `active` (`active`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
PHP Code to generate the html:
$query = '
SELECT
*
FROM
comments
LEFT JOIN
profiles ON (comments.com_uid = profiles.ik_uid)
WHERE
comments.comment_post_id = :post_id AND
comments.active = :active
ORDER BY
comment_date ASC
';
$statement = $pdo->prepare($query);
$statement->execute([':post_id' => $post_id, ':active' => 'Y']);
$count = $statement->rowCount();
$comments = $statement->fetchAll(PDO::FETCH_ASSOC);
$comments = buildNestedComments($comments);
$html = getCommentsHtml($comments);
function getArrayWithKeys($array, $key)
{
$result = [];
foreach ($array as $value) {
$result[$value[$key]] = $value;
}
return $result;
}
function buildNestedComments($comments)
{
$comments = getArrayWithKeys($comments, 'comment_id');
$nestedComments = [];
foreach ($comments as &$comment) {
$parentId = (isset($comment['comment_parent_id']) && !empty($comment['comment_parent_id'])) ? (int)$comment['comment_parent_id'] : null;
if ($parentId === null) {
$nestedComments[] = &$comment;
if (!isset($comment['comments'])) {
$comment['count'] = 0;
$comment['comments'] = [];
}
} else {
if (isset($comments[$parentId])) {
if (!isset($comments[$parentId]['comments'])) {
$comments[$parentId]['count'] = 0;
$comments[$parentId]['comments'] = [];
}
$comments[$parentId]['count']++;
$comments[$parentId]['comments'][] = &$comment;
}
}
}
return $nestedComments;
}
function getCommentsHtml($comments)
{
$html = '';
foreach ($comments as $comment) {
if (
isset($comment['ik_img']) &&
!empty($comment['ik_img'])
) {
$image = explode('.',$comment['ik_img']);
$ik_img = $image[0] . '.webp';
$ik = $comment['ik_img'];
} else {
$ik_img = 'avatar.jpg';
$ik = 'avatar.jpg';
}
$class = (isset($comment['comment_parent_id']) && !empty($comment['comment_parent_id'])) ? 'comment-' . $comment['comment_id'] . ' comment-parent-' . $comment['comment_parent_id'] : 'comment-' . $comment['comment_id'];
$button = '';
$subCommentsHtml = '';
if (
isset($comment['comments']) &&
!empty($comment['comments'])
) {
$button = '<button type="button" class="btn btn-primary btn-xs show_reply">show replies</button>';
$subCommentsHtml = getCommentsHtml($comment['comments']);
}
$html .= '<div class="form-group border-bottom '.$class.'">
<div class="row">
<div class="col-12"><b>' . htmlspecialchars(ucfirst($comment["comment_sender_name"])) . '</b> said!</div>
<div class="row">
<div class="col-2 stimg">
<picture>
<source type="image/webp" srcset="uploads/small/' . $ik_img . '">
<img src="uploads/small/' . $ik . '" alt="'.htmlspecialchars($comment['comment_sender_name']).'" class="img-fluid">
</picture>
</div>
<div class="col-10 sttext">' . htmlspecialchars($comment['comment']) . '</div>
</div>
<div class="col-12 sttime">' . htmlspecialchars($comment["comment_date"]) . '
<button type="button" class="btn btn-primary btn-xs reply" id="' . intval($comment["comment_id"]) . '">Reply <i class="fas fa-share"></i></button>
</div>
<div class="col-12">' . $button . '</div>
<div class="sub-comments">' . $subCommentsHtml . '</div>
</div>
</div>';
}
return $html;
}
As you can see in my example I'm getting all comments at once and after that I've made few things:
comment_id
as key in getArrayWithKeys
functioncomments
key of the array in buildNestedComments
functionsub-comments
for easier management with javascriptThen you will be able to use a little css and javascript to style this html and to show/hide sub comments.
Also you have to think about few points:
Upvotes: 1
Reputation: 11
You said,
"I have problem with displaying button, show replies button displays under all
comments which has parent-id 0, even if it doesn't have the replies.".
I think you can achiave it with sql query - you can calculate column replies_count with sub query. With that info you can modifie php code to draw Show replies (replies_count) btn if they exist.
This would be a query:
SELECT *,
(
select count(*)
from comments cc
where cc.comment_parent_id = c.id
) replies_count
FROM comments c
JOIN profiles ON c.com_uid = profiles.ik_uid
WHERE c.comment_post_id = ?
AND c.comment_parent_id = ?
AND c.active = ? ORDER BY comment_id DESC
And then, in PHP you just use it like this:
if( $row['replies_count'] > 0 ) {
// draw btn
}
Upvotes: 0