Ferreteria/archive/data.php
<php><?php /* ===========================
*** DATA UTILITY CLASSES ***
(2007-05-20 Wzl) These classes have been designed to be db-engine agnostic, but I wasn't able to test against anything other than MySQL nor was I able to implement the usage of the dbx_ functions, as the system that I was using didn't have them installed. (2007-08-30 Wzl) posting this version at http://htyp.org/User:Woozle/data.php (2007-12-24 Wzl) Some changes seem to have been made as recently as 12/17, so posting updated version
- /
class clsDatabase {
private $cntOpen; // count of requests to keep db open private $strType; // type of db (MySQL etc.) private $strUser; // database user private $strPass; // password private $strHost; // host (database server domain-name or IP address) private $strName; // database (schema) name
private $Conn; // connection object
// status
private $strErr; // latest error message public $sql; // last SQL executed (or attempted)
public function __construct($iConn) { CallEnter('clsDatabase('.get_class($iConn).')'); $this->Init($iConn); CallExit('clsDatabase()'); } public function Init($iConn) {
// $iConn format: type:user:pass@server/dbname
CallEnter('clsDatabase.Init('.get_class($iConn).')'); $this->cntOpen = 0; list($part1,$part2) = split('@',$iConn); list($this->strType,$this->strUser,$this->strPass) = split(':',$part1); list($this->strHost,$this->strName) = explode('/',$part2); $this->strType = strtolower($this->strType); // make sure it is lowercased, for comparison CallExit('clsDatabase.Init()'); } public function Open() { CallEnter('clsDatabase.Open()'); if ($this->cntOpen == 0) {
// then actually open the db
if ($this->strType == 'mysql') { $this->Conn = new mysqli($this->strHost,$this->strUser,$this->strPass,$this->strName); } else { $this->Conn = dbx_connect($this->strType,$this->strHost,$this->strName,$this->strUser,$this->strPass); } } $this->cntOpen++; CallExit('clsDatabase.Open() - '.$this->cntOpen.' lock'.Pluralize($this->cntOpen)); } public function Shut() { CallEnter('clsDatabase.Shut()'); $this->cntOpen--; if ($this->cntOpen == 0) { if ($this->strType == 'mysql') { $this->Conn->close(); } else { dbx_close($this->Conn); } } CallExit('clsDatabase.Shut() - '.$this->cntOpen.' lock'.Pluralize($this->cntOpen)); } public function _api_query($iSQL) {
// USAGE: should only be used by clsDataItem
$this->sql = $iSQL; if ($this->strType == 'mysql') { $this->Conn->real_query($iSQL); return $this->Conn->store_result(); } else { return dbx_query($this->Conn,$iSQL,DBX_RESULT_ASSOC); }
} public function Exec($iSQL) {
// MYSQL only
CallEnter('clsDataTable_noID.Exec('.$iSQL.')'); $this->sql = $iSQL; $objQry = $this->Conn->prepare($iSQL); if (is_object($objQry)) { $ok = $objQry->execute(); if (!$ok) { $this->txtErr = $this->Conn->error; } } else { $ok = false; echo '
SQL error: '.$iSQL.'
'; } $objQry->close(); CallExit('clsDataTable_noID.Exec()'); return $ok; } public function NewID() { return $this->Conn->insert_id; } public function SafeParam($iString) { return $this->Conn->escape_string($iString); } public function ErrorText() { return $this->txtErr; }
}
class clsData {
protected $objDB; // clsDatabase public function __construct($iDB) { $this->objDB = $iDB; $this->objDB->Open(); assert (isset($this->objDB)); } public function DB() { CallStep('('.get_class($this).')clsDataTable.DB()'); return $this->objDB; }
}
class clsDataQuery extends clsData {
protected $sqlSelect;
public function __construct($iDB,$iSQL) { CallEnter('clsDataQuery('.get_class($iDB).','.$iSQL.')'); parent::__construct($iDB); $this->sqlSelect = $iSQL; CallExit('clsDataQuery()'); } public function __destruct() { $this->objDB->Shut(); } protected function _newItem() { return new clsDataItem_noID($this); } public function GetData() { $objItem = $this->_newItem(); $objItem->Query($this->sqlSelect); return $objItem; }
}
class clsDataTable_noID extends clsData {
protected $strName; public function __construct($iDB,$iName) { CallEnter('clsDataTable_noID('.get_class($iDB).','.$iName.')'); parent::__construct($iDB); $this->strName = $iName; CallExit('clsDataTable_noID()'); } public function __destruct() { $this->objDB->Shut(); } protected function _newItem() { CallStep('('.get_class($this).')clsDataTable_noID._newItem()'); return new clsDataItem_noID($this); } public function Name() { return $this->strName; } public function GetData($iFilt=,$iSort=) { CallEnter('clsDataTable.GetData(filt="'.$iFilt.'",sort="'.$iSort.'")'); $sql = 'SELECT * FROM '.$this->strName; if ($iFilt != ) { $sql .= ' WHERE ('.$iFilt.')'; } if ($iSort != ) { $sql .= ' ORDER BY '.$iSort; } CallStep('SQL = ['.$sql.']'); $objItem = $this->_newItem(); $objItem->Query($sql); CallExit('clsDataTable.GetData() -> '.get_class($objItem)); return $objItem; }
} // // clsDataTable_noID with functions based on autonumbered ID field // class clsDataTable extends clsDataTable_noID {
protected $strIDname; // name of unique ID field
public function __construct($iDB,$iName,$iIDname='ID') { CallEnter('clsDataTable('.get_class($iDB).','.$iName.')'); parent::__construct($iDB,$iName); $this->strIDname = $iIDname; CallExit('clsDataTable()'); } public function NameOfID() { return $this->strIDname; } protected function _newItem() { CallStep('('.get_class($this).')clsDataTable._newItem()'); return new clsDataItem($this); } public function GetItem($iID) { CallEnter('('.get_class($this).')clsDataTable.GetItem('.$iID.')'); $sql = 'SELECT * FROM '.$this->strName.' WHERE '.$this->strIDname.'="'.$iID.'"'; CallStep('SQL = ['.$sql.']');
// $objQry = dbx_query($this->objDB,$sql,DBX_RESULT_ASSOC);
$objItem = $this->_newItem(); $objItem->Query($sql);
// $objItem->Eat($objQry);
CallExit('clsDataTable.GetItem('.$iID.') -> '.get_class($objItem)); return $objItem; }
}
class clsDataItem_noID {
public $Res; // result set public $Row; // first (presumably the *only*) row data public $Table; // clsDataTable object public function __construct($iTable=NULL) { CallEnter('clsDataItem_noID('.get_class($iTable).')'); $this->Init($iTable); CallExit('clsDataItem_noID()'); } public function Init($iTable=NULL) { CallEnter('('.get_class($this).')clsDataItem_noID.Init('.get_class($iTable).')'); $this->Table = $iTable;
// this works for mysql only: // fetch the first row of the results as an associative array: // $this->Row = $iResults->fetch_assoc();
CallExit('clsDataItem_noID.Init()'); } public function Query($iSQL) { CallEnter('('.get_class($this).')clsDataItem_noID.Query('.$iSQL.')'); assert($this->Table); assert($this->Table->DB()); $this->Res = $this->Table->DB()->_api_query($iSQL);
/*
if ($this->strType == 'mysql') { $this->Conn()->real_query($iSQL); $this->Res = $this->Conn()->store_result(); } else { $this->Res = dbx_query($this->Conn(),$iSQL,DBX_RESULT_ASSOC); }
- /
// later, we might want a flag for *not* doing this automatically... maybe.
$this->FirstRow(); CallExit('clsDataTable_noID.Query()'); } protected function LoadResults() {
// USAGE: Abstract
CallStep('('.get_class($this).')clsDataItem_noID.LoadResults()'); } public function GetValue($iName) {
// this works for mysql only
CallEnter('clsDataTable_noID.GetValue('.$iName.')');
// DumpArray($this->Row);
$val = $this->Row[$iName]; CallExit('clsDataTable_noID.GetValue('.$iName.') -> ['.$val.']'); return $val; } public function RowCount() { $cntRows = $this->Res->num_rows; CallStep('('.get_class($this).')clsDataItem_noID.RowCount() -> '.$cntRows); return $cntRows; } public function HasData() { return (is_array($this->Row)); } public function HasRows($iMin=1) { if ($this->HasData()) { return ($this->RowCount() >= $iMin); } else { return 0; } } private function FirstRow() { CallEnter('('.get_class($this).')clsDataItem_noID.FirstRow()'); if (!is_null($this->Res)) { if ($this->RowCount()) { $this->NextRow(); // get the first row of data } } CallExit('('.get_class($this).')clsDataItem_noID.FirstRow()'); } public function NextRow() {
// this works for mysql only: // fetch the NEXT row of the results as an associative array:
$this->Row = $this->Res->fetch_assoc(); if (is_array($this->Row)) { $this->LoadResults(); } }
} // // clsDataItem with functions based on autonumbered ID field // class clsDataItem extends clsDataItem_noID {
public $ID; protected $strIDname; // name of unique ID field
//TO DO: set $strIDname at construct time; use it instead of hard-coded "ID" // or maybe clsTitleExt should descend from clsDataItem_noID? Or need clsTitleIttyp class instead?
protected function LoadResults() {
// USAGE: Descendants do not have to call this function
CallEnter('('.get_class($this).')clsDataItem.LoadResults()'); assert($this->Table); assert($this->Table->NameOfID()); $this->ID = $this->GetValue($this->Table->NameOfID()); assert($this->ID); if (!isset($this->ID)) { echo '
TABLE: ['.$this->Table->Name().'] ID name: ['.$this->Table->NameOfID().']
'; } CallExit('clsDataItem.LoadResults()'); }
}
/* ========================
*** UTILITY FUNCTIONS ***
- /
function Pluralize($iQty,$iSingular=,$iPlural='s') { if ($iQty == 1) { return $iSingular; } else { return $iPlural; } } /* ========================
*** DEBUGGING FUNCTIONS ***
- /
// these could later be expanded to create a call-path for errors, etc.
function CallEnter($iName) {
global $intCallDepth, $debug; if (KDO_DEBUG_STACK) { $intCallDepth++; if (KDO_DEBUG_HTML) { $debug .= '
'.str_repeat('>> ',$intCallDepth).''.$iName.''; } else { $debug .= "\n\n".str_repeat('*',$intCallDepth).$iName; } if (KDO_DEBUG_IMMED) { echo $debug; $debug = ; } }
} function CallExit($iName) {
global $intCallDepth, $debug; if (KDO_DEBUG_STACK) { $intCallDepth--; if (KDO_DEBUG_HTML) { $debug .= '
'.str_repeat('>> ',$intCallDepth).'<< '.$iName.''; } else { $debug .= "\n\n".str_repeat('*',$intCallDepth).'<'; } if (KDO_DEBUG_IMMED) { DoDebugStyle(); echo $debug; $debug = ; } }
} function CallStep($iName) {
global $intCallDepth, $debug; if (KDO_DEBUG_STACK) { if (KDO_DEBUG_HTML) { $debug .= '
'.str_repeat('>> ',$intCallDepth).'++ '.$iName.''; } else { $debug .= "\n\n".str_repeat('*',$intCallDepth).'+'; } if (KDO_DEBUG_IMMED) { DoDebugStyle(); echo $debug; $debug = ; } }
} function DumpArray($iArr) {
global $intCallDepth, $debug;
if (KDO_DEBUG) { while (list($key, $val) = each($iArr)) { if (KS_DEBUG_HTML) { $debug .= '
'.str_repeat('-- ',$intCallDepth+1).''; $debug .= " $key => $val"; $debug .= ''; } else { $debug .= "/ $key => $val /"; } if (KDO_DEBUG_IMMED) { DoDebugStyle(); echo $debug; $debug = ; } } }
} function DumpValue($iName,$iVal) {
global $intCallDepth, $debug;
if (KDO_DEBUG) { if (KS_DEBUG_HTML) { $debug .= '
'.str_repeat('-- ',$intCallDepth+1); $debug .= " $iName: [$iVal]"; $debug .= ''; } else { $debug .= "/ $iName => $iVal /"; } if (KDO_DEBUG_IMMED) { DoDebugStyle(); echo $debug; $debug = ; } }
} function DoDebugStyle() {
static $isStyleDone = false;
if (!$isStyleDone) { echo '<style type="text/css"></style>'; $isStyleDone = true; }
}
?></php>