euphora Posted July 28, 2010 Share Posted July 28, 2010 Mmm i'm not sure if i'm approaching this correctly. Anyways, I wanted to create a multi-level thread, Where the child thread would be after the parent thread. Something like this: Hello World - Re: Hello World - Hi! - What's up? - Hi Bob! Goodbye World - ....This guy got issues - Dude! You should watch Despicable Me! "It's so fuzzy i'm going to dieee!" Anyways, so my table looks something along the line of this: | post id | parent_id | title | body | date | 1 | NULL | Hello | Hi, i'm K | date 2 | NULL | Thread One | Body One | date 3 | 1 | Re: Hello World | Body One | date 4 | 2 | Thread post 4 | Body One | date 5 | 1 | Thread post 5 | Body One | date 6 | 1 | Thread post 6 | Body One | date 7 | 3 | Hi What's up | Body One | date And here's the PHP code, although it's not very neat I want to clean it up and make it neater. I can only go two level deep so far. Any suggestion or recommendations? Using while & for: // Select * Threads $q = "SELECT * FROM test_db ORDER BY post_id ASC"; $r = @mysql_query($q); while ($pid_row = @mysql_fetch_object($r)) { // Array $pid_arr[] = $pid_row->post_id; // Assign Indexes to Post ID $ppid_arr[] = $pid_row->parent_id; // Assign Indexes to ParentID $md_arr = array($pid_arr, $ppid_arr); // Create multi-dimensional array matrix $parent_id = $pid_row->parent_id; } for ($i = 0; $i < count($pid_arr); $i++) { for ($a = 0; $a < count($ppid_arr); $a++) { $pid = $pid_arr[$i]; // pid = post id $ppid = $ppid_arr[$i]; // ppid = parent id //echo "<div>~~ PID $pid ~~ PPID $ppid ~~</div>"; if ($ppid === NULL) { $ppid_is_null = " & parent_id is NULL"; } else { $ppid_is_null = NULL; } // Select Top level Thread $z = "SELECT * FROM test_db WHERE post_id = '$pid'"; $y = @mysql_query($z); while ($t_row = @mysql_fetch_object($y)) { $title = $t_row->title; // title of child thread $level = $t_row->level; // level of child thread...is this useful? } // Display top level thread lvl 1 if ($ppid === NULL) { // If the parent_id is NULL, display top level thread echo '<div>PID: ' . $pid . ' || PPID: ' . $ppid . " || Title: " . $title . "</div><br>\n"; $post = $pid; // PostID = 1 $parent = $ppid; // Parent ID ex: [1] // Get child id, where parent id = [1] // trying to get the child thread here...but it's not working $child_q = "SELECT * FROM test_db WHERE parent_id = '$post'"; $child_r = @mysql_query($child_q); while($c_row = @mysql_fetch_object($child_r)) { $c_arr[] = $c_row->post_id; $c_ppid_arr[] = $c_row->parent_id; } for ($n = 0; $n < count($c_arr); $n++) { if ($c_ppid_arr[$n] === $post) { echo "<div>$c_arr[$n]</div>"; } } break; //echo "<div>PID: $pid</div>"; } break; } } Using While: <?php require_once('db_connection'); echo '<hr><hr><br>'; // I just realized that selecting * where parent id is null might limit the amount of rows retrieved. // Query to select threads $n = NULL; $q = "SELECT * FROM test_db WHERE (test_db.parent_id is NULL) Order By date ASC"; $r = @mysql_query($q); while ($threads = @mysql_fetch_object($r)){ $pid = $threads->post_id; $sid = $threads->subject_id; $parent_id = $threads->parent_id; $title = $threads->title; $body = $threads->body; echo '<div>PostID: ' . $pid . ' || Parent: ' . $parent_id . ' || SubjectID: ' . $sid . ' || Title: ' . $title . ' || Body: ' . $body . '</div>'; $q2 = "SELECT * FROM test_db WHERE parent_id = '$pid' Order by date DESC"; $r2 = @mysql_query($q2); while ($level2 = @mysql_fetch_object($r2)) { $level2_pid = $level2->post_id; $level = 1.5 *($level2->level); // lvl 2: 3em echo '<div style="text-indent:' . $level . 'em">' . 'PostID: ' . $level2->post_id . ' || ParentID: ' . $level2->parent_id . '</div>'; $q3 = "SELECT * FROM test_db WHERE parent_id = '$level2_pid'"; $r3 = @mysql_query($r3); while ($level3 = @mysql_fetch_object($r3)) { $level3 = 1.5 + $level; echo '<div style="text-indent:' . $level3 . 'em">' . 'PostID: ' . $level3->post_id . ' || ParentID: ' . $level3->parent_id . '</div>'; } } } ?> I'm not a comp. sci major or anything, so I'm learning this as I go. Any help would be greatly appreciated. It seems like the while & for is more practical, but i'm not quiet sure. What am I doing wrong? - K I just joined this forum today Hope to be good friends with you guys and gals Quote Link to comment https://forums.phpfreaks.com/topic/209171-how-can-i-make-a-proper-multi-level-thread-using-parent-child/ Share on other sites More sharing options...
bh Posted July 29, 2010 Share Posted July 29, 2010 Hi, Theres a PHP function to make multithread, its pcntl_fork. Quote Link to comment https://forums.phpfreaks.com/topic/209171-how-can-i-make-a-proper-multi-level-thread-using-parent-child/#findComment-1092467 Share on other sites More sharing options...
euphora Posted July 29, 2010 Author Share Posted July 29, 2010 it seems a bit confusing to me when it talks about time and executing process. Can you show me a very simple sample of how it would work? Quote Link to comment https://forums.phpfreaks.com/topic/209171-how-can-i-make-a-proper-multi-level-thread-using-parent-child/#findComment-1092778 Share on other sites More sharing options...
Alex Posted July 29, 2010 Share Posted July 29, 2010 The function that bh stated isn't for what you want to do at all. Two completely different types of threads. Quote Link to comment https://forums.phpfreaks.com/topic/209171-how-can-i-make-a-proper-multi-level-thread-using-parent-child/#findComment-1092779 Share on other sites More sharing options...
euphora Posted July 29, 2010 Author Share Posted July 29, 2010 ah, that's why I was so confused. What would be an efficient way of doing what I wanted to do? I know it involves a while, foreach/for loop, and as for the array part, i'm still fiddling with it. Quote Link to comment https://forums.phpfreaks.com/topic/209171-how-can-i-make-a-proper-multi-level-thread-using-parent-child/#findComment-1092781 Share on other sites More sharing options...
euphora Posted July 30, 2010 Author Share Posted July 30, 2010 bump Quote Link to comment https://forums.phpfreaks.com/topic/209171-how-can-i-make-a-proper-multi-level-thread-using-parent-child/#findComment-1093302 Share on other sites More sharing options...
DavidAM Posted July 30, 2010 Share Posted July 30, 2010 If you notice, your "q3" (level 3) code is exactly the same as your "q2" (level 2) code, except you had to use different variable names. This is a great opportunity for a function! You are going to have to write a recursive function here. That's just a normal function that calls itself. So, after you output your top level posts (parent_id IS NULL) you would call a function to show its children. The function would output each child and call the function to output its children. Eventually, you should reach a point where there are no more children and it will unwind. Something along these lines: function showChildrenOf($parent_id) { $qry = "SELECT * FROM test_db WHERE parent_id = '$parent_id' Order by date DESC"; $res = @mysql_query($qry); while ($levelObj = @mysql_fetch_object($res)) { $level_pid = $levelObj->post_id; $level = 1.5 *($levelObj->level); // lvl 2: 3em echo '<div style="text-indent:' . $level . 'em">' . 'PostID: ' . $levelObj->post_id . ' || ParentID: ' . $levelObj->parent_id . '</div>'; showChildrenOf($levelObj->post_id); } Note: I just copied your code and made minor changes. I do not recommend or endorse the user of the '@' operator. You need to check $res before the while loop to make sure it has a value. Quote Link to comment https://forums.phpfreaks.com/topic/209171-how-can-i-make-a-proper-multi-level-thread-using-parent-child/#findComment-1093309 Share on other sites More sharing options...
euphora Posted July 30, 2010 Author Share Posted July 30, 2010 My friend told me that 2nd code I posted can only go about 3 or so level deep. How can I make it more than 3 level? Also what does the @ operator do exactly? Quote Link to comment https://forums.phpfreaks.com/topic/209171-how-can-i-make-a-proper-multi-level-thread-using-parent-child/#findComment-1093314 Share on other sites More sharing options...
DavidAM Posted July 30, 2010 Share Posted July 30, 2010 The second code you posted does 3 levels. Period. But the second and third levels are basically the same code, so you could keep copying it to make it how ever many levels you want. If you replace the second and third levels with a call to the function I showed, it will go to an infinite number of levels (theoretically - you will be limited by memory and PHP timeout constraints). function showChildrenOf($parent_id) { $qry = "SELECT * FROM test_db WHERE parent_id = '$parent_id' Order by date DESC"; $res = @mysql_query($qry); while ($levelObj = @mysql_fetch_object($res)) { $level_pid = $levelObj->post_id; $level = 1.5 *($levelObj->level); // lvl 2: 3em echo '<div style="text-indent:' . $level . 'em">' . 'PostID: ' . $levelObj->post_id . ' || ParentID: ' . $levelObj->parent_id . '</div>'; showChildrenOf($levelObj->post_id); } require_once('db_connection'); echo '<hr><hr><br>'; // I just realized that selecting * where parent id is null might limit the amount of rows retrieved. // Query to select threads $n = NULL; $q = "SELECT * FROM test_db WHERE (test_db.parent_id is NULL) Order By date ASC"; $r = @mysql_query($q); while ($threads = @mysql_fetch_object($r)){ $pid = $threads->post_id; $sid = $threads->subject_id; $parent_id = $threads->parent_id; $title = $threads->title; $body = $threads->body; echo '<div>PostID: ' . $pid . ' || Parent: ' . $parent_id . ' || SubjectID: ' . $sid . ' || Title: ' . $title . ' || Body: ' . $body . '</div>'; showChildrenOf($parent_id); } Note: Again, I just copied your code there and I do not have any way of testing it here, but it should get you started down the right road. The '@' operator hides error messages from you. When applied to a statement, if the statement generates any errors, those errors will not be caught or reported. In my opinion, it is better to leave it out, correct any errors during development as they occur, and test the inputs before a function call and the outputs after a function call and handle any exceptions in a user-friendly manner. Quote Link to comment https://forums.phpfreaks.com/topic/209171-how-can-i-make-a-proper-multi-level-thread-using-parent-child/#findComment-1093339 Share on other sites More sharing options...
euphora Posted August 3, 2010 Author Share Posted August 3, 2010 Hiya, I used this one and it works well, but I run into some other issues. Here's the php script function showChildrenOf($parent_id) { $qry = "SELECT * FROM test_db WHERE parent_id = '$parent_id' Order by date DESC"; $res = @mysql_query($qry); while ($levelObj = @mysql_fetch_object($res)) { $level_pid = $levelObj->post_id; $level = 2 *($levelObj->level); // lvl 2: 3em //echo 'test'; //if ($level_pid === $parent_id) { echo '<div style="text-indent:' . $level . 'em">' . 'PostID: ' . $levelObj->post_id . ' || ParentID: ' . $levelObj->parent_id . '</div>'; //} showChildrenOf($levelObj->post_id); } } //require_once('db_connection'); echo '<hr><hr><br>'; // I just realized that selecting * where parent id is null might limit the amount of rows retrieved. // Query to select threads $q = "SELECT * FROM test_db WHERE (test_db.name_id = '1427') Order By date ASC"; $r = @mysql_query($q); while ($threads = @mysql_fetch_object($r)){ $pid = $threads->post_id; $sid = $threads->subject_id; $parent_id = $threads->parent_id; $title = $threads->title; $body = $threads->body; if ($parent_id === NULL) { echo '<div>PostID: ' . $pid . ' || Parent: ' . $parent_id . ' || SubjectID: ' . $sid . ' || Title: ' . $title . ' || Body: ' . $body . '</div>'; } showChildrenOf($parent_id); } What gets outputted is this: http://cbbd.org/db_test4.php [attachment deleted by admin] Quote Link to comment https://forums.phpfreaks.com/topic/209171-how-can-i-make-a-proper-multi-level-thread-using-parent-child/#findComment-1094797 Share on other sites More sharing options...
euphora Posted August 3, 2010 Author Share Posted August 3, 2010 I did a slight modification: function showChildrenOf($parent_id) { $qry = "SELECT * FROM test_db WHERE parent_id = '$parent_id' Order by date DESC"; $res = @mysql_query($qry); while ($levelObj = @mysql_fetch_object($res)) { $level_pid = $levelObj->post_id; // Gets PostID $level = 1.75 *($levelObj->level); // lvl 2: 3em //echo 'test'; //if ($level_pid === $pid) { echo '<div style="text-indent:' . $level . 'em">' . 'PostID: ' . $levelObj->post_id . ' || ParentID: ' . $levelObj->parent_id . '</div>'; //} showChildrenOf($levelObj->post_id); } } //require_once('db_connection'); echo '<hr><hr><br>'; // I just realized that selecting * where parent id is null might limit the amount of rows retrieved. // Query to select threads $q = "SELECT * FROM test_db WHERE (test_db.name_id = '1427') Order By date ASC"; $r = @mysql_query($q); while ($threads = @mysql_fetch_object($r)){ $pid = $threads->post_id; $sid = $threads->subject_id; $parent_id = $threads->parent_id; $title = $threads->title; $body = $threads->body; if ($parent_id === NULL) { echo '<div>PostID: ' . $pid . ' || Parent: ' . $parent_id . ' || SubjectID: ' . $sid . ' || Title: ' . $title . ' || Body: ' . $body . '</div>'; showChildrenOf($pid); // $pid instead of $parent_id } } Link: http://www.cbbd.org/db_test4.php Now, is there an easy way to post a reply thread and assign the correct message level? mm Quote Link to comment https://forums.phpfreaks.com/topic/209171-how-can-i-make-a-proper-multi-level-thread-using-parent-child/#findComment-1094832 Share on other sites More sharing options...
DavidAM Posted August 4, 2010 Share Posted August 4, 2010 With a single button to post a reply, how are you going to know which entry they are replying to? If you want to allow replies directly from the list that you have now. You need to add a link at the end of each list entry. It would be something like: <A href="replyPage.php?replyto=idOfTopic&level=levelOfTopicPlus1">Reply</A> replyPage.php would then use $_GET['replyto'] to get the ParentID of the new post; and use $_GET['level'] to get the level of the new post (make sure you have already added 1 to the topic's level when you build the link (or don't and add it in the reply page)). Actually, if you are only using the level for the output indentation, you don't need it in the database. You can pass it to the initial call of showChildrenOf() and then each resursive call would pass the level it got plus 1 to the next call. Something like this: function showChildrenOf($parent_id, $level_in) { $qry = "SELECT * FROM test_db WHERE parent_id = '$parent_id' Order by date DESC"; $res = @mysql_query($qry); while ($levelObj = @mysql_fetch_object($res)) { $level_pid = $levelObj->post_id; // Gets PostID // INSTEAD OF THIS LINE // $level = 1.75 *($levelObj->level); // lvl 2: 3em // USE THIS LINE $level = 1.75 * ($level_in); //echo 'test'; //if ($level_pid === $pid) { echo '<div style="text-indent:' . $level . 'em">' . 'PostID: ' . $levelObj->post_id . ' || ParentID: ' . $levelObj->parent_id . '</div>'; //} showChildrenOf($levelObj->post_id, $level_in + 1); } } //require_once('db_connection'); echo '<hr><hr><br>'; // I just realized that selecting * where parent id is null might limit the amount of rows retrieved. // Query to select threads $q = "SELECT * FROM test_db WHERE (test_db.name_id = '1427') Order By date ASC"; $r = @mysql_query($q); while ($threads = @mysql_fetch_object($r)){ $pid = $threads->post_id; $sid = $threads->subject_id; $parent_id = $threads->parent_id; $title = $threads->title; $body = $threads->body; if ($parent_id === NULL) { echo '<div>PostID: ' . $pid . ' || Parent: ' . $parent_id . ' || SubjectID: ' . $sid . ' || Title: ' . $title . ' || Body: ' . $body . '</div>'; showChildrenOf($pid, 1); // $pid instead of $parent_id } } By the way, this code is not producing anything different than selecting from the table with parent_id IS NULL. You are skipping the ones that are null, so you may as well just not select them. Performance would be better as the database grows. Also, you probably want an INDEX - not unique - on the parent_id column to help with performance down the road. Quote Link to comment https://forums.phpfreaks.com/topic/209171-how-can-i-make-a-proper-multi-level-thread-using-parent-child/#findComment-1095080 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.