* @copyright 2001-2006 VIKO team and contributors
* @license http://www.gnu.org/licenses/gpl.html GPL 2.0
*/
/**
* This class abstracts database tables, so it needs database connection
*/
require_once 'DBInstance.php';
/**
* Handles general tasks of interfacing a database table
*
* Subclasses need to implement the specific functionality.
* Child classes defenetly need to override the following methods:
*
*
* - readFromDatabaseRecord()
* - writeToDatabaseRecord()
* - getTableName()
* - getIDFieldName()
*
*
* @abstract
*/
class TableAbstraction
{
/**
* Value of the ID column
*
* TableAbstraction class requires that the table has one column,
* that contains the unique primary key (possibly auto-generated).
*
* @access private
* @var integer
*/
var $_id = null;
/**
* Creates new TableAbstraction instance
*
* The record ID may be optionally specified.
*
* @param int $id database record ID
*/
function TableAbstraction( $id = null ) {
$this->_id = $id;
}
/**
* Returns the value of ID column, null if unset
*
* @access public
* @return integer row ID
*/
function getID()
{
return $this->_id;
}
/**
* Sets value for the ID column
*
* @access public
* @param integer $id row ID
*/
function setID( $id )
{
$this->_id = $id;
}
/**
* Returns the value of private attribute
*
* If attribute is not set, then it is attempted to retrieve from database.
* If the retrieval from database failed, false is returned.
*
* @access protected
* @param string $attribute_name
* @return mixed value of the requested attribute
*/
function getAttribute( $attribute_name )
{
if ( isset($this->$attribute_name) ) {
// the requested value is readily available - just return it
return $this->$attribute_name;
}
else {
// so we request it from the database
if ( $this->loadFromDatabaseByID() ) {
return ( isset($this->$attribute_name) ) ? $this->$attribute_name : null;
}
else {
return false;
}
}
}
/**
* Loads object with info from table corresponding to specified record ID
*
* If a record corresponding to the ID was not found, false is returned.
*
* If record ID is unavailable,
* an error is generated and the execution stops.
*
* @access public
* @return bool true if corresponding record was found
*/
function loadFromDatabaseByID()
{
// ensure that record ID is available
if ( !isset($this->_id) ) {
trigger_error( "No record ID specified when loading.", E_USER_ERROR );
}
// try to load a DB record corresponding to the ID
$db = DBInstance::get();
$table_name = $this->getTableName();
$id_field_name = $this->getIDFieldName();
$record = $db->getRow(
"SELECT
*
FROM
$table_name
WHERE
$id_field_name = ?
LIMIT 1",
array( $this->_id )
);
// Ensure that the query went without error.
// If it didn't announce the error and stop execution.
if ( PEAR::isError( $record ) ) {
trigger_error( $record->getMessage(), E_USER_ERROR );
}
// if the ID existed in table apply the retrieved data to this object.
// if not, then just return false.
if ( isset($record) ) {
$this->readFromDatabaseRecord( $record );
return true;
}
else {
return false;
}
}
/**
* Saves object information into database
*
* If record ID is set, an existing record will be updated,
* without ID a new record will be inserted.
*
* @access public
* @return boolean success
*/
function save()
{
if ( isset( $this->_id ) ) {
return $this->_updateRecord();
}
else {
return $this->_insertRecord();
}
}
/**
* Updates the record in database
*
* @access private
* @return boolean success
*/
function _updateRecord()
{
$field_values = $this->writeToDatabaseRecord();
$where_clause = $this->getIDFieldName() . '=' . $this->_id;
$db = DBInstance::get();
$result = $db->autoExecute(
$this->getTableName(),
$field_values,
DB_AUTOQUERY_UPDATE,
$where_clause
);
// check for errors
if ( PEAR::isError($result) ) {
// The update might fail because of a UNIQUE constraint
// in that case return false,
// for other errors just show the error message and stop.
if ( $result->getCode() == DB_ERROR_CONSTRAINT ) {
return false;
}
else {
trigger_error( $result->getMessage(), E_USER_ERROR );
}
}
// we reached here, so everything should have gone just fine
return true;
}
/**
* Inserts new record into database
*
* @access private
* @return boolean success
*/
function _insertRecord()
{
$field_values = $this->writeToDatabaseRecord();
$db = DBInstance::get();
$result = $db->autoExecute(
$this->getTableName(),
$field_values,
DB_AUTOQUERY_INSERT
);
// check for errors
if ( PEAR::isError($result) ) {
// The insert might fail because of a UNIQUE constraint
// in that case return false,
// for other errors just show the error message and stop.
if ( $result->getCode() == DB_ERROR_CONSTRAINT ) {
return false;
}
else {
trigger_error( $result->getMessage(), E_USER_ERROR );
}
}
// Get the ID of last insert with a help of MySQL specific function
// TODO: This has to be changed, if we want to port VIKO to other databases
$this->_id = mysql_insert_id();
// we reached here, so everything should have gone just fine
return true;
}
/**
* Removes record corresponding to the ID from database table
*
* The ID must be specified for this to work.
*
* @access public
* @return boolean true on successful delete.
*/
function delete()
{
// ensure that record ID is available
if ( !isset($this->_id) ) {
trigger_error( "No record ID specified when deleting.", E_USER_ERROR );
}
// remove the record from database
$db = DBInstance::get();
$table_name = $this->getTableName();
$id_field_name = $this->getIDFieldName();
$result = $db->query(
"DELETE FROM $table_name WHERE $id_field_name = ? LIMIT 1",
$this->_id
);
// Check tha there were no errors in performing the query
if ( PEAR::isError($result) ) {
trigger_error( $result->getMessage(), E_USER_ERROR );
}
// return true, if a record was deleted
return ( $db->affectedRows() == 1 );
}
//
// abstract methods that require implementing in child classes
//
/**
* Returns the name of the database table which the class abstracts
*
* @access protected
* @return string table name
*/
function getTableName()
{
trigger_error( "TableAbstraction::getTableName() not implemented.", E_USER_ERROR );
}
/**
* Returns the name of the id field in database table
*
* @access protected
* @return string ID field name
*/
function getIDFieldName()
{
trigger_error( "TableAbstraction::getIDFieldName() not implemented.", E_USER_ERROR );
}
/**
* Takes values from database record and applies those to object attributes
*
* @access protected
* @param array $record a row retrieved from database
*/
function readFromDatabaseRecord( $record )
{
trigger_error( "TableAbstraction::readFromDatabaseRecord() not implemented.", E_USER_ERROR );
}
/**
* Reads values from object attributes into array of fields and returns it
*
* @access protected
* @return array a row to be written in database
*/
function writeToDatabaseRecord()
{
trigger_error( "TableAbstraction::writeToDatabaseRecord() not implemented.", E_USER_ERROR );
}
}
?>