Ferreteria/archive/data.php: Difference between revisions
(New page: <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 anyt...) |
(12/24 code update) |
||
| Line 7: | Line 7: | ||
the dbx_ functions, as the system that I was using didn't have them installed. | 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-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 | |||
*/ | */ | ||
| Line 102: | Line 103: | ||
} | } | ||
class | class clsData { | ||
protected $objDB; // clsDatabase | 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; | protected $strName; | ||
public function __construct($iDB,$iName) { | public function __construct($iDB,$iName) { | ||
CallEnter('clsDataTable_noID('.get_class($iDB).','.$iName.')'); | CallEnter('clsDataTable_noID('.get_class($iDB).','.$iName.')'); | ||
parent::__construct($iDB); | |||
$this->strName = $iName; | $this->strName = $iName; | ||
CallExit('clsDataTable_noID()'); | CallExit('clsDataTable_noID()'); | ||
} | } | ||
| Line 119: | Line 152: | ||
CallStep('('.get_class($this).')clsDataTable_noID._newItem()'); | CallStep('('.get_class($this).')clsDataTable_noID._newItem()'); | ||
return new clsDataItem_noID($this); | return new clsDataItem_noID($this); | ||
} | } | ||
public function Name() { | public function Name() { | ||
return $this->strName; | return $this->strName; | ||
} | } | ||
public function GetData($iFilt,$iSort='') { | public function GetData($iFilt='',$iSort='') { | ||
CallEnter('clsDataTable.GetData(filt="'.$iFilt.'",sort="'.$iSort.'")'); | CallEnter('clsDataTable.GetData(filt="'.$iFilt.'",sort="'.$iSort.'")'); | ||
$sql = 'SELECT * FROM '.$this->strName.' WHERE ('.$iFilt.')'; | $sql = 'SELECT * FROM '.$this->strName; | ||
if ($iFilt != '') { | |||
$sql .= ' WHERE ('.$iFilt.')'; | |||
} | |||
if ($iSort != '') { | |||
$sql .= ' ORDER BY '.$iSort; | $sql .= ' ORDER BY '.$iSort; | ||
} | } | ||
| Line 225: | Line 257: | ||
public function HasData() { | public function HasData() { | ||
return (is_array($this->Row)); | return (is_array($this->Row)); | ||
} | |||
public function HasRows($iMin=1) { | |||
if ($this->HasData()) { | |||
return ($this->RowCount() >= $iMin); | |||
} else { | |||
return 0; | |||
} | |||
} | } | ||
private function FirstRow() { | private function FirstRow() { | ||
Revision as of 00:54, 25 December 2007
<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>