Index
    Preface
      What This Book Is About
      What You Need to Know
      How This Book Is Organized
      How to Use This Book
      Conventions Used in This Book
      Using Code Examples
      How to Contact Us
      Web Site and Code Examples
      Acknowledgments
      Chapter 1.  Database Applications and the Web
      Section 1.1.  The Web
      Section 1.2.  Three-Tier Architectures
      Chapter 2.  The PHP Scripting Language
      Section 2.1.  Introducing PHP
      Section 2.2.  Conditions and Branches
      Section 2.3.  Loops
      Section 2.4.  Functions
      Section 2.5.  Working with Types
      Section 2.6.  User-Defined Functions
      Section 2.7.  A Working Example
      Chapter 3.  Arrays, Strings, and Advanced Data Manipulation in PHP
      Section 3.1.  Arrays
      Section 3.2.  Strings
      Section 3.3.  Regular Expressions
      Section 3.4.  Dates and Times
      Section 3.5.  Integers and Floats
      Chapter 4.  Introduction to Object-Oriented Programming with PHP 5
      Section 4.1.  Classes and Objects
      Section 4.2.  Inheritance
      Section 4.3.  Throwing and Catching Exceptions
      Chapter 5.  SQL and MySQL
      Section 5.1.  Database Basics
      Section 5.2.  MySQL Command Interpreter
      Section 5.3.  Managing Databases and Tables
      Section 5.4.  Inserting, Updating, and Deleting Data
      Section 5.5.  Querying with SQL SELECT
      Section 5.6.  Join Queries
      Section 5.7.  Case Study: Adding a New Wine
      Chapter 6.  Querying Web Databases
      Section 6.1.  Querying a MySQL Database Using PHP
      Section 6.2.  Processing User Input
      Section 6.3.  MySQL Function Reference
      Chapter 7.  PEAR
      Section 7.1.  Overview
      Section 7.2.  Core Components
      Section 7.3.  Packages
      Chapter 8.  Writing to Web Databases
      Section 8.1.  Database Inserts, Updates, and Deletes
      Section 8.2.  Issues in Writing Data to Databases
      Chapter 9.  Validation with PHP and JavaScript
      Section 9.1.  Validation and Error Reporting Principles
      Section 9.2.  Server-Side Validation with PHP
      Section 9.3.  JavaScript and Client-Side Validation
      Chapter 10.  Sessions
      Section 10.1.  Introducing Session Management
      Section 10.2.  PHP Session Management
      Section 10.3.  Case Study: Using Sessions in Validation
      Section 10.4.  When to Use Sessions
      Section 10.5.  PHP Session API and Configuration
      Chapter 11.  Authentication and Security
      Section 11.1.  HTTP Authentication
      Section 11.2.  HTTP Authentication with PHP
      Section 11.3.  Form-Based Authentication
      Section 11.4.  Protecting Data on the Web
      Chapter 12.  Errors, Debugging, and Deployment
      Section 12.1.  Errors
      Section 12.2.  Common Programming Errors
      Section 12.3.  Custom Error Handlers
      Chapter 13.  Reporting
      Section 13.1.  Creating a Report
      Section 13.2.  Producing PDF
      Section 13.3.  PDF-PHP Reference
      Chapter 14.  Advanced Features of Object-Oriented Programming in PHP 5
      Section 14.1.  Working with Class Hierarchies
      Section 14.2.  Class Type Hints
      Section 14.3.  Abstract Classes and Interfaces
      Section 14.4.  Freight Calculator Example
      Chapter 15.  Advanced SQL
      Section 15.1.  Exploring with SHOW
      Section 15.2.  Advanced Querying
      Section 15.3.  Manipulating Data and Databases
      Section 15.4.  Functions
      Section 15.5.  Automating Querying
      Section 15.6.  Table Types
      Section 15.7.  Backup and Recovery
      Section 15.8.  Managing Users and Privileges
      Section 15.9.  Tuning MySQL
      Chapter 16.  Hugh and Dave's Online Wines:A Case Study
      Section 16.1.  Functional and System Requirements
      Section 16.2.  Application Overview
      Section 16.3.  Common Components
      Chapter 17.  Managing Customers
      Section 17.1.  Code Overview
      Section 17.2.  Customer Validation
      Section 17.3.  The Customer Form
      Chapter 18.  The Shopping Cart
      Section 18.1.  Code Overview
      Section 18.2.  The Winestore Home Page
      Section 18.3.  The Shopping Cart Implementation
      Chapter 19.  Ordering and Shipping at the Online Winestore
      Section 19.1.  Code Overview
      Section 19.2.  Credit Card and Shipping Instructions
      Section 19.3.  Finalizing Orders
      Section 19.4.  HTML and Email Receipts
      Chapter 20.  Searching and Authentication in the Online Winestore
      Section 20.1.  Code Overview
      Section 20.2.  Searching and Browsing
      Section 20.3.  Authentication
      Appendix A.  Linux Installation Guide
      Section A.1.  Finding Out What's Installed
      Section A.2.  Installation Overview
      Section A.3.  Installing MySQL
      Section A.4.  Installing Apache
      Section A.5.  Installing PHP
      Section A.6.  What's Needed for This Book
      Appendix B.  Microsoft Windows Installation Guide
      Section B.1.  Installation Overview
      Section B.2.  Installing with EasyPHP
      Section B.3.  What's Needed for This Book
      Appendix C.  Mac OS X Installation Guide
      Section C.1.  Getting Started
      Section C.2.  Installing MySQL
      Section C.3.  Setting Up Apache and PHP
      Section C.4.  What's Needed for This Book
      Appendix D.  Web Protocols
      Section D.1.  Network Basics
      Section D.2.  Hypertext Transfer Protocol
      Appendix E.  Modeling and Designing Relational Databases
      Section E.1.  The Relational Model
      Section E.2.  Entity-Relationship Modeling
      Appendix F.  Managing Sessions in theDatabase Tier
      Section F.1.  Using a Database to Keep State
      Section F.2.  PHP Session Management
      Section F.3.  MySQL Session Store
      Appendix G.  Resources
      Section G.1.  Client Tier Resources
      Section G.2.  Middle-Tier Resources
      Section G.3.  Database Tier Resources
      Section G.4.  Security and Cryptography Resources
      Appendix H.  The Improved MySQL Library
      Section H.1.  New Features
      Section H.2.  Getting Started
      Section H.3.  Using the New Features
    Colophon
    Copyright



 

Previous Section  < Day Day Up >  Next Section

14.4 Freight Calculator Example

The examples we have shown so far in this chapter have been contrived to help illustrate the features of PHP. In this section, we apply these techniques and features discussed in this chapter to improve the freight calculator example we introduced in Chapter 4.

14.4.1 Review of the FreightCalculator

The FreightCalculator class defined in Example 4-9 is used to calculate the cost of delivering an online order. Example 4-9 also define the AirFreightCalculator class that redefines the two protected member functions that do the work of calculating the cost components: perKgTotal( ) and perCaseTotal( ).

FreightCalculator objects, including AirFreightCalculator objects, are constructed with two parameters, the total weight and the number of cases that make up a delivery:

    function _  _construct($numberOfCases, $totalWeight)

    {

        $this->numberOfCases = $numberOfCases;

        $this->totalWeight = $totalWeight;

    }

We also defined the CaseCounter class in Example 4-8 that extends the simple UnitCounter class defined in Example 4-4. A CaseCounter object can be used to accumulate units that make up a delivery and calculate the total weight and number of cases required to pack the order. The following example shows how a CaseCounter is created and used:

// Access to the CaseCounter class definition

require "example.4-8.php";



// Create a CaseCounter object where there are 

// 12 units to a case, and each unit weights 1.2 Kg.

$myOrder = new CaseCounter(12, 1.2);



// Add 5 bottles

$myOrder->add(5);



// Add 11 bottles

$myOrder->add(11);



// Add a case

$myOrder->addCase( );



// Now show me how many cases are required and the total weight

print "My order can be packed in {$myOrder->caseCount( )} and 

       weighs {$myOrder->totalWeight( ) Kg.";

The CaseCounter object is constructed with two parameters: the number of units that fit into a case, and the weight per unit. Once constructed, we can add units or cases to the counter. We describe how the CaseCounter works in Chapter 4.

To calculate the cost of delivering an order, we can create an AirFreightCalculator object using the output from the caseCount( ) and totalWeight( ) functions. Here's how it's done:

// Access to the CaseCounter class definition

require "example.4-8.php";



// Access to the AirFreightCalculator class definition

require "example.4-9.php";



// Create a CaseCounter object where there are 12 units to

// a case, and each unit weights 1.2 Kg.

$myOrder = new CaseCounter(12, 1.2);



// Add 28 bottles

$myOrder->add(28);



// Create an AirFreightCalculator

$air = new AirFreightCalculator($myOrder->caseCount( ), 

                                $myOrder->totalWeight( ))



// Now show me the cost

print "The cost of delivering $myOrder->numberOfUnits( ) bottles

       is $ {$air->totalFreight( )}.";

We can simplify the use of FreightCalculator objects by redefining the FreightCalculator class to use a CaseCounter object rather than passing in individual numeric values. However, a better solution is to use an interface that defines the functions that are required to calculate freight costs—an interface that can be used with classes other than CaseCounter.

14.4.2 Deliverable Interface

Example 14-4 shows the definition of the Deliverable interface that specifies the caseCount( ) and totalWeight( ) functions.

Example 14-4. Delivery interface
<?php



interface Deliverable

{

    function caseCount( );

    function totalWeight( );

}

?>

The CaseCounter class already supports the caseCount( ) and totalWeight( ) functions —caseCount( ) is implemented in the CaseCounter definition, while the totalWeight( ) implementation is inherited from the base class UnitCounter—so the only change required is to use the Deliverable interface. This is shown in Example 14-5.

Example 14-5. The CaseCounter class implementing Deliverable
<?php



// Access to the UnitCounter class definition

require_once "example.4-4.php";



// Access to the Deliverable interface definition

require_once "example.14-4.php";





class CaseCounter extends UnitCounter implements Deliverable

{

    private $unitsPerCase;



    function addCase( )

    {

        $this->add($this->unitsPerCase);

    }



    function caseCount( )

    {

        return ceil($this->numberOfUnits( )/$this->unitsPerCase);

    }



    function _  _construct($caseCapacity, $unitWeight)

    {

        parent::_  _construct($unitWeight);

        $this->unitsPerCase = $caseCapacity;

    }

}

14.4.3 Improving the FreightCalculator

We now turn our attention to improving the FreightCalculator class. Improvements are made in two ways: we modify the class to use objects that support the Deliverable interface—thus simplifying the use of FreightCalculator objects—and we make the class abstract. The improved FreightCalculator class is shown in Example 14-6.

Example 14-6. The improved FreightCalculator class
<?php



// Access to the Deliverable interface definition

require_once "example.14-4.php";



abstract class FreightCalculator

{

    // The Deliverable item

    protected $item;



    function totalFreight( )

    {

        return $this->perCaseTotal( ) + $this->perKgTotal( );

    }



    abstract protected function perCaseTotal( );

    abstract protected function perKgTotal( );



    function _  _construct(Deliverable $item)

    {

        $this->item = $item;

    }

}



?>

While the FreightCalculator class defined in Example 4-9 implements a default pricing scheme, real schemes are implemented in descendant classes that redefine the protected perCaseTotal( ) and perKgTotal( ) functions. We designed the FreightCalculator class to be extended, creating a descendant class for each freight option that is offered by an online store. For example, the AirFreightCalculator class shown in Example 4-9 provides a pricing scheme appropriate for airfreight.

By defining the FreightCalculator class as abstract, we can prevent accidental creation of FreightCalculator objects. We can also remove the misleading implementation that doesn't correspond to any real pricing scheme by declaring the perCaseTotal( ) and perKgTotal( ) functions as abstract:

abstract protected function perCaseTotal( );

abstract protected function perKgTotal( );

PHP 5 allows the abstract and protected keywords to be used in either order.

The improved FreightCalculator class in Example 14-6 also replaces the protected member variables $numberOfCases and $totalWeight with the single protected variable $item. The _ _construct( ) function has also been modified to accept one parameter: a class type hint allowing only Deliverable objects to be passed:

    function _  _construct(Deliverable $item)

    {

        $this->item = $item;

    }

Descendant classes of FreightCalculator must also be modified to use the protected Deliverable member variable $item. Example 14-7 shows two descendant classes: a modified version of the AirFreightCalculator and a RoadFreightCalculator.

Example 14-7. AirFreightCalculator and RoadFreightCalculator
<?php



// Access to the FreightCalculator class

require_once "example.14-6.php";



class AirFreightCalculator extends FreightCalculator

{

     protected function perCaseTotal( )

     {

         return 15 + $this->item->caseCount( ) * 1.00;

     }



     protected function perKgTotal( )

     {

         return $this->item->totalWeight( ) * 0.40;

     }

}



class RoadFreightCalculator extends FreightCalculator

{



     protected function perCaseTotal( )

     {

         $numcases = $this->item->caseCount( );



         if ($numcases < 5)

             return 15;

         else

             return 15 + ($numcases - 5) * 1.50;

     }



     protected function perKgTotal( )

     {

         $weight = $this->item->totalWeight( );



         if ($weight < 50)

             return 0;

         else

             return ($weight - 50) * 0.10;

     }

}



?>

The class AirFreightCalculator calculates freight costs for a single delivery as $15 plus $1 per case and $0.40 per kilogram, while RoadFreightCalculator is a little more complicated with stepped rates for both case counts and total weight.

The member variables and functions that are available from $item can be accessed by chaining together -> access operators. For example, in the RoadFreightCalculator class definition, the number of cases is determined with the following code:

$numcases = $this->item->caseCount( );

14.4.4 Summary of Improvements

The classes we have defined in this section to calculate freight costs have real advantages over the FreightCalculator we presented in Chapter 4:

  • The FreightCalculator class is now defined as abstract, eliminating the risk of accidentally writing code that generate misleading freight costs.

  • We use the Deliverable interface allowing us to safely modify CaseCounter in the future without risk of breaking the FreightCalculator class.

  • Using the Deliverable interface, the FreightCalculator class can now be used with other, non-CaseCounter objects.

To illustrate the last point, consider the ChristmasHamper class in Example 14-8.

Example 14-8. A ChristmasHamper class
<?php



// access to the Deliverable interface

require_once "example.14-4.php";



class ChristmasHamper implements Deliverable

{

    function caseCount( )

    {

        return 1;

    }



    function totalWeight ( )

    {

        return 26.5;

    }



    function description( )

    {

        return "A hamper chock-full of Christmas goodies";

    }

}

?>

The ChristmasHamper class implements the Deliverable interface, so we can calculate the freight costs of ChristmasHamper objects using a FreightCalculator object. The following fragment shows how AirFreightCalculator objects can be created using CaseCounter and ChristmasHamper objects:

$wineOrder = new CaseCounter(12, 1.2);

$hamperOrder = new ChristmasHamper;



$wineOrder->add(10);



// Create two AirFreightCalculator objects

$a = new AirFreightCalculator($wineOrder);

$b = new AirFreightCalculator($hamperOrder);



// prints "Air freight on Christmas Hamper = 26.6"

print "Air freight on Christmas Hamper = {$b-> totalFreight( )}";

14.4.5 Using the Improved Freight Calculator

Example 14-9 demonstrates how the classes developed in this section can be used to build a simple application. The template that works with the script is shown in Example 14-10.

The application is a single web page that shows a table that compares the freight costs for different sized orders. This page might be included with an online store to help a customer choose delivery options when it comes time to purchase an order.

Example 14-9. Freight comparison table
<?php

require_once "HTML/Template/ITX.php";



// Access to the FreightCalculator classes

require_once"example.14-7.php";



// Access to the CaseCounter class

require_once"example.14-5.php";



// Access to the ChristmasHamper class

require_once"example.14-8.php";



$template = new HTML_Template_ITX("./templates");

$template->loadTemplatefile("example.14-10.tpl", true, true);



$exampleOrder = new CaseCounter(12, 1.2);



$air = new AirFreightCalculator($exampleOrder);

$road = new RoadFreightCalculator($exampleOrder);



for ($i = 0; $i < 10; $i++)

{

    $exampleOrder->add(6);



    $template->setCurrentBlock("order");

    $template->setVariable("UNITS", $exampleOrder->numberOfUnits( ));

    $template->setVariable("CASES", $exampleOrder->caseCount( ));

    $template->setVariable("WEIGHT", $exampleOrder->totalWeight( ));

    $template->setVariable("AIR", $air->totalFreight( ));

    $template->setVariable("ROAD", $road->totalFreight( ));

    $template->parseCurrentBlock( );

}



// Create a ChristmasHamper object

$hamper = new ChristmasHamper;

$air = new AirFreightCalculator($hamper);

$road = new RoadFreightCalculator($hamper);



// output the last row for the ChristmasHamper

$template->setCurrentBlock("order");

$template->setVariable("UNITS", "A Christmas hamper");

$template->setVariable("CASES", $hamper->caseCount( ));

$template->setVariable("WEIGHT", $hamper->totalWeight( ));

$template->setVariable("AIR", $air->totalFreight( ));

$template->setVariable("ROAD", $road->totalFreight( ));

$template->parseCurrentBlock( );



$template->show( );

?>

Example 14-10. The template used with Example 14-9
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"

                      "http://www.w3.org/TR/html401/loose.dtd">

<html>

<head>

  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

  <title>Freight Costs</title>

</head>

<body>

<h2>Freight Cost Comparison: Air vs. Road</h2>

<table border='1'>

    <tr>

      <th>Order size</th><th>Cases</th><th>Total Weight (kg)</th>

      <th>Air Freight</th><th>Road Freight</th>

    </tr>

<!-- BEGIN order -->

    <tr>

         <td>{UNITS}</td>

         <td>{CASES}</td>

         <td>{WEIGHT}</td>

         <td>${AIR}</td>

         <td>${ROAD}</td>

    </tr>

<!-- END order -->

</table>

</body>

</html>

To calculate the freight costs for the wine order, AirFreightCalculator and RoadFreightCalculator objects are constructed using the $exampleOrder CaseCounter object. Rates for different-sized orders can be calculated by adding units to the $exampleOrder object—we don't need to create new FreightCalculator objects for each order size. We do this inside the for loop that creates the table rows by adding 6 bottles to the $exampleOrder object:

        $exampleOrder->add(6);

The result of Example 14-9 is shown in Figure 14-2.

Figure 14-2. Freight comparison table
figs/wda2_1402.gif


14.4.6 Class Diagram

The freight calculation example now uses six classes, and one interface definition. Figure 14-3 shows how these definitions are related in a class diagram.

Figure 14-3. Class diagram
figs/wda2_1403.gif


As with Figure 14-1, inheritance is shown with connecting lines and solid arrowheads. In Figure 14-3 we've used additional notation to represent the Deliverable interface and the abstract class FreightCalculator.

The relationship between the FreightCalculator class and the Deliverable interface is shown with a connecting line with an open arrowhead. The open arrowhead indicates where one class uses the capabilities of another.

    Previous Section  < Day Day Up >  Next Section







    Copyright © 2010 | Domen maybe sale - bye this domen