I'm building a VERY simple threaded message system, primarily for users of my site to communicate bugs and problems to me and each other as I expand my site's functionality. But, I'm having no luck creating a properly nested list of each thread.
I have two tables: Threads and Posts, which I've simplified for presentation here.
The Threads table is substantially like so, ordered by most recently modified thread:
+----+-----------------+---------------------+
| id | thName | thModified |
+----+-----------------+---------------------+
| 5 | Thread Number 5 | 2019-06-29 20:54:59 |
+----+-----------------+---------------------+
| 4 | Thread Number 4 | 2019-06-29 20:45:22 |
+----+-----------------+---------------------+
| 3 | Thread Number 3 | 2019-06-29 20:44:20 |
+----+-----------------+---------------------+
| 2 | Thread Number 2 | 2019-06-29 20:43:00 |
+----+-----------------+---------------------+
| 1 | Thread Number 1 | 2019-06-29 20:39:25 |
+----+-----------------+---------------------+
The Posts table is substantially like so:
+----+------+-----+----------------------------------+
| Id | thID | pID | postMessage |
+----+------+-----+----------------------------------+
| 1 | 1 | 0 | First message of thread number 1 |
+----+------+-----+----------------------------------+
| 2 | 2 | 0 | First message of thread number 2 |
+----+------+-----+----------------------------------+
| 3 | 3 | 0 | First message of thread number 3 |
+----+------+-----+----------------------------------+
| 4 | 4 | 0 | First message of thread number 4 |
+----+------+-----+----------------------------------+
| 5 | 5 | 0 | First message of thread number 5 |
+----+------+-----+----------------------------------+
| 6 | 5 | 5 | First response to post 5 |
+----+------+-----+----------------------------------+
| 7 | 5 | 5 | Second response to post 5 |
+----+------+-----+----------------------------------+
| 8 | 5 | 6 | First response to post 6 |
+----+------+-----+----------------------------------+
| 9 | 1 | 1 | First response to post 1 |
+----+------+-----+----------------------------------+
Where each post is related to a thread on the other table, and parent/child relationships are determined in this table by parsing the parentID column. Posts with "0" as a parent are root nodes.
My basic plan of attack is this:
Sadly, it's the last step that has brought me to an utter standstill for the past 3 days. Using "Thread 5" as an example, after step 2 I have an array that looks like this:
[0] => Array
(
[post_id] => 5
[thread_id] => 5
[parent_id] => 0
[user_id] => 9
[post_message] => First message of thread number 5
[post_created] => 2019-06-29 20:54:59
[thread_title] => Thread Number 5
)
[1] => Array
(
[post_id] => 6
[thread_id] => 5
[parent_id] => 5
[user_id] => 9
[post_message] => First response to post 5
[post_created] => 2019-06-29 21:39:00
[thread_title] => Thread Number 5
)
[2] => Array
(
[post_id] => 7
[thread_id] => 5
[parent_id] => 5
[user_id] => 9
[post_message] => Second response to post 5
[post_created] => 2019-06-29 21:52:00
[thread_title] => Thread Number 5
)
[3] => Array
(
[post_id] => 8
[thread_id] => 5
[parent_id] => 6
[user_id] => 0
[post_message] => First response to post 6
[post_created] => 2019-06-29 21:55:00
[thread_title] => Thread Number 5
)
From that array, I'd like to generate a nested list that looks something like:
Thread Number 5 - First message of thread number 5
Thread Number 5 - Second response to post 5
Thread Number 5 - First response to post 5
Thread Number 5 - First response to post 6
Notice that responses are sorted by post date (most recent first), and of course for subsequent threads I'd like the indentation to go back to the zero location again.
Added to clarify intent: in production each post would be a link that opens to display the full text of the message. Responses would be the same "thread name" with user and date appended. So, for example, the tread might read "Found bug during login" and my response (1st child) would read: "Found bug during login - Chris Conlee 19/07/01 09:10" I realized the example above seems weird without context.
I honestly don't have any code that's working well enough to post it here. At one point I had a recursive routine which only traversed the left-most leg, and then skipped the second response to post 5.
At another point I had a routine which displayed all the nodes in duplicate and triplicate, and the indentation never worked properly.
I apologize profusely, as it seems like it should be a VERY simple exercise, but I just have worked myself into knots trying to get my head around the recursive nature of it, coupled with multiple threads, etc. If anybody can throw me a lifeline it would be HUGELY appreciated.
Well, I finally slowed down and stepped thru the iteration element by element and figured it out.
Feeding an array of posts, relative to a given thread, such as this:
[0] => Array
(
[post_id] => 5
[thread_id] => 5
[parent_id] => 0
[user_id] => 9
[post_message] => First message of thread number 5
[post_created] => 2019-06-29 20:54:59
[thread_title] => Thread Number 5
)
[1] => Array
(
[post_id] => 6
[thread_id] => 5
[parent_id] => 5
[user_id] => 9
[post_message] => First response to post 5
[post_created] => 2019-06-29 21:39:00
[thread_title] => Thread Number 5
)
[2] => Array
(
[post_id] => 7
[thread_id] => 5
[parent_id] => 5
[user_id] => 9
[post_message] => Second response to post 5
[post_created] => 2019-06-29 21:52:00
[thread_title] => Thread Number 5
)
[3] => Array
(
[post_id] => 8
[thread_id] => 5
[parent_id] => 6
[user_id] => 0
[post_message] => First response to post 6
[post_created] => 2019-06-29 21:55:00
[thread_title] => Thread Number 5
)
Into the following method:
public function buildForum($postsToThread, &$forum, $parent_id = 0) {
foreach ($postsToThread as $post) {
$time = strtotime($post['post_created']);
$tmpCurrentAuthorName = $this->getPostAuthor($post['user_id']);
$tmpCurrentThreadTitle = $post['thread_title'];
$tmpCurrentPostDate = date("M d, Y g:i A", $time);
if ($post['parent_id'] == $parent_id) {
$forum .= "<ol><li><a href='/freetools/forumViewPost/" .$post['post_id'] . "'>" . $tmpCurrentThreadTitle .= " by " . $tmpCurrentAuthorName . "</a> on " . $tmpCurrentPostDate . "</li>";
$parent_id = $post['post_id'];
$this->buildForum($postsToThread, $forum, $parent_id);
$parent_id = $post['parent_id'];
$forum .= "</ol>";
}
}
}
Recursively traverses the tree and returns a result similar to:
(source: post-tools.com)