Page 1 of 1

Toggling between a normal site page and a forum entry.

Posted: Fri Oct 01, 2004 11:15 pm
by The Monkey
Hello,

Simply for the learning experience, and the flexibility, I have decided to design my next personal website from the ground up, starting with a blank PHP file, so to speak.

The website will have a message board, and of course, normal web site features like things I have done and other such things.

I have decided to adopt the pretty much standard 3 table design:

1. Directories
2. Topics
3. Comments (Or replies).

When I have a normal web page that I want to select from the database, I would simply call the normal function to display a topic in an ordinary forum... or not.

Obviously, the data needs to be formatted differently for an article on my website than a normal discussion topic.

So, how would you go about telling the function how to display the data?

I've thought of several ways:

1. Declare a constant at the beginning of the script, determining whether the page is a topic or an article

2. Send a variable along with the function to display a topic/article, for instance, $render_as_article = TRUE, to determine how to format the data returned from the database.

3. Simply use the functions to call the query, return the $row = mysql_fetch_array($query);, and then I have an array of the data, and can format it however I choose. This method seems a bit to clunky to me, and would probably require me copying the same script over and over again or creating yet another set of functions.

Any thoughts?

- Monkey

Posted: Fri Oct 01, 2004 11:59 pm
by feyd
3 is the more modular way, I feel. However, you'll want classes (probably) to handle the "bulk" of the work. However, you still have to do some coding for choosing what of the set of things you can display, to display.. among other things like filling in template variables and repeatable sections of the templates and things.

Re: Toggling between a normal site page and a forum entry.

Posted: Sat Oct 02, 2004 6:27 am
by McGruff
If I understand you correctly you plan to have a forum and an articles area (with article comments).
The Monkey wrote:1. Declare a constant at the beginning of the script, determining whether the page is a topic or an article- Monkey
If we call these "resources" that gives you a forum resource and an articles resource. The resource would normally be specified in a GET var like this:

http://www.mysite.com/forum
http://www.mysite.com/articles

Next there are "operations" performed on resources, and parameters associated with the operation:

http://www.mysite.com/forum/viewtopic.php?tid=3664

..is a "viewtopic" operation with topic id 3664. In this case the viewtopic.php script is opened.

You can either map straight to script files or pass everything through a front controller - ie a single index.php file which hands over to other scripts:

http://www.mysite.com/index.php?res=for ... c&tid=3664

Here the index file would watch the res & op GET vars in order to identify a resource and an operation to be performed on that resource. Defining these as constants might be useful; they could be needed later.

Incidentally, URL re-rwriting tricks can turn the link into:

http://www.mysite.com/forum/viewtopic/3664

Although search engines like Google can cope with one or two GET vars, I understand that it doesn't cope well with several so this is something worth looking at.

The key to good design is to separate out different concerns. You could have a forum core for example which you can use in the actual forum area as well as the article comments block. If the core is separate from a presentation layer you can display posts differently in each.

Another important layer is data access. The core should not know where the data is coming from - files, db, whatever. This allows you to swap different databases etc easily.

I started off talking about the third high-level layer: request handling. This receives (and validates) user input then decides how to deal with it, ie which core scripts to call and how to present the client output.

This layer can provide a space for common tasks such as user input validation. User-agent checks might be another; we've recently had a problem on devnetwork with what appear to be spam bots making bogus registrations (user-agent checks aren't conclusive but can help). The design should allow you to easily to add or remove tasks such as these. The php configuration settings auto_append_file (and auto_prepend_file) are one option, or you can do it in scripts. The Intercepting Filter design pattern is commonly used for this.

Separation of concerns should go right down to the micro level ie wrap code up in short functions which do just one thing - it will be difficult to do the high-level separations if you don't.

Really, the best way to do all this is with object-oriented programming and design patterns. Without them, I honestly wouldn't know where to start.

A good source of patterns info for php here: http://www.phppatterns.com (see "Design" section).

Posted: Sat Oct 02, 2004 11:39 am
by The Monkey
Thanks a lot, both of you. I think I better understand what it is I want and need to do, now.

Using objects and functions to query the database for a single result is simple enough: Return the array of the single entry, and you have all of your data, and can sort it out however you want after calling the function.

However, when, for instance, you need all of the users in the database, and say, more information about them then just their username: Their id, their username, and their email, for instance, is this method efficient and clear?

Code: Select all

<?php
function users($user = '')
{
	// If $user is empty, then we query all of the users in the db
	// If it isn't, we return the user
	
	if(!empty($user))
	{
		// Determine whether the variable is an integer or a string
		if(is_int($user))
		{
			$sql = "SELECT * FROM users where id = $user LIMIT 1;";
		}
		else if(is_string($user))
		{
			$sql = "SELECT * FROM users where username = $user LIMIT 1;";
		}
		else
		{
			// Incorrect variable passed, error out
			return FALSE;
			break;
		}
		
		$result = mysql_query($sql);
		return mysql_fetch_array($result);
		break;
	}
	else
	{
		// Return all of the users, via arrays inside arrays
		$sql = mysql_query("SELECT id FROM users ORDER BY id;");

		while($row = mysql_fetch_array($sql))
		{
			$user_id = $row['id'];
			unset($row['id'];
						
			$users[$user_id] = $row;
		}
		
		// use foreach() to extract all the data from the arrays
		return $users;
		break;
	}
}		
?>
Maybe a bit more cleanly spoken this way:

Code: Select all

$users = Array(
     "1" =&gt; Array(
           "username" =&gt; "bob"
           "email" =&gt; "foo@bar.com"
      )

     "2" =&gt; Array(
           "username" =&gt; "david Sm!th"
           "email" =&gt; "bar@foo.com"
      )
)
- Monkey

Edit: I had two queries when selecting all of the users from the database. Completely unnecessary, and fixed now.

Posted: Sat Oct 02, 2004 12:10 pm
by feyd
more often it's a little different:

Code: Select all

<?php
function users($user = '')
    {
        // If $user is empty, then we query all of the users in the db
        // Else, we return the user.
        // Eventually, we will have options to query for just usergroups, etc,
        // but this gives us the general idea
        
        if(is_numeric($user) || !empty($user))
        {
            // Determine whether the variable is an integer 
            if(is_int($user))
            {
                $sql = "SELECT * FROM users where id = $user LIMIT 1";
            }
            else if(is_string($user))
            {
                $sql = "SELECT * FROM users where username = '$user' LIMIT 1";
            }
            else
            {
                // Incorrect variable passed, error out
                return FALSE;
            }
            $query = mysql_query($sql) or die(mysql_error());
            if(mysql_num_rows($query)) return mysql_fetch_assoc($query);
            else return false;
        }
        else
        {
            // Return all of the users, via arrays inside arrays
            $sql = mysql_query("SELECT * FROM users ORDER BY id");
            $users = array();

            while($row = mysql_fetch_assoc($sql))
            {
                $users[$row['id']] = $row;
            }

            // use foreach() to extract all the data from the arrays
            return $users;
        }
}
?>

Posted: Sat Oct 02, 2004 12:34 pm
by The Monkey
Thanks for adding the is_numeric function into that if statement. It wasn't quite fresh in my mind the 0 would register as "empty".

Your other little additions are very nice too. Thanks for your help!