Table 13-1 summarizes the purpose of each part of the application.Table 13-1.The Purpose of Components in the Community Weather Portal Application weather.php This page contains the data
Trang 1This table stores the date of the forecast, the maximum and minimum temperatures, andthe current weather conditions
The current conditions come from values in the weatherWeatherTypeID field This foreignkey is associated with the weatherType table:
CREATE TABLE weatherType (
weatherTypeID int(11) NOT NULL auto_increment,weatherType varchar(40) default NULL,
PRIMARY KEY (weatherTypeID)) TYPE=MyISAM;
The last section of the SQL script inserts the default weather conditions into theweatherType table:
INSERT INTO weatherType VALUES (1,'hot');
INSERT INTO weatherType VALUES (2,'sunny');
INSERT INTO weatherType VALUES (3,'windy');
INSERT INTO weatherType VALUES (4,'cloudy');
INSERT INTO weatherType VALUES (5,'rain');
INSERT INTO weatherType VALUES (6,'rainstorms');
INSERT INTO weatherType VALUES (7,'snow');
INSERT INTO weatherType VALUES (8,'snowstorms');
Each of these weather types has an associated image in the images folder
In phpMyAdmin, switch to the SQL section and copy and paste the contents of theweather.sql file into the Run SQL queries section of the page, as shown in Figure 13-3
Figure 13-3.Running the SQL script in phpMyAdmin
Trang 2Click the Go button to run the script You should see a message stating that the SQL queryhas been executed successfully The left-hand side of the page should show the names of six
tables, as in Figure 13-4
Figure 13-4.The completed database
You also need to set the permissions and user details for the database The connectiondetails are stored within the file weather.php:
$wdb_host = 'localhost';
$wdb_user = 'user_weather';
$wdb_pass = 'weatherpassword';
$wdb_name = 'weather';
You may need to alter the host setting for your own system
In phpMyAdmin, switch back to the databases section by choosing (Databases) from thedrop-down list on the left of the screen Click the Privileges link in the central pane and
choose Add a new User
Trang 3Enter the details from weather.php The default username is user_weather, and the defaultpassword is weatherpassword Enter the host details and assign the privileges, as shown inFigure 13-5.
Figure 13-5.The privileges for the user_weather user
Click Go, then set the same database-specific privileges on the weather database You mayalso need to restart MySQL to apply the permissions
Understanding Components of the Weather Portal Application
Before I work through the application, let’s look at its component parts The home page,index.php, is made up of sidebar.php and standard.php The file standard.php is constructedfrom mk_navxml.php and mk_weather.php These pages interact with the XSLT stylesheetsnav.xsl and weather.xsl, and the pages addnew.php and addweather.php Figure 13-6 showsthe interaction between these pages
Trang 4Figure 13-6.The interaction between the components of the Community Weather Portal
applica-tion
Figure 13-7 shows the finished application displaying the temperature for a city
Figure 13-7.The Community Weather Portal
Trang 5Table 13-1 summarizes the purpose of each part of the application.
Table 13-1.The Purpose of Components in the Community Weather Portal Application
weather.php This page contains the database username and password, as well as the
database connection code
index.php This is the home page of the application
standard.css This CSS stylesheet adds styling to XHTML elements
sidebar.php This page contains the sidebar for the application, which provides a
breadcrumb style of navigation through the locations to the home page.standard.php This page determines the content to display
mk_navxml.php This page queries the database and returns an XML document determining
the next level of navigation
nav.xsl This XSLT stylesheet transforms the navigation XML into XHTML
addnew.php This page adds content to the database
mk_weather.php This page queries the database and returns the current weather conditions as
an XML document
weather.xsl This XSLT stylesheet transforms the weather conditions into XHTML.addweather.php This page adds a new weather record to the database
/images/ This folder contains images for the application
I’ll examine these components in more detail in the next section
Trang 6The application identifies four navigation areas: continent, country, area, and city Bypassing these arguments to the script, the application can filter the content displayed on the
index.php page It determines which value(s) are passed and then extracts the filter from the
$_GET array
If you test the page before populating the database content, you’ll see something similar
to the image shown in Figure 13-8
Figure 13-8.The Community Weather Portal without database content
The addnew.php script allows users to enter content for the portal I’ll work through thatpage shortly The code within the index.php page follows:
sys-page through the querystring It uses these variables to determine what data to extract and
display from the database
Trang 7The remainder of the page follows:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Community Weather</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<link href="standard.css" rel="stylesheet" type="text/css" />
<style>
#layHeading {position:absolute;
Trang 8This code sets up the page, links to an external stylesheet, and embeds some stylesheetdeclarations associated with the ids of <div> elements.
The <body> section of the page contains a series of <div> elements The first, layHeading,contains the heading image:
The standard.php page determines whether to display additional levels of navigation—
either countries, areas, or cities If users select a city, this page displays the weather
conditions I’ll work through the page shortly
standard.css
The CSS stylesheet standard.css provides formatting for index.php It contains a set of
stan-dard declarations for elements on the page:
Trang 9The sidebar.php script builds the breadcrumb navigation for the left of the index.php page.Figure 13-9 shows the navigation system Notice that I’ve used Australasia in the example,which isn’t, strictly speaking, a continent
Figure 13-9.The index.php page showing the breadcrumb navigation
The sidebar.php page starts with a link to the home page:
<a href="index.php">Home</a><br />
The page needs to connect to the database, so it must include the weather.php file:
<?php
include_once 'weather.php';
The next block of code determines which of the three navigation variables have been set:
$country, $area, or $city The page doesn’t need to test for the $continent variable, as thehome page is above continent level, and that page has a fixed link
If users are at country level, the page will need to provide a link to the continent ing that country:
contain-if (isset($country)) {
$sql = 'SELECT country.countryContinentID, continent.* ➥
FROM country, continent WHERE countryContinentID=continentID ➥
AND countryID=' $country;
$cRes = mysql_query($sql) or die(mysql_error());
Trang 10The SELECT statement determines the country If the database contains a valid country,the page provides a link.
The application uses the same approach for the area level, where it provides links back tothe area’s country and continent:
if (isset($area)) {
$sql = 'SELECT area.areaCountryID, country.*, continent.* ➥
FROM area, country, continent WHERE areaCountryID=countryID ➥
AND countryContinentID=continentID AND areaID=' $area;
$cRes = mysql_query($sql) or die(mysql_error());
Finally, when users are at a city level, they need to be able to link back to the area, country,and continent:
if (isset($city)) {
$sql = 'SELECT city.cityAreaID, area.*, country.*, continent.* ➥
FROM city, area, country, continent WHERE cityAreaID=areaID ➥
AND areaCountryID=countryID AND countryContinentID=continentID ➥
AND cityID=' $city;
$cRes = mysql_query($sql) or die(mysql_error());
?>
You’ll notice that the SQL statements become more complicated as the page determinesmore levels in the navigation hierarchy
Trang 11The standard.php page determines what content to display on the page If the page has set the
$city variable, the users have chosen a city and wish to see the weather Figure 13-10 showsthe content that displays when the $city variable is set but when there are no weather entries
Figure 13-10.Displaying city details where no weather is entered
If the $city variable hasn’t been set, the page needs to display further navigation so userscan navigate to the city level
The standard.php page follows:
<?php
$xml = new DomDocument();
$xsl = new DomDocument();
if (isset($city)) {include 'mk_weather.php';
$xsl->load('weather.xsl');
}
else {include 'mk_navxml.php';
Trang 12Let’s work through the code in a little more detail First, the page creates two DomDocumentobjects for the XML and XSL documents:
$xsl = new DomDocument();
$inputdom = new DomDocument();
Then it tests to see if the $city variable is set and includes the appropriate document
The code also loads the related XSLT stylesheet:
$proc = new XsltProcessor();
The code then imports the stylesheet and applies the transformation, displaying the put in the page:
out-$xsl = $proc->importStylesheet(out-$xsl);
$newdom = $proc->transformToDoc($xml);
echo $newdom->saveXML();
mk_navxml.php
The mk_navxml.php script is a complicated page responsible for much of the work in the
appli-cation This page creates the XML document that the application uses for the navigation in
the site
The variables passed to the page determine the navigation system There are four types ofnavigation to display:
1. The $area variable is set, so the navigation should display the cities
2. The $country variable is set, so the navigation should display the areas
3. The $continent variable is set, so the navigation should display the countries
4. No variables are set, so the navigation should display a list of continents
Trang 13The application uses the following template for the XML document built from the base content:
<entry> elements to create the links to the subsequent levels of navigation
The structure of the XML document built by the application needs to take into accountthe following scenarios:
1. There are no subnavigation items to display
2. The values in the querystring change and cause an error
3. There are subnavigation items to display
The last scenario is the most likely, but I’ll look at the XML structure that the applicationneeds to produce for each option
Scenario 1: No Subnavigation Items
The first situation I’ll look at is where the users have reached a point in the navigation wherethere are no subnavigation items A sample XML file structure for this scenario follows:
In this structure, I’ve navigated to Western Australia (WA), a state in Australia The
<current> element shows that I’m in an area called WA However, the <items> element doesn’tcontain <entry> tags, as no cities are specified within the area
Scenario 2: Changing Querystring Variables
Users might change the values in the querystring, perhaps changing one of the variables tosee what happens Let’s assume that the URL to generate the XML document in scenario 1 washttp://localhost/weather/index.php?continent=1
Trang 14If users change the URL to http://localhost/weather/index.php?continent=7643, one oftwo things can happen Either the value 7643 refers to a continent in the database, or the id is
invalid In the first case, the application can display the subnavigation for that continent, but
in the second case, it needs to display an error message
The application uses the following XML document structure for this scenario:
Instead of an <items> element, the document includes Error as the value of the <current>
element It also includes an <error> element with an error message that displays to the user
Scenario 3: Dealing with Subnavigation Items
The most likely scenario is that the application displays subnavigation items The structure of
this type of XML document is similar to that shown in scenario 1 The difference is that the
<items> element contains multiple <entry> elements:
Now let’s see how to build the XML document to cope with these different scenarios
Building the XML Document
The mk_navxml.php document starts by including weather.php:
Trang 15The code then sets the document element using the createElement() and appendChild()methods:
$root = $xml->createElement('entries');
$root = $xml->appendChild($root);
The next code block tests which variable has been set: $area, $country, or $continent
It does this in an if/else statement that starts with the lowest navigation level, area:
if (isset($area)) {
If the $city variable is set, the code in standard.php will branch to include themk_weather.php script instead
The code starts by retrieving the current area information from the database:
$sql = 'SELECT * from area WHERE areaID=' $area;
$tres = mysql_query($sql) or die(mysql_error());
It also tests that the area id is valid:
Once the page determines the area, it then needs to select the subnavigation city items:
$sql = 'SELECT * FROM city WHERE cityAreaID =' $area ' ORDER BY city';
$cres = mysql_query($sql) or die(mysql_error());
The code can then use DOM methods to create the <current> element and set the attributes:
$current = $xml->createElement('current', $area_name);
Trang 16Finally, it loops through the results and creates a set of <entry> elements Obviously, ifthere are no cities, it doesn’t create any elements:
while ($crow = mysql_fetch_array($cres)) {
$entry = $xml->createElement('entry', $crow['city']);
$entry->setAttribute('id', $crow['cityID']);
$items->appendChild($entry);
}
Note that I’ve left out the closing brackets to simplify the code
The code repeats this process for the country This time, it returns the areas with thecountry as <entry> elements instead of the cities:
else if (isset($country)) {
$sql = 'SELECT * from country WHERE countryID =' $country;
$tres = mysql_query($sql) or die(mysql_error());
$trow = mysql_fetch_array($tres);
$country_name = $trow['country'];
$sql = 'SELECT * FROM area WHERE areaCountryID =' $country ' ➥
ORDER BY area';
$cres = mysql_query($sql) or die(mysql_error());
$current = $xml->createElement('current', $country_name);
while ($crow = mysql_fetch_array($cres)) {
$entry = $xml->createElement('entry', $crow['area']);
$entry->setAttribute('id', $crow['areaID']);
$items->appendChild($entry);
}}}
Trang 17The page then repeats the process for continents:
else if (isset($continent)) {
$sql = 'SELECT * from continent WHERE continentID =' $continent;
$tres = mysql_query($sql) or die(mysql_error());
$trow = mysql_fetch_array($tres);
$continent_name = $trow['continent'];
$sql = 'SELECT * FROM country WHERE countryContinentID =' $continent ➥
' ORDER BY country';
$cres = mysql_query($sql) or die(mysql_error());
$current = $xml->createElement('current', $continent_name);
while ($crow = mysql_fetch_array($cres)) {
$entry = $xml->createElement('entry', $crow['country']);
$entry->setAttribute('id', $crow['countryID']);
$items->appendChild($entry);
}}}
If none of the variables has been set, users are at the top level of navigation, and the cation must display a list of continents from the database:
appli-else {
$sql = 'SELECT * FROM continent ORDER BY continent';
$cres = mysql_query($sql) or die(mysql_error());
$current = $xml->createElement('current', 'Home');
Trang 18$entry = $xml->createElement('entry', $crow['continent']);
$entry->setAttribute('id', $crow['continentID']);
$items->appendChild($entry);
}}
By the time the script finishes running, it has built an XML document that is transformed
in the standard.php script, as you saw earlier
nav.xsl
Let’s look at the XSLT stylesheet, nav.xsl in more detail This stylesheet transforms the XML
document from the mk_navxml.php page
The stylesheet starts with an XML declaration and the opening <xsl:stylesheet>
element:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
The code creates some XSLT variables to store values that the stylesheet will use:
When the application has an error, the stylesheet displays it in a level 4 heading
If there is no error, it displays the requested details:
<xsl:otherwise>
<h4>Current: <xsl:value-of select="entries/current" /></h4>
The stylesheet uses another <xsl:choose> element to see if there are any subnavigationlinks:
<xsl:choose>
<xsl:when test="$numLinks=0">
Trang 19If there are no links, it displays a message to that effect:
There are currently no <strong><xsl:value-of select="$linksto" />
</strong> entries in the database under
<a><xsl:attribute name="href">index.php?<xsl:value-of select="$linksto" />➥
=<xsl:value-of select="@id" /></xsl:attribute><xsl:value-of select="." />
</a><br />
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
This portion of the template generates XHTML similar to the following:
<p>Please select a country:</p>
<a href="index.php?country=1">Australia</a><br/>
<a href="index.php?country=2">New Zealand</a><br/>
After the stylesheet displays the subnavigation links, it displays a form that allows users toadd a new entry at the current level:
<p>Add a new <xsl:value-of select="$linksto" />:<br />
<form action="addnew.php" method="POST">
The code needs to pass the level at which you’re adding this entry, the id of the parentrecord, and the current navigation level It does this using hidden form fields:
<xsl:text disable-output-escaping="yes">" /> </xsl:text>
The current level determines which table receives the new record The code then insertsthe parent id value into the record The current navigation level redirects users to the currentpage after inserting the record
Trang 20The remainder of the block creates the visible text field and Add button:
<input type="text" name="entry" /> <br />
<input type="submit" value="Add" />
If you add new details, the form action calls the addnew.php script This script inserts the new
record into the appropriate table in the database I’ll break down the page and discuss each
section
To start with, the page includes weather.php to access the database:
<?php
include_once 'weather.php';
Trang 21It then retrieves the details from the form, including the values in the hidden fields:
$sql = 'INSERT into country (country, countryContinentID) ➥
VALUES ("' htmlspecialchars($entry,ENT_QUOTES) '",' $parent ')';break;
case 'area':
$sql = 'INSERT into area (area, areaCountryID) ➥
VALUES ("' htmlspecialchars($entry,ENT_QUOTES) '",' $parent ')';break;
case 'city':
$sql = 'INSERT into city (city, cityAreaID) ➥
VALUES ("' htmlspecialchars($entry,ENT_QUOTES) '",' $parent ')';break;
default:
$sql = '';
break;
}}
Trang 22if (strlen($sql) > 0) { mysql_query($sql) or die(mysql_error());
}header('Location: index.php?' $current '=' $parent);
?>
The $current variable contains the previous navigation level, while $parent contains the
id of that entry I’ve now worked through the code that builds the site navigation
The remainder of the application handles the weather details The mk_weather.php,weather.xsl, and addweather.php scripts deal with the weather details The application uses
the same approach as it did with the navigation The mk_weather.php script generates the
weather XML, which weather.xsl transforms into XHTML The addweather.php page allows
users to add new weather details
mk_weather.php
The mk_weather.php page generates the XML document containing current weather details
It uses the following template:
1. There is no current weather report
2. The values in the querystring change and cause an error
3. There is a current weather report
I’ll work through each scenario
Trang 23Scenario 1: No Current Weather Reports
In the first scenario, the selected city has no current weather reports Figure 13-12 shows howthis appears to users
Figure 13-12.There is no current weather report to display.
The XML document describing the weather in this scenario would appear as follows:
Trang 24ele-The page also contains a form that allows users to add a new weather report To make lifeeasier, the application provides a list of weather types in a drop-down list This information
comes from the <weathertypes> element
Scenario 2: Changing Querystring Variables
The second possibility occurs when users edit the querystring to add an invalid city code This
would produce the following XML document:
This document provides users with an error message
Scenario 3: Current Weather Reports Available
The final scenario shows a current weather report for the selected city The XML document
needs to include the current weather conditions with the possible weather types:
The <temperature> element provides the minimum and maximum temperatures The
<outlook> element is the current outlook for the city It contains one of the predefined weather
types
Now that you’ve seen the XML document structures, I’ll look at the code that builds thesestructures from the database