<<

. 70
( 132 .)



>>

Properties:

— product_id

— product

— description
Chapter 12: Catalog 411

Methods:

— fetch_from_db: Retrieve all data about this product from the database

— write_to_db: Write a new or updated product record to the database

— delete_from_db: Remove a product from the database

— print: Display a product to the browser

Knowing this information, and really nothing else, you could write a new script
that displayed a product. The script that follows assumes that a product_id was
passed through the querystring or via a POST.

$p = new Product(array(˜product_id™=>$product_id));
$p->fetch_from_db();
$p->print();

But if we left it at this, your learning experience would be only a fraction of
what it should be. Of course, in the next section, we go over the code in depth. For
one thing, in this application the display of an object is left to the user of the
object ” we use regular functions, rather than having a print method in each object.

Classes
We designed the classes in this application so that most of them look and behave
similarly. As you look at the classes, you should notice that all but the Base class
have methods with similar names. Our hope is that once you understand one class,
the workings of the others will be pretty clear. For this reason, we™re only going to
break down two classes in this chapter. Note that the each method in each class is
extensively commented on the CD. If you have a specific question as to the work-
ing of a snippet of code, you will likely find the answer within the comments.
In the following pages we break down code in the following classes: Base and
Product. For the other classes we describe only how to use the methods and prop-
erties. But once you understand the Product class, the other classes should be easy
enough to figure out.


Please be sure that you have mastered the concepts in Chapter 7 before
reading this section.




Breaking the classes into includes also enables you to selectively reuse specific
classes when you need them. This becomes important in Chapter 14, when we reuse
some of these classes in creating the shopping cart.
412 Part IV: Not So Simple Applications

PHP 5 also has a new feature that gives objects a bit of an advantage over func-
tions. You can create a function named __autoload () that PHP calls whenever
you reference a class that you have not yet declared. This function can then include
the file that declares that class. What this means is that you don™t have to include a
whole raft of class declarations just because you might use them in your script.
Neither do you have to do the bug-prone work of spreading the include statements
throughout your code. We use the __autoload() feature in these examples, but
files that include the class definitions, like the preceding one, are included in a
commented-out version as well ” you can use them if you wish.

BASE
There is usually a base class on which your other classes are built (though it™s not
always named Base). In this application Base contains a set of utilities that all of
the other classes make use of. The class is declared with the following statement:

class Base
{

Next you declare a couple of constants used by methods of the class. They™re not
exactly the most original or purposeful constants you™ll ever see, but are mostly
here as examples:

const ON = TRUE;
const OFF = FALSE;

Now on to the properties. Most of the classes are built to handle reading, writing,
and manipulating data pertaining to a single table in a database. Those common
functions are what the Base class is built to handle, and its properties show that:

var $table = NULL;
var $idfield = NULL;
var $id = NULL;
var $what = NULL;
var $fields = NULL;
var $appname = ˜test™;

var $error = NULL;



The properties are all assigned values of NULL in Base because it™s up to each
child class to fill them in with the values specific to the table it will be handling.
For example, the Product class sets the $table property to products and the
$idfield property to property_id.
Chapter 12: Catalog 413

The $appname property is typically set in the base class of an application ” in
this example, CatalogBase ” because it™s what you use to determine what database
to use when connecting to MySQL.

__construct() In earlier versions of PHP a class™s constructor method ” the
method that is run every time you instantiate a new object of that class ” had to be
given the same name as the class itself. In PHP 5 constructor methods can all be
given the same name, __construct(). Here you are taking any arguments passed
into the class in a new Classname() statement and handing them off to the build()
method, and then setting up the $idfield and $id properties and connecting to the
database:

function __construct()
{
$args = func_get_args();
call_user_func_array(array($this,™build™), $args);
if (!empty($this->idfield))
{
$f = $this->idfield;
$this->id =& $this->$f;
}
if ($this->table !== null)
$this->dbh();
}

dbh() This method shows the use of static variables in methods. As with regular
functions, a static variable retains its value from one call to the next. In the context
of a class method, what that means is that two objects of the same class ” or of
classes that inherit the same class ” make use of the same single static value. This
makes good sense for something like a database connection, as shown in the fol-
lowing code. If you have four objects in your script, after all, they™re all still talking
to the same database (probably), and so they need only the one connection.

function dbh()
{
static $dbh = NULL;
if ($dbh === NULL)
{
$dbh = db_connect($this->appname);
if ($dbh === NULL) {
user_error(
˜Received NULL db connection™
, E_USER_ERROR
);
414 Part IV: Not So Simple Applications

return FALSE;
}
$dbh->setFetchMode(DB_FETCHMODE_ASSOC);
}
return $dbh;
}

build() This method takes a list or array of arguments and uses them to set values
for the properties of the object. We have a couple of points to make here:

— You can use built-in PHP functions to figure out what your objects™
property names are at runtime, and use that information to pay attention
only to incoming values that match those properties. This enables you do
things like
$product->build($_POST);
$style->build($_POST);

knowing that each object picks out from $_POST only the fields that it
needs.
— You can check to see if your class has a method with the same name as
the property you™ve been given a value for. If it does, you can hand that
new value off to that method. This capability makes it easier to ensure
that only legal values are assigned to an object™s properties ” that a
$quantity property is never set to a negative number, for example.

function build()
{
$args = func_get_args();
if (count($args) == 0)
{
return;
}
$simple = array_keys(get_object_vars($this));
$p = parse_arguments($args, $simple);
$args = array_key_remove($p, $simple);
foreach ($args as $k => $v)
{
if (method_exists($this, $k))
call_user_func(array($this,$k),$v);
else
$this->$k = $v;
}
}
Chapter 12: Catalog 415

fetch_simple_query() This method lives to be overwritten. The default is about as
simple as the code here gets. Anticipating the ability of the database to substitute
values into the text of a query, it just returns a query getting everything from a
table to be named later. The purpose of the method is to allow child classes to sub-
stitute less simple queries in their place. Subsequent methods of the Base class can
use these queries. Consider a common example: If you have a table that has multi-
ple lookup values, like a product_type_id field, you can use a query that joins your
main table with the lookup table and returns the appropriate product_type for stor-
age in a property of the object:

function fetch_simple_query()
{
return ˜select * from !™;
}

fetch_simple() Using this method is another step along the path to retrieving a
record from the database and storing it in the object, but fetch_simple() can have
other uses as well. The method requires a table name and optionally accepts a field
name, a value, and an operator (usually just an equals sign). It runs the query sup-
plied by fetch_simple_query() and returns the result. Normally the table name
will be the value from the $table property of the object, but you can also call this
method directly, on any table, querying the value of any single field. That lets you
do something like

$result = $p->fetch_simple(˜products™,™product™,™S%™,™like™);

to get a DB result handle for all of the rows in the products table wherein the
product name begins with s. If nothing else, it saves typing.
Notice that you can use the result of the dbh() method as if it were a property.
Because it returns an object of the DB class (one of DB™s subclasses, to be exact), it
has its own properties and methods you can use, as shown in this example in which
we populate an array with pieces of what will become (thanks to the dbh() func-
tion) a database query:

function fetch_simple($table,$idfield=NULL,$id=NULL,$op=™=™)
{
$result = FALSE;
$bind = array($table);
$query = $this->fetch_simple_query();
if ($idfield !== NULL)
{
$query .= ˜ where ! ! ?™;
$bind[] = $idfield;
$bind[] = nullop($id,$op);
416 Part IV: Not So Simple Applications

$bind[] = $id;
}
$result = $this->dbh()->query($query,$bind);
return $result;
}

fetch_record() This method uses fetch_simple() to get a single record from a
table in the database and return it:

function fetch_record($table=NULL,$idfield=NULL,$id=NULL)
{
if (empty($table))
$table = $this->table;
if (empty($idfield))
$idfield = $this->idfield;
if (empty($id))
$id = $this->id;
$result = $this->fetch_simple($table,$idfield,$id);
if (!$result)
{
return FALSE;
}
$row = $result->fetchRow();
$result->free();
return $row;
}

fetch_from_db() Finally, we come to the method you™ll see most frequently used
in the actual child classes that work with a particular table. This method enables
you to get the record corresponding to a supplied unique ID value, or the ID value

<<

. 70
( 132 .)



>>