Source for file Table.php
Documentation is available at Table.php
* Error code at instantiation time when the first parameter to the
* constructor is not a PEAR DB object.
define('DB_TABLE_ERR_NOT_DB_OBJECT', -1 );
* Error code at instantiation time when the PEAR DB $phptype is not
define('DB_TABLE_ERR_PHPTYPE', -2 );
* Error code when you call select() or selectResult() and the first
* parameter does not match any of the $this->sql keys.
define('DB_TABLE_ERR_SQL_UNDEF', -3 );
* Error code when you try to insert data to a column that is not in the
define('DB_TABLE_ERR_INS_COL_NOMAP', -4 );
* Error code when you try to insert data, and that data does not have a
* column marked as 'require' in the $this->col array.
define('DB_TABLE_ERR_INS_COL_REQUIRED', -5 );
* Error code when auto-validation fails on data to be inserted.
define('DB_TABLE_ERR_INS_DATA_INVALID', -6 );
* Error code when you try to update data to a column that is not in the
define('DB_TABLE_ERR_UPD_COL_NOMAP', -7 );
* Error code when you try to update data, and that data does not have a
* column marked as 'require' in the $this->col array.
define('DB_TABLE_ERR_UPD_COL_REQUIRED', -8 );
* Error code when auto-validation fails on update data.
define('DB_TABLE_ERR_UPD_DATA_INVALID', -9 );
* Error code when you use a create() flag that is not recognized (must
* be 'safe', 'drop', or boolean false.
define('DB_TABLE_ERR_CREATE_FLAG', -10 );
* Error code at create() time when you define an index in $this->idx
define('DB_TABLE_ERR_IDX_NO_COLS', -11 );
* Error code at create() time when you define an index in $this->idx
* that refers to a column that does not exist in the $this->col array.
define('DB_TABLE_ERR_IDX_COL_UNDEF', -12 );
* Error code at create() time when you define a $this->idx index type
* that is not recognized (must be 'normal' or 'unique').
define('DB_TABLE_ERR_IDX_TYPE', -13 );
* Error code at create() time when you have an error in a 'char' or
* 'varchar' definition in $this->col (usually because 'size' is wrong).
define('DB_TABLE_ERR_DECLARE_STRING', -14 );
* Error code at create() time when you have an error in a 'decimal'
* definition (usually becuase the 'size' or 'scope' are wrong).
define('DB_TABLE_ERR_DECLARE_DECIMAL', -15 );
* Error code at create() time when you define a column in $this->col
* with an unrecognized 'type'.
define('DB_TABLE_ERR_DECLARE_TYPE', -16 );
* Error code at validation time when a column in $this->col has an
define('DB_TABLE_ERR_VALIDATE_TYPE', -17 );
* Error code at create() time when you define a column in $this->col
* with an invalid column name (usually because it's a reserved keyword).
define('DB_TABLE_ERR_DECLARE_COLNAME', -18 );
* Error code at create() time when you define an index in $this->idx
* with an invalid index name (usually because it's a reserved keyword).
define('DB_TABLE_ERR_DECLARE_IDXNAME', -19 );
* Error code at create() time when you define an index in $this->idx
* that refers to a CLOB column.
define('DB_TABLE_ERR_IDX_COL_CLOB', -20 );
* The PEAR class for errors
* The Date class for recasting date and time values
* DB_Table supports these RDBMS engines and their various native data
* types; we need these here instead of in Manager.php becuase the
* initial array key tells us what databases are supported.
$GLOBALS['_DB_TABLE']['type'] = array (
'boolean' => 'DECIMAL(1,0)',
'smallint' => 'SMALLINT',
'double' => 'DOUBLE PRECISION',
'timestamp' => 'CHAR(19)'
'boolean' => 'DECIMAL(1,0)',
'smallint' => 'SMALLINT',
'timestamp' => 'CHAR(19)'
'boolean' => 'DECIMAL(1,0)',
'smallint' => 'SMALLINT',
'timestamp' => 'CHAR(19)'
'boolean' => 'NUMBER(1)',
'smallint' => 'NUMBER(6)',
'integer' => 'NUMBER(11)',
'bigint' => 'NUMBER(19)',
'double' => 'DOUBLE PRECISION',
'timestamp' => 'CHAR(19)'
'boolean' => 'DECIMAL(1,0)',
'smallint' => 'SMALLINT',
'double' => 'DOUBLE PRECISION',
'timestamp' => 'CHAR(19)'
'smallint' => 'SMALLINT',
'timestamp' => 'TIMESTAMP'
* US-English error messages. DB_Table has no other embedded strings, so
* if you want to internationalize, you can modify these for your
* language; just set them before or after including DB_Table.
if (! isset ($GLOBALS['_DB_TABLE']['error'])) {
$GLOBALS['_DB_TABLE']['error'] = array (
* DB_Table is a database API and data type SQL abstraction class.
* DB_Table provides database API abstraction, data type abstraction,
* automated SELECT, INSERT, and UPDATE queries, automated table
* creation, automated validation of inserted/updated column values,
* and automated creation of QuickForm elemnts based on the column
* $Id: Table.php,v 1.10 2004/07/12 15:22:42 pmjones Exp $
* @author Paul M. Jones <pmjones@ciaweb.net>
* The PEAR DB object that connects to the database.
* The table or view in the database to which this object binds.
* Associative array of column definitions.
* Associative array of index definitions.
* Baseline SQL SELECT mappings for select() and selectResult().
* Whether or not to automatically validate data at insert-time.
var $_valid_insert = true;
* Whether or not to automatically validate data at update-time.
var $_valid_update = true;
* When calling select() and selectResult(), use this fetch mode (usually
* a DB_FETCHMODE_* constant). If null, uses whatever is set in the $db
* When fetchmode is DB_FETCHMODE_OBJECT, use this class for each
* returned row. If null, uses whatever is set in the $db
* If there is an error on instantiation, this captures that error.
* This property is used only for errors encountered in the constructor
* at instantiation time. To check if there was an instantiation error...
* $obj =& new DB_Table();
* // ... error handling code here ...
* Whether or not to automatically recast data at insert- and update-time.
var $_auto_recast = true;
* Specialized version of throwError() modeled on PEAR_Error.
* Throws a PEAR_Error with a DB_Table error message based on a
* DB_Table constant error code.
* @param string $code A DB_Table error code constant.
* @param string $extra Extra text for the error (in addition to the
* regular error message).
* @return object PEAR_Error
// get the error message text based on the error code
$text = $GLOBALS['_DB_TABLE']['error'][$code];
// add any additional error text
return PEAR ::throwError ($text, $code);
* If there is an error on instantiation, $this->error will be
* populated with the PEAR_Error.
* @param object &$db A PEAR DB object.
* @param string $table The table name to connect to in the database.
* @param mixed $create The automatic table creation mode to pursue:
* boolean false to not attempt creation, 'safe' to
* create the table only if it does not exist, or
* 'drop' to drop any existing table with the same name
* @return object DB_Table
function DB_Table(&$db, $table, $create = false )
// is the first argument a DB object?
// is the RDBMS supported?
// set the class properties
// should we attempt table creation?
// yes, attempt to create the table with the appropriate
$result = $this->create($create);
if (PEAR ::isError ($result)) {
// problem creating the table
* Is a particular RDBMS supported by DB_Table?
* @param string $phptype The RDBMS type for PHP.
* @return bool True if supported, false if not.
$supported = array_keys($GLOBALS['_DB_TABLE']['type']);
* Returns all or part of the $this->col property array.
* @param mixed $col If null, returns the $this->col property array
* as it is. If string, returns that column name from the $this->col
* array. If an array, returns those columns named as the array
* values from the $this->col array as an array.
* @return mixed All or part of the $this->col property array, or
* boolean false if no matching column names are found.
// by default, return all column definitions
// if the param is a string, only return the column definition
// named by the that string
if (isset ($this->col[$col])) {
// if the param is a sequential array of column names,
// return only those columns named in that array
foreach ($col as $name) {
// param was not null, string, or array
* Returns all or part of the $this->idx property array.
* @param string $col If specified, returns only this index key
* from the $this->col property array.
* @return array All or part of the $this->idx property array.
// by default, return all index definitions
// if the param is a string, only return the index definition
// named by the that string
if (isset ($this->idx[$idx])) {
// if the param is a sequential array of index names,
// return only those indexes named in that array
foreach ($idx as $name) {
// param was not null, string, or array
* Selects rows from the table using one of the 'DB::get*()' methods.
* @param string $sqlkey The name of the SQL SELECT to use from the
* $this->sql property array.
* @param string $filter Ad-hoc SQL snippet to AND with the default
* @param string $order Ad-hoc SQL snippet to override the default
* SELECT ORDER BY clause.
* @param int $start The row number to start listing from in the
* @param int $count The number of rows to list in the result set.
* @return mixed An array of records from the table (if anything but
* 'getOne'), a single value (if 'getOne'), or a PEAR_Error object.
* @see DB_Table::_swapModes()
function select($sqlkey, $filter = null , $order = null ,
$start = null , $count = null )
// build the base command
$sql = $this->buildSQL($sqlkey, $filter, $order, $start, $count);
// set the get*() method name
if (isset ($this->sql[$sqlkey]['get'])) {
// DB_Table assumes you are using a shared PEAR DB object. Other
// scripts using the same object probably expect its fetchmode
// not to change, unless they change it themselves. Thus, to
// provide friendly mode-swapping, we will restore these modes
$restore_mode = $this->db->fetchmode;
$restore_class = $this->db->fetchmode_object_class;
$result = $this->db->$method($sql);
$this->_swapModes ($restore_mode, $restore_class);
* Selects rows from the table as a DB_Result object.
* @param string $sqlkey The name of the SQL SELECT to use from the
* $this->sql property array.
* @param string $filter Ad-hoc SQL snippet to add to the default
* @param string $order Ad-hoc SQL snippet to override the default
* SELECT ORDER BY clause.
* @param int $start The record number to start listing from in the
* @param int $count The number of records to list in the result set.
* @return mixed A PEAR_Error on failure, or a DB_Result object on
* @see DB_Table::_swapModes()
function selectResult($sqlkey, $filter = null , $order = null ,
$start = null , $count = null )
// build the base command
$sql = $this->buildSQL($sqlkey, $filter, $order, $start, $count);
// DB_Table assumes you are using a shared PEAR DB object. Other
// scripts using the same object probably expect its fetchmode
// not to change, unless they change it themselves. Thus, to
// provide friendly mode-swapping, we will restore these modes
$restore_mode = $this->db->fetchmode;
$restore_class = $this->db->fetchmode_object_class;
$result = & $this->db->query ($sql);
$this->_swapModes ($restore_mode, $restore_class);
* Changes the $this->db PEAR DB object fetchmode and
* fetchmode_object_class.
* Becase DB_Table objects tend to use the same PEAR DB object, it
* may sometimes be useful to have one object return results in one
* mode, and have another object return results in a different mode.
* This method allows us to switch DB fetch modes on the fly.
* @param string $new_mode A DB_FETCHMODE_* constant. If null,
* defaults to whatever the DB object is currently using.
* @param string $new_class The object class to use for results when
* the $db object is in DB_FETCHMODE_OBJECT fetch mode. If null,
* defaults to whatever the the DB object is currently using.
function _swapModes ($new_mode, $new_class)
// get the old (current) mode and class
$old_mode = $this->db->fetchmode;
$old_class = $this->db->fetchmode_object_class;
// don't need to swap anything if the new modes are both
// null or if the old and new modes already match.
($old_mode == $new_mode && $old_class == $new_class)) {
// set the default new mode
// set the default new class
$this->db->setFetchMode ($new_mode, $new_class);
* Builds the SQL command from a specified $this->sql element.
* @param string $sqlkey The $this->sql key to use as the basis for the
* @param string $filter A filter to add to the WHERE clause of the
* defined SELECT in $this->sql.
* @param string $order An ORDER clause to override the defined order
* @param int $start The row number to start listing from in the
* @param int $count The number of rows to list in the result set.
* @return mixed A PEAR_Error on failure, or an SQL command string on
function buildSQL($sqlkey, $filter = null , $order = null ,
$start = null , $count = null )
// does the SQL SELECT key exist?
// the SQL clause parts and their default values
// loop through each possible clause
foreach ($part as $key => $val) {
if (! isset ($this->sql[$sqlkey][$key])) {
$part[$key] = $this->sql[$sqlkey][$key];
// add the filter to the WHERE part
$part['where'] .= $filter;
$part['where'] .= " AND ($filter)";
// override the ORDER part
// build up the command string form the parts
foreach ($part as $key => $val) {
// if the part value has not been set, skip it
// add LIMIT if requested
$cmd = $this->db->modifyLimitQuery (
* Inserts a single table row after validating through validInsert().
* @param array $data An associative array of key-value pairs where
* the key is the column name and the value is the column value. This
* is the data that will be inserted into the table. Data is checked
* against the column data type for validity.
* @return mixed Void on success, a PEAR_Error object on failure.
// forcibly recast the data elements to their proper types?
if ($this->_auto_recast) {
// validate the data if auto-validation is turned on
if ($this->_valid_insert) {
if (PEAR ::isError ($result)) {
return $this->db->autoExecute ($this->table, $data,
* Turns on (or off) automatic validation of inserted data.
* @param bool $flag True to turn on auto-validation, false to turn it off.
if ($flag === true || $flag === false ) {
$this->_valid_insert = $flag;
$this->_valid_insert = true;
$this->_valid_insert = false;
* Validates an array for insertion into the table.
* @param array $data An associative array of key-value pairs where
* the key is the column name and the value is the column value. This
* is the data that will be inserted into the table. Data is checked
* against the column data type for validity.
* @return mixed Boolean true on success, a PEAR_Error object on
// loop through the data, and disallow insertion of unmapped
foreach ($data as $col => $val) {
if (! isset ($this->col[$col])) {
// loop through each column mapping, and check the data to be
// inserted into it against the column data type. we loop through
// column mappings instead of the insert data to make sure that
// all necessary columns are being inserted.
foreach ($this->col as $col => $val) {
// is the value allowed to be null?
if (isset ($val['require']) &&
$val['require'] == true &&
(! isset ($data[$col]) || is_null($data[$col]))) {
// does the value to be inserted match the column data type?
if (isset ($data[$col]) &&
! $this->isValid($data[$col], $col)) {
* Updates table row(s) matching a custom WHERE clause, after checking
* @param array $data An associative array of key-value pairs where
* the key is the column name and the value is the column value. These
* are the columns that will be updated with new values.
* @param string $where An SQL WHERE clause limiting which records
* @return mixed Void on success, a PEAR_Error object on failure.
function update($data, $where)
// forcibly recast the data elements to their proper types?
if ($this->_auto_recast) {
// validate the data if auto-validation is turned on
if ($this->_valid_update) {
if (PEAR ::isError ($result)) {
return $this->db->autoExecute ($this->table, $data,
DB_AUTOQUERY_UPDATE , $where);
* Turns on (or off) automatic validation of updated data.
* @param bool $flag True to turn on auto-validation, false to turn it off.
if ($flag === true || $flag === false ) {
$this->_valid_update = $flag;
$this->_valid_update = true;
$this->_valid_update = false;
* Validates an array for updating the table.
* @param array $data An associative array of key-value pairs where
* the key is the column name and the value is the column value. This
* is the data that will be inserted into the table. Data is checked
* against the column data type for validity.
* @return mixed Boolean true on success, a PEAR_Error object on
// loop through each data element, and check the
// data to be updated against the column data type.
foreach ($data as $col => $val) {
// does the column exist?
if (! isset ($this->col[$col])) {
$defn = $this->col[$col];
// is it allowed to be null?
if (isset ($defn['require']) &&
$defn['require'] == true &&
// does the value to be inserted match the column data type?
if (! $this->isValid($data[$col], $col)) {
* Deletes table rows matching a custom WHERE clause.
* @param string $where The WHERE clause for the delete command.
* @return mixed Void on success or a PEAR_Error object on failure.
return $this->db->query (" DELETE FROM $this->table WHERE $where" );
* Generates a sequence value; sequence name defaults to the table name.
* @param string $seq_name The sequence name; defaults to _table_id.
* @return integer The next value in the sequence.
function nextID($seq_name = null )
$seq_name = " _{$this->table}_id ";
$seq_name = "_{ $this->table}_{ $seq_name}";
return $this->db->nextId ($seq_name);
* Escapes and enquotes a value for use in an SQL query.
* Helps makes user input safe against SQL injection attack.
* @return string The value with quotes escaped, and inside single quotes.
* @see DB_Common::quoteSmart()
return $this->db->quoteSmart ($val);
* Returns a blank row array based on the column map.
* The array keys are the column names, and all values are set to null.
* @return array An associative array where the key is column name
foreach ($this->col as $key => $val) {
* Turns on (or off) automatic recasting of insert and update data.
* @param bool $flag True to autmatically recast insert and update data,
function autoRecast($flag = true)
if ($flag === true || $flag === false) {
$this->_valid_insert = $flag;
$this->_valid_insert = true;
$this->_valid_insert = false;
* Forces array elements to the proper types for their columns.
* This will not valiate the data, and will forcibly change the data
* to match the recast-type.
* The date, time, and timestamp recasting has special logic for
* arrays coming from an HTML_QuickForm object so that the arrays
* are converted into properly-formatted strings.
* @todo If a column key holds an array of values (say from a multiple
* select) then this method will not work properly; it will recast the
* value to the string 'Array'. Is this bad?
* @param array &$data The data array to re-cast.
$keys = array_keys($data);
foreach ($keys as $key) {
if (! isset($this->col[$key])) {
switch ($this->col[$key]['type']) {
// the date is in HTML_QuickForm format,
? '0'.$val['m'] : $val['m'];
? '0'.$val['d'] : $val['d'];
// convert using the Date class
$val = $tmp->format ('%Y-%m-%d');
// the time is in HTML_QuickForm format,
? '0' . $val['H'] : $val['H'];
? '0' . $val['i'] : $val['i'];
? '0' . $val['s'] : $val['s'];
// date does not matter in this case, so
// pre 1970 and post 2040 are not an issue.
$tmp = strtotime(date('Y-m-d') . " $val");
$val = date('H:i:s', $tmp);
// timestamp is in HTML_QuickForm format,
? '0'.$val['m'] : $val['m'];
? '0'.$val['d'] : $val['d'];
? '0' . $val['H'] : $val['H'];
? '0' . $val['i'] : $val['i'];
? '0' . $val['s'] : $val['s'];
$val = "$y-$m-$d $h:$i:$s";
// convert using the Date class
$val = $tmp->format ('%Y-%m-%d %H:%M:%S');
settype($val, 'integer');
* Creates the table based on $this->col and $this->idx.
* @param mixed $flag Boolean false to abort the create attempt from
* the start, 'drop' to drop the existing table and
* re-create it, or 'safe' to only create the table if it
* does not exist in the database.
* @return mixed Boolean false if there was no attempt to create the
* table, boolean true if the attempt succeeded, or a PEAR_Error if
* @see DB_Table_Manager::create()
// are we OK to create the table?
// forcibly drop an existing table
$this->db->query ("DROP TABLE { $this->table}" );
// create only if table does not exist
$list = $this->db->getListOf ('tables');
// ok to create only if table does not exist
$ok = (! in_array ($this->table, $list));
DB_TABLE_ERR_CREATE_FLAG ,
// are we going to create the table?
include_once 'DB/Table/Manager.php';
return DB_Table_Manager::create(
* Checks if a value validates against the DB_Table data type for a
* given column. This only checks that it matches the data type; it
* does not do extended validation.
* @param array $val A value to check against the column's DB_Table
* @param array $col A column name from $this->col.
* @return boolean True if the value validates (matches the
* data type), false if not.
function isValid($val, $col)
// is the column required?
// not required, so it's valid
// make sure we have the validation class
include_once 'DB/Table/Valid.php';
// validate values per the column type
$map = array_keys($GLOBALS['_DB_TABLE']['type']['sqlite']);
// is the column type on the map?
if (! in_array($this->col[$col]['type'], $map)) {
DB_TABLE_ERR_VALIDATE_TYPE ,
"'$col' ('{ $this->col[$col]['type']}')"
switch ($this->col[$col]['type']) {
$result = DB_Table_Valid::isChar(
$result = DB_Table_Valid ::isDecimal (
$this->col[$col]['size'],
$this->col[$col]['scope']
$result = call_user_func (
'is' . ucwords ($this->col[$col]['type'])
// have we passed the check so far, and should we
// also check for allowed values?
if ($result && isset($this->col[$col]['qf_vals'])) {
array_keys($this->col[$col]['qf_vals'])
* Is a specific column required to be set and non-null?
* @param mixed $column The column to check against.
* @return boolean True if required, false if not.
function isRequired($column)
if (isset($this->col[$column]['require']) &&
$this->col[$column]['require'] == true ) {
* Creates and returns a QuickForm object based on table columns.
* @param array $columns A sequential array of column names to use in
* the form; if null, uses all columns.
* @param string $array_name By default, the form will use the names
* of the columns as the names of the form elements. If you pass
* $array_name, the column names will become keys in an array named
* @param array $args An associative array of optional arguments to
* pass to the QuickForm object. The keys are...
* 'formName' : String, name of the form; defaults to the name of this
* 'method' : String, form method; defaults to 'post'.
* 'action' : String, form action; defaults to
* $_SERVER['REQUEST_URI'].
* 'target' : String, form target target; defaults to '_self'
* 'attributes' : Associative array, extra attributes for <form>
* tag; the key is the attribute name and the value is attribute
* 'trackSubmit' : Boolean, whether to track if the form was
* submitted by adding a special hidden field
* @return object HTML_QuickForm
* @see DB_Table_QuickForm
function &getForm($columns = null, $array_name = null, $args = array(),
include_once 'DB/Table/QuickForm.php';
return DB_Table_QuickForm ::getForm ($coldefs, $array_name, $args,
* Adds elements and rules to a pre-existing HTML_QuickForm object.
* @param object &$form An HTML_QuickForm object.
* @param array $columns A sequential array of column names to use in
* the form; if null, uses all columns.
* @param string $array_name By default, the form will use the names
* of the columns as the names of the form elements. If you pass
* $array_name, the column names will become keys in an array named
* @see DB_Table_QuickForm
function addFormElements(&$form, $columns = null, $array_name = null,
include_once 'DB/Table/QuickForm.php';
DB_Table_QuickForm ::addElements ($form, $coldefs, $array_name);
DB_Table_QuickForm ::addRules ($form, $coldefs, $array_name,
* Creates and returns an array of QuickForm elements based on an
* array of DB_Table column names.
* @param array $columns A sequential array of column names to use in
* the form; if null, uses all columns.
* @param string $array_name By default, the form will use the names
* of the columns as the names of the form elements. If you pass
* $array_name, the column names will become keys in an array named
* @return array An array of HTML_QuickForm_Element objects.
* @see DB_Table_QuickForm
function &getFormGroup($columns = null, $array_name = null)
include_once 'DB/Table/QuickForm.php';
return DB_Table_QuickForm ::getGroup ($coldefs, $array_name);
* Creates and returns a single QuickForm element based on a DB_Table
* @param string $column A DB_Table column name.
* @param string $elemname The name to use for the generated QuickForm
* @return object HTML_QuickForm_Element
* @see DB_Table_QuickForm
function &getFormElement($column, $elemname)
include_once 'DB/Table/QuickForm.php';
return DB_Table_QuickForm ::getElement ($coldef, $elemname);
* Creates a column definition array suitable for DB_Table_QuickForm.
* @param string|array $column_set A string column name, a sequential
* array of columns names, or an associative array where the key is a
* column name and the value is the default value for the generated
* form element. If null, uses all columns for this class.
* @return array An array of columne defintions suitable for passing
function _getFormColDefs($column_set = null)
if (is_null($column_set)) {
// no columns or columns+values; just return the $this->col
// check to see if the keys are sequential integers. if so,
// the $column_set is just a list of columns.
settype($column_set, 'array');
$keys = array_keys($column_set);
foreach ($keys as $val) {
if (! is_integer($val)) {
// the column_set is just a list of columns; get back the $this->col
// array elements matching this list.
// the columns_set is an associative array where the key is a
// column name and the value is the form element value.
foreach ($coldefs as $key => $val) {
$coldefs[$key]['qf_setvalue'] = $column_set[$key];
Documentation generated on Mon, 11 Mar 2019 13:52:54 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|