<<

. 71
( 132 .)



>>

already specified by the $id property of your object, and to assign the values from
that record to the properties of your object using the building-block methods
described in the beginning of the section on object-orientation in this chapter:

function fetch_from_db($id=NULL)
{
if ($id !== NULL)
{
$this->id = $id;
}
$row = $this->fetch_record(
$this->table
, $this->idfield
, $this->id
Chapter 12: Catalog 417

);
if (!$row)
return FALSE;
$this->build($row);
}

fetch_all() This is just a shortcut method for getting all the records from a table
that match a particular field value. In practice, using DB™s getAll() method is about
as easy.

function fetch_all($table=NULL,$idfield=NULL,$id=NULL,$op=™=™)
{
if (empty($table)) { $table = $this->table; }
$result = $this->fetch_simple($table,$idfield,$id,$op);
if (!$result)
{
return FALSE;
}
$rows = array();
while ($row = $result->fetchRow())
{
$rows[$row[$this->idfield]] = $row;
}
$result->free();
return $rows;
}

delete_from_db() This method deletes a record from the database:

function delete_from_db($id=NULL)
{
if ($id === NULL)
{
$id = $this->id;
}
$result = $this->dbh()->query(
˜delete from ! where ! = ?™
, array($this->table, $this->idfield, $id)
);
return $result;
}

fieldlist() Now we begin building up to the other main purpose of a class, writing
its values to the database. This method hands back a list of fields that, in theory,
418 Part IV: Not So Simple Applications

correspond to the fields of the table the object represents. If the list is not
predefined ” as it generally is ” the method gets a list of fields from the database.
(Note that this is a very MySQL-specific query in that it uses the MySQL reserved
word describe.)

function fieldlist()
{
if (is_array($this->fields) && count($this->fields) > 0)
{
return $this->fields;
}
if ($this->dbh() && $this->table)
{ $this->fields = $this->dbh()->getCol(
“describe {$this->table}”
);
return $this->fields;
}
return NULL;
}

data_fields() You might have a table with 25 fields defined, but use only three of
them in a form. When you write the record out to the database you don™t want to
unwittingly change the other 22 fields. This method returns an associative array of
field names and values built from the properties of the object, leaving out proper-
ties that are NULL or set to empty strings when the corresponding fields in the table
are integers:

function data_fields()
{
$fields = array();
foreach ($this->fieldlist() as $f)
{
if (!isset($this->$f))
continue;
$v = $this->$f;
if ($v === NULL)
continue;
if ($v === ˜™ && strstr($f, ˜_id™))
continue;
$fields[$f] = $v;
}
return $fields;
}
Chapter 12: Catalog 419

create_record() This method inserts into the database a new record corresponding
to the value stored in the properties of the object. It uses the PEAR DB class™
nextId() function to get the next ID value for the table (rather than letting MySQL
automatically assign it ” though in practice PEAR itself is using MySQL™s
auto_increment feature to come up with the new ID value). Generating ID values
is dead simple thanks to DB™s autoPrepare() method, which takes a table name
and an array of column names and values and gives you back a fully-baked insert
query.

function create_record()
{
if ($this->what)
$this->id = $this->dbh()->nextId($this->what);
$data_fields = $this->data_fields();
$stmt = $this->dbh()->autoPrepare(
$this->table
, array_keys($data_fields)
, DB_AUTOQUERY_INSERT
);
$result = $this->dbh()->execute(
$stmt
, array_values($data_fields)
);
return $result;
}

update_record() This method updates the record in the database that corresponds
to the current object, as indicated by the unique ID value in the $id property. Once
again, DB makes it easy.

function update_record()
{
$data_fields = $this->data_fields();
$stmt = $this->dbh()->autoPrepare(
$this->table
, array_keys($data_fields)
, DB_AUTOQUERY_UPDATE
,˜!=?˜
);
$bind = array_values($data_fields);
$bind[] = $this->idfield;
$bind[] = $this->id;
$result = $this->dbh()->execute($stmt,$bind);
return $result;
}
420 Part IV: Not So Simple Applications

write_to_db() This method ties it all together, taking the values in the object and
saving them to the database as a new record or as an update to an existing one:

function write_to_db()
{
$args = func_get_args();
call_user_func_array(array($this,™build™), $args);
$result = FALSE;
$this->id = $this->{$this->idfield};
if ($this->id)
{
$result = $this->update_record();
}
else
{
$result = $this->create_record();
}
return $result;
}

legal_values() You frequently have tables, like status or product_type, that trans-
late a unique ID value to an English word or phrase. This method makes it easy to
use an inherited class built on such a table to get the name for a particular ID
within a script (or vice versa). Note that it stores all the values from the object™s
table in a static variable in the method.


You wouldn™t want to use this method with a million-record table, where
you™d see a big performance problem. Ten is more like it. For large tables,
you™ll need to run individual queries for each validation.



function legal_values($id=NULL, $use_values=NULL)
{
static $values = NULL;
if ($use_values !== NULL)
$values = $use_values;
if ($values === NULL)
$values = $this->fetch_all();
if ($id !== NULL)
{
if (isset($values[$id]))
return $values[$id];
Chapter 12: Catalog 421

elseif (($value = array_search($id, $values)) !== FALSE)
return $value;
else
return FALSE;
}
return $values;
}

transaction() This method enables you to set up a multi-statement transaction
that can span multiple method calls, even when each of those calls is itself normally
a multi-statement transaction. Rather than directly issuing begin and commit
queries to MySQL, the methods call the transaction() method (through a series of
front methods, which we™ll see in the next section), specifying what they want they
want to do and how. If they want to begin a transaction, and one is already in
progress, nothing happens; otherwise a transaction is begun. Similarly, if they want
to commit a transaction that hasn™t begun, nothing happens; otherwise the transac-
tion is committed. If called for, a rollback is always performed immediately, of
course.

function transaction($what=NULL,$how=NULL)
{
static $states = array();
static $state = NULL;

if ($what === self::ON)
{
if ($state !== self::ON)
{
$this->dbh()->query(˜begin™);
$state = self::ON;
}
array_push($states, self::ON);
}
elseif ($what === self::OFF)
{
if ($how !== ˜commit™)
$how = ˜rollback™;
if ($how === ˜rollback™)
$states = array();
else
array_pop($states);
if ($state !== self::OFF && count($states) == 0)
{
422 Part IV: Not So Simple Applications

$this->dbh()->query($how);
$state = self::OFF;
}
}
return $state;
}

begin(), commit(), and rollback() These are the methods actually called by other
methods in the child class. To prevent any more queries from being executed, the
rollback() method issues a fatal error after rolling back the transaction.

function begin()
{
self::transaction(self::ON);
}

function commit()
{
self::transaction(self::OFF,™commit™);
}

function rollback($error=NULL)
{
self::transaction(self::OFF,™rollback™);
if ($error === NULL && isset($this) && isset($this->error))

<<

. 71
( 132 .)



>>