Web Database Applications With Php And Mysql (2nd Edition) [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Web Database Applications With Php And Mysql (2nd Edition) [Electronic resources] - نسخه متنی

David Lane, Hugh E. Williams

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید








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 costsan 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 UnitCounterso 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
interfacethus simplifying the use of
FreightCalculator objectsand 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 objectwe
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



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


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.


/ 176