Recursion
Here is a quick example of the recursive solution, using arrays as a mockup of database queries.
Some important notes:
Note the structure: All data fetching and manipulation is done before a single thing is printed out.
This would be far better as an object, which would avoid the GLOBAL
tags inside the functions, but this gets you pointed in that direction.
Recursive functions should always have a test to stop recursion in case something goes awry. This example does not! You could use a static variable to count recursions and stop if some limit is reached.
<?php
// mock data of "select * from comments"
$dbRows = [
1 => ['name' => 'BigBadProducer1', 'comment' => 'I love this vst! I use it all the time!', 'reply_id' => 0],
2 => ['name' => 'DrummaBoy504', 'comment' => 'Hey, this is Drumma from Drum Squad!', 'reply_id' => 0],
3 => ['name' => 'Mike Smith', 'comment' => 'How did you get the vst to sound so good like that...', 'reply_id' => 1],
4 => ['name' => 'BigBadProducer1', 'comment' => 'Yes, I learned how to tweak it from YouTube Mike S...', 'reply_id' => 3],
5 => ['name' => 'SmoothBeatz3', 'comment' => 'Dude, Ive been looking for a vst like this for a l...', 'reply_id' => 0],
6 => ['name' => 'FanBoy123', 'comment' => 'Hey Drumma, when are you going to release a new hi...', 'reply_id' => 2],
7 => ['name' => 'Mike Johnson', 'comment' => 'Hey Fanboy123, why are you such a fanboy of Drum S...', 'reply_id' => 6],
];
// mock data of "select id from comments where reply_id=?"
$children = [];
foreach($dbRows as $id => $row) {
$reply_id = $row['reply_id'];
$children[$reply_id][] = $id;
}
// format row into html
function formatRow($row, $reply_name='unknown') {
$out =<<<FORMATROW
<div class="replies" style="position:relative; margin:auto; width:500px; border:1px solid black; margin-top:1px;">
<div style="width:80%; text-align:center;">{$row['name']} replied to {$reply_name}</div>
<div style="width:80%; text-align:center;">{$row['comment']}<br><br></div>
</div>
FORMATROW;
return $out;
}
// mock of database CRUD function "select * from comments where id=?"
function find($id) {
global $dbRows;
if(array_key_exists($id, $dbRows)) {
return $dbRows[$id];
}
}
// mock of database CRUD function "select id from comments where reply_id=?"
function findChildren($id) {
global $children;
if($id == 0) { return []; }
$out = [];
if(array_key_exists($id, $children)) {
$out = $children[$id];
}
return $out;
}
function getRepliesTo($id) {
// test to end recursion
// if(!$id) { return; }
// get parent name
$row = find($id);
$parent_name = $row['name'];
// start indented list every time a traversal is called
$out = "<ul>\n";
// list of child ids. if no children are found,
// assigns an empty array so that foreach won't barf
$children = findChildren($id);
foreach($children as $cid) {
// if there are children, capture their reply and then call this same function to get replies to this reply
if($reply= find($cid)) {
$out .= ' <li>' . formatRow($reply, $parent_name);
$out .= getRepliesTo($cid);
$out .= "</li>\n";
}
}
$out .= "</ul>\n";
return $out;
}
// print_r(find(1));
// print_r(findChildren(1));
// print_r(findChildren(2));
// print traverse(1);
$id = 1; // $id = (int)$_GET['id'];
$commentData = find($id);
$replyHtml = getRepliesTo($id);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div class="comments" style="position:relative; margin:auto; width:500px; border:1px solid black; margin-top:1px;">
<div><?= $commentData['name'] ?></div>
<div><?= $commentData['comment'] ?><br><br></div>
</div>
<?= replyHtml ?>
</body>
</html>
Materialized Path
Another method would be to use Materialized Path query, which would require a slight change to the reply_id field:
$dbRows = [
1 => ['name' => 'BigBadProducer1', 'comment' => 'I love this vst! I use it all the time!', 'reply_id' => '/0/1'],
2 => ['name' => 'DrummaBoy504', 'comment' => 'Hey, this is Drumma from Drum Squad!', 'reply_id' => '/0/2'],
3 => ['name' => 'Mike Smith', 'comment' => 'How did you get the vst to sound so good like that...', 'reply_id' => '/0/1/3'],
4 => ['name' => 'BigBadProducer1', 'comment' => 'Yes, I learned how to tweak it from YouTube Mike S...', 'reply_id' => '/0/1/3/4'],
5 => ['name' => 'SmoothBeatz3', 'comment' => 'Dude, Ive been looking for a vst like this for a l...', 'reply_id' => '/0/5'],
6 => ['name' => 'FanBoy123', 'comment' => 'Hey Drumma, when are you going to release a new hi...', 'reply_id' => '/0/2/6'],
7 => ['name' => 'Mike Johnson', 'comment' => 'Hey Fanboy123, why are you such a fanboy of Drum S...', 'reply_id' => '/0/2/6/7'],
];
Want to find all descendants of 2? select * from comments where reply_id like '/0/2%'