In the spirit of practicing what we preach, before we wrote a single line of code for the appointment management web application, we planned it on paper, including which pages we would write and how the user would progress through them. As shown in Figure 31-3, our application is a series of pages that communicate with the AppointmentManager and some helpers to work with dates and times.
Figure 31-3. Logical structure of our appointment management system.
Our application consists of six primary visual pages and a page to show errors (as discussed in the section, "Displaying Errors to Users"). A number of intermediate scripts are used to process submitted data before moving the user on to one of the other pages in our application. These pages and the possible progressions display as shown in Figure 31-4.
Figure 31-4. Possible page progressions in the appointments sample.
The key pages are as follows:
All three date-based display pagesshowday.php, showweek.php, and showmonth.phpdefault to showing the current day, week, or month, respectively. However, you can provide optional parameters to have them determine which day, week, or month to display, as shown in Table 31-1. For the weekly or monthly views, the application determines the appropriate week or month from the specified date. For example, 2008-03-12 indicates that the week of March 9 until March 15, 2008 should be shown, or the entire month of March, 2008, depending on whether the weekly or monthly view was selected.
Most additional scripts are designed to process input data or otherwise assist these pages in their function. (See the "Complete File Listing" section later in this chapter.)
The database that we will set up for this sample is simple. We begin by creating an Appointments database and users permitted to work with it (MySQL syntax shown):
CREATE DATABASE Appointments DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; GRANT CREATE, DROP, SELECT, UPDATE, INSERT, DELETE ON Appointments.* TO 'appt_admin'@'localhost' IDENTIFIED BY 'appt_admin'; GRANT SELECT, UPDATE, INSERT, DELETE ON Appointments.* TO 'appt_user'@'localhost' IDENTIFIED BY 'appt_user'; USE Appointments; SET NAMES 'utf8';
Notice that the setup script also makes sure that we are correctly using UTF-8 when we communicate with the server.
Although we will not use it much in our initial implementation, we will create a Users table, in case we decide to make this system multiuser in the future. The extra work now is minimal, and we are not prevented from adding some potentially interesting functionality later.
We create the Users table as follows:
CREATE TABLE Users ( user_id INTEGER AUTO_INCREMENT PRIMARY KEY, fullname VARCHAR(200) NOT NULL, email VARCHAR(200) NOT NULL, office VARCHAR(200) NOT NULL, phone VARCHAR(200) );
Our Appointments table will store the following information for an appointment:
The SQL we use to create the Appointments table is as follows:
CREATE TABLE Appointments ( appt_id INTEGER AUTO_INCREMENT PRIMARY KEY, user_id INTEGER NOT NULL, title VARCHAR(200) NOT NULL, start_time DATETIME NOT NULL, end_time DATETIME NOT NULL, location VARCHAR(200), description TEXT, INDEX(start_time), INDEX(end_time) );
Because we will search on the start_time and end_time fields, we create indexes to speed this up.
Finally, we create a default user in our system by adding a record to the Users table. We will just cheat and set the user ID of this user in the $g_userID variable in our scripts, to which we can refer all over the place. Chapter 32, "A Blogging Engine," shows how you can set such a variable in your scripts when working with a true multiuser system.
INSERT INTO Users (fullname, email, office) VALUES('Marc Wandschneider', 'firstname.lastname@example.org', 'Home (Seattle)');
Chapter 14, "Implementing a User Interface," suggested a number of strategies for creating and generating XHTML in web applications. For this particular sample application, we are going to use the method of including at the top and bottom of our page scripts some XHTML content, in files called pagetop.inc and pagebottom.inc.
The pagetop.inc file will contain only the XHTML headers and menu bar that are shown in Figure 31-1:
<!DOCTYPE html PUBLIC "~//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US"> <head> <title><?php echo $page_title; ?></title> <meta http-equiv="content-type" content="text/html; charset=utf-8"/> <link rel="stylesheet" href="basestyle.css" type="text/css"/> </head> <body class='pageBody'> <table border='1' align='center' width='80%' cellspacing='0' cellpadding='0'> <tr> <td> <table width='100%' border='0' cellspacing='0' cellpadding='4' class='topMenuBar'> <tr> <td width='20%' align='center' class='topMenuCell'> <a class='topMenuLink' href='index.php'>Home</a> </td> <td width='20%' align='center' class='topMenuCell'> <a class='topMenuLink' href='addnewappt.php'> New Appointment </a> </td> <td width='20%' align='center' class='topMenuCell'> <a class='topMenuLink' href='showday.php'>Today</a> </td> <td width='20%' align='center' class='topMenuCell'> <a class='topMenuLink' href='showweek.php'> This Week </a> </td> <td width='20%' align='center' class='topMenuCell'> <a class='topMenuLink' href='showmonth.php'> This Month </a> </td> </tr> </table> </td> </tr> </table>
The pagebottom.inc file is extremely trivial. It merely makes sure that our pages are properly closed:
The structure of a visual script in this web application then becomes this:
<?php ob_start(); $page_title = 'Some Page'; require_once('libs/coreincs.inc'); // discussed next require_once('libs/pagetop.inc'); // do some work and output here. require_once('libs/pagebottom.inc'); ob_end_flush(); ?>
As you will note in the pagetop.inc file, we use Cascading Style Sheets (CSS) to perform much of the UI styling in the application, through the basestyle.css file. This file contains classes and other style information that our web application will use to try to reduce clutter in the actual script files.
Complete File Listing
Table 31-2 shows the complete list of files we wrote to run this web application sample. One strategy in this application will be to use a common include file for the many scripts we have to include in our individual scripts. Therefore, instead of having to write the following at the top of every script
include('appts/sessions.inc'); include('appts/errors.inc'); include('appts/appointmentmanager.inc');
we will create a file called coreincs.inc, have it include those scripts, and then include that in our individual scripts. Then, if we want to add any new common include scripts, we do not have to chase through all of our files to add them:
include('appts/coreincs.inc'); // proceed with normal script here.
You might be worried that we have written a lot of code for a simple "sample web application," but as mentioned repeatedly throughout this book, it is critical to do things correctly in an application for our own and our users' security. Fortunately, many of the scripts are short and much of the code we have written is reusable, particularly that pertaining to errors, sessions, and database connection management. We will see these same files and classes in subsequent samples.