66
767
Viewing the Tree of Articles
public $m_postid;
public $m_title;
public $m_poster;
public $m_posted;
public $m_children;
public $m_childlist;
public $m_depth;
Notice that the
treenode
does not contain the body of the article.There is no need to
load the body until a user goes to the
view_post.php
script.You need to try to make
this process relatively fast because you are doing a lot of data manipulation to display the
tree list and need to recalculate when the page is refreshed or a button is pressed.
These variables follow a naming scheme commonly used in object-oriented applica-
tions—starting variables with
m_
to indicate that they are member variables of the class.
Most of these variables correspond directly to rows from the
header
table in the
database.The exceptions are
$m_childlist
and
$m_depth
.You use the variable
$m_childlist
to hold the replies to this article.The variable
$m_depth
will hold the
number of tree levels that you are down;this information will be used for creating the
display.
The constructor function sets up the values of all the variables, as follows:
public function __construct($postid, $title, $poster, $posted, $children,
$expand, $depth, $expanded, $sublist)
{
// the constructor sets up the member variables, but more
// importantly recursively creates lower parts of the tree
$this->m_postid = $postid;
$this->m_title = $title;
$this->m_poster = $poster;
$this->m_posted = $posted;
$this->m_children =$children;
$this->m_childlist = array();
$this->m_depth = $depth;
When you construct the root
treenode
from
display_tree()
from the main page,you
actually create a
dummy
node with no article associated with it.You pass in some initial
values as follows:
$tree = new treenode($start, ‘’, ‘’, ‘’, 1, true, -1, $expanded, $sublist);
This line creates a root node with a
$postid
of 0 (zero).It can be used to find all the
first-level postings because they have a parent of 0.You set the depth to
-1
because this
node isn’t actually part of the display.All the first-level postings have a depth of 0 and are
located at the far left of the screen.Subsequent depths step toward the right.
58
768
Chapter 31 Building Web Forums
The most important thing that happens in this constructor is that the child nodes of
this node are instantiated.You begin this process by checking whether you need to
expand the child nodes.You perform this process only if a node has some children,and
you have elected to display them:
if(($sublist||$expand) && $children)
{
$conn = db_connect();
You then connect to the database and retrieve all the child posts,as follows:
$query = “select * from header where parent = $postid order by posted”;
$result = $conn->query($query);
Next, you fill the array
$m_childlist
with instances of the
treenode
class,containing
the replies to the post stored in this
treenode
,as follows:
for ($count=0; $row = @$result->fetch_assoc(); $count++)
{
if($sublist||$expanded[ $row[‘postid’] ] == true)
$expand = true;
else
$expand = false;
$this->m_childlist[$count]= new treenode($row[‘postid’],$row[‘title’],
$row[‘poster’],$row[‘posted’],
$row[‘children’], $expand,
$depth+1, $expanded, $sublist);
}
This last line creates the new
treenode
s,following exactly the same process we just
walked through,but for the next level down the tree.This is the recursive part:A parent
tree node calls the
treenode
constructor,passes its own
postid
as parent, and adds one
to its own depth before passing it.
Each
treenode
,in turn,is created and then creates its own children until you run out
of replies or levels that you want to expand to.
After all that’s done,you call the root
treenode
’s display function (back in
display_tree()
),as follows:
$tree->display($row, $sublist);
The
display()
function begins by checking whether this is the dummy root node:
if($this->m_depth > -1)
In this way,the dummy can be left out of the display.You don’t want to completely skip
the root node,though.You do not want it to appear, but it needs to notify its children
that they need to display themselves.
49
769
Viewing the Tree of Articles
The
display()
function then starts drawing the table containing the articles.It uses
the modulus operator (
%
) to decide what color background this row should have (hence
they alternate):
//color alternate rows
echo ‘<tr><td bgcolor = ‘;
if ($row%2)
echo “‘#cccccc’>”;
else
echo “‘#ffffff’>”;
It then uses the
$m_depth
member variable to work out how much to indent the cur-
rent item.If you look back at the figures,you will see that the deeper the level a reply is
on,the further it is indented.You code this as follows:
// indent replies to the depth of nesting
for($i = 0; $i < $this->m_depth; $i++)
{
echo “<img src = ‘images/spacer.gif’ height = ‘22’
width = ‘22’ alt = ‘’ valign = ‘bottom’ />”;
}
The next part of the function works out whether to supply a plus or minus button or
nothing at all:
// display + or - or a spacer
if ( !$sublist && $this->m_children && sizeof($this->m_childlist))
// we’re on the main page, have some children, and they’re expanded
{
// we are expanded - offer button to collapse
echo “<a href = ‘index.php?collapse=”.
$this->m_postid.”#$this->m_postid’
><img src = ‘images/minus.gif’ valign = ‘bottom’
height = ‘22’ width = ‘22’ alt = ‘Collapse Thread’ border = ‘0’
/></a>”;
}
else if(!$sublist && $this->m_children)
{
// we are collapsed - offer button to expand
echo “<a href = ‘index.php?expand=”.
$this->m_postid.”#$this->m_postid’><img src = ‘images/plus.gif’
height = ‘22’ width = ‘22’ alt = ‘Expand Thread’ border = ‘0’
/></a>”;
}
else
{
48
770
Chapter 31 Building Web Forums
// we have no children, or are in a sublist, do not give button
echo “<img src = ‘images/spacer.gif’ height = ‘22’ width = ‘22’
alt = ‘’ valign = ‘bottom’ />”;
Next, you display the actual details of this node:
echo “ <a name = $this->m_postid ><a href =
‘view_post.php?postid=$this->m_postid’>$this->m_title -
$this->m_poster - “.reformat_date($this->m_posted).’</a>’;
echo ‘</td></tr>’;
You then change the color for the next row:
// increment row counter to alternate colors
$row++;
After that,you add some code that will be executed by all
treenode
s, including the root
one,as follows:
// call display on each of this node’s children
// note a node will only have children in its list if expanded
$num_children = sizeof($this->m_childlist);
for($i = 0; $i<$num_children; $i++)
{
$row = $this->m_childlist[$i]->display($row, $sublist);
}
return $row;
Again, this is a recursive function call,which calls on each of this node’s children to dis-
play themselves.You pass them the current row color and get them to pass it back when
they are finished with it so that you can keep track of the alternating color.
That’s it for this class.The code is fairly complex.You might like to experiment with
running the application and then come back to look at it again when you are comfort-
able with what it does.
Viewing Individual Articles
The
display_tree()
call gives you links to a set of articles.If you click one of these
articles, you will go to the
view_post.php
script,with a parameter of the
postid
of the
article to be viewed. Sample output from this script is shown in Figure 31.7.
The
view_post.php
script,shown in Listing 31.6,shows the message body,as well as
the replies to this message.The replies are again displayed as a tree but completely
expanded this time,and without any plus or minus buttons.This is the effect of the
$sublist
switch coming into action.
22
771
Viewing Individual Articles
Figure 31.7 You can now see the message body for this posting.
Listing 31.6 view_post.php—Displays a Single Message Body
<?php
// include function libraries
include (‘include_fns.php’);
$postid = $_GET[‘postid’];
// get post details
$post = get_post($postid);
do_html_header($post[‘title’]);
// display post
display_post($post);
// if post has any replies, show the tree view of them
if($post[‘children’])
{
echo ‘<br /><br />’;
display_replies_line();
display_tree($_SESSION[‘expanded’], 0, $postid);
}
do_html_footer();
?>
60
772
Chapter 31 Building Web Forums
This script uses three main function calls to do its job:
get_post()
,
display_post()
,
and
display_tree()
.The
get_post()
function,shown in Listing 31.7, pulls the func-
tion details out of the database.
Listing 31.7 get_post() Function from discussion_fns.php—Retrieves a
Message from the Database
function get_post($postid)
{
// extract one post from the database and return as an array
if(!$postid) return false;
$conn = db_connect();
//get all header information from ‘header’
$query = “select * from header where postid = $postid”;
$result = $conn->query($query);
if($result->num_rows!=1)
return false;
$post = $result->fetch_assoc();
// get message from body and add it to the previous result
$query = “select * from body where postid = $postid”;
$result2 = $conn->query($query);
if($result2->num_rows>0)
{
$body = $result2->fetch_assoc();
if($body)
{
$post[‘message’] = $body[‘message’];
}
}
return $post;
}
This function, given a
postid
,performs the two queries required to retrieve the message
header and body for that posting and puts them together into a single array,which it
then returns.
The results of the
get_post()
function are then passed to the
display_post()
func-
tion from
output_fns.php
.This function just prints out the array with some HTML
formatting,so we did not include it here.
Finally,the
view_post.php
script checks whether there are any replies to this article
and calls
display_tree()
to show them in the sublist format—that is,fully expanded
with no plusses or minuses.
36
773
Adding New Articles
Adding New Articles
After all that,we can now look at how a new post is added to the forum.A user can add
a post in two ways:first,by clicking on the New Post button in the index page, and sec-
ond,by clicking on the Reply button on the
view_post.php
page.
These actions both activate the same script,
new_post.php
,just with different param-
eters.Figure 31.8 shows the output from
new_post.php
after it is reached by clicking
the Reply button.
Figure 31.8 In replies, the text of the original message is automatically
inserted and marked.
First, look at the URL shown in the figure:
http://localhost/phpmysql3e/chapter31/new_post.php?parent=18
The parameter passed in as
parent
will be the parent
postid
of the new posting.If you
click New Post instead of Reply,you will get
parent=0
in the URL.
Second,you can see that,in a reply,the text of the original message is inserted and
marked with a
>
character, as is the case in most mail and news-reading programs.
Third,you can see that the title of this message defaults to the title of the original
message prefixed with
Re:
.
Let’s look at the code that produces this output; it is shown in Listing 31.8.
38
774
Chapter 31 Building Web Forums
Listing 31.8 new_post.php—Allows a User to Type a New Post or Reply to an
Existing Post
<?php
include (‘include_fns.php’);
$title = $_POST[‘title’];
$poster = $_POST[‘poster’];
$message = $_POST[‘message’];
if(isset($_GET[‘parent’]))
$parent = $_GET[‘parent’];
else
$parent = $_POST[‘parent’];
if(!$area)
$area = 1;
if(!$error)
{
if(!$parent)
{
$parent = 0;
if(!$title)
$title = ‘New Post’;
}
else
{
// get post name
$title = get_post_title($parent);
// append Re:
if(strstr($title, ‘Re: ‘) == false )
$title = ‘Re: ‘.$title;
//make sure title will still fit in db
$title = substr($title, 0, 20);
//prepend a quoting pattern to the post you are replying to
$message = add_quoting(get_post_message($parent));
}
}
do_html_header($title);
display_new_post_form($parent, $area, $title, $message, $poster);
47
775
Adding New Articles
if($error)
{
echo ‘Your message was not stored.
Make sure you have filled in all fields and try again.’;
}
do_html_footer();
?>
After some initial setup,the
new_post.php
script checks whether the parent is 0 (zero)
or otherwise.If it is 0,this topic is new,and little further work is needed.
If this message is a reply (
$parent
is the
postid
of an existing article),the script goes
ahead and sets up the title and text of the original message,as follows:
// get post name
$title = get_post_title($parent);
// append Re:
if(strstr($title, ‘Re: ‘) == false )
$title = ‘Re: ‘.$title;
//make sure title will still fit in db
$title = substr($title, 0, 20);
//prepend a quoting pattern to the post you are replying to
$message = add_quoting(get_post_message($parent));
The functions used here are
get_post_title()
,
get_post_message()
,and
add_
quoting()
.These functions,all from the
discussion_fns.php
library, are shown in
Listings 31.9,31.10,and 31.11, respectively.
Listing 31.9 get_post_title() Function from discussion_fns.php—Retrieves a
Message’s Title from the Database
function get_post_title($postid)
{
// extract one post’s name from the database
if(!$postid) return ‘’;
$conn = db_connect();
Listing 31.8 Continued
35
776
Chapter 31 Building Web Forums
//get all header information from ‘header’
$query = “select title from header where postid = $postid”;
$result = $conn->query($query);
if($result->num_rows!=1)
return ‘’;
$this_row = $result->fetch_array();
return $this_row[0];
}
Listing 31.10 get_post_message() Function from discussion_fns.php—
Retrieves a Message’s Body from the Database
function get_post_message($postid)
{
// extract one post’s message from the database
if(!$postid) return ‘’;
$conn = db_connect();
$query = “select message from body where postid = $postid”;
$result = $conn->query($query);
if($result->num_rows>0)
{
$this_row = $result->fetch_array();
return $this_row[0];
}
}
These first two functions retrieve an article’s header and body,respectively,from the
database.
Listing 31.11 add_quoting() Function from discussion_fns.php—Indents a
Message Text with > Symbols
function add_quoting($string, $pattern = ‘> ‘)
{
// add a quoting pattern to mark text quoted in your reply
return $pattern.str_replace(“\n”, “\n$pattern”, $string);
}
Listing 31.9 Continued
Documents you may be interested
Documents you may be interested