%PDF- %PDF-
| Direktori : /home1/lightco1/www/lightingrepublic.com.au/libraries/koowa/database/adapter/ |
| Current File : //home1/lightco1/www/lightingrepublic.com.au/libraries/koowa/database/adapter/abstract.php |
<?php
/**
* @version $Id$
* @package Koowa_Database
* @subpackage Adapter
* @copyright Copyright (C) 2007 - 2012 Johan Janssens. All rights reserved.
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html>
* @link http://www.nooku.org
*/
/**
* Abstract Database Adapter
*
* @author Johan Janssens <johan@nooku.org>
* @package Koowa_Database
* @subpackage Adapter
* @uses KPatternCommandChain
*/
abstract class KDatabaseAdapterAbstract extends KObject implements KDatabaseAdapterInterface
{
/**
* Active state of the connection
*
* @var boolean
*/
protected $_connected = null;
/**
* The database connection resource
*
* @var mixed
*/
protected $_connection = null;
/**
* Last auto-generated insert_id
*
* @var integer
*/
protected $_insert_id;
/**
* The affected row count
*
* @var int
*/
protected $_affected_rows;
/**
* Schema cache
*
* @var array
*/
protected $_table_schema = null;
/**
* The table prefix
*
* @var string
*/
protected $_table_prefix = '';
/**
* The table needle
*
* @var string
*/
protected $_table_needle = '';
/**
* Quote for named objects
*
* @var string
*/
protected $_name_quote = '`';
/**
* The connection options
*
* @var KConfig
*/
protected $_options = null;
/**
* Constructor.
*
* @param object An optional KConfig object with configuration options.
* Recognized key values include 'command_chain', 'charset', 'table_prefix',
* (this list is not meant to be comprehensive).
*/
public function __construct( KConfig $config = null )
{
//If no config is passed create it
if(!isset($config)) $config = new KConfig();
// Initialize the options
parent::__construct($config);
// Set the connection
$this->setConnection($config->connection);
// Set the default charset. http://dev.mysql.com/doc/refman/5.1/en/charset-connection.html
if (!empty($config->charset)) {
//$this->setCharset($config->charset);
}
// Set the table prefix
$this->_table_prefix = $config->table_prefix;
// Set the table prefix
$this->_table_needle = $config->table_needle;
// Set the connection options
$this->_options = $config->options;
// Mixin a command chain
$this->mixin(new KMixinCommandchain($config->append(array('mixer' => $this))));
}
/**
* Destructor
*
* Free any resources that are open.
*/
public function __destruct()
{
$this->disconnect();
}
/**
* Initializes the options for the object
*
* Called from {@link __construct()} as a first step of object instantiation.
*
* @param object An optional KConfig object with configuration options.
* @return void
*/
protected function _initialize(KConfig $config)
{
$config->append(array(
'options' => array(),
'charset' => 'UTF-8',
'table_prefix' => 'jos_',
'table_needle' => '#__',
'command_chain' => new KCommandChain(),
'dispatch_events' => true,
'enable_callbacks' => false,
'connection' => null,
));
parent::_initialize($config);
}
/**
* Get a database query object
*
* @return KDatabaseQuery
*/
public function getQuery(KConfig $config = null)
{
if(!isset($config)) {
$config = new KConfig(array('adapter' => $this));
}
return new KDatabaseQuery($config);
}
/**
* Reconnect to the db
*
* @return KDatabaseAdapterAbstract
*/
public function reconnect()
{
$this->disconnect();
$this->connect();
return $this;
}
/**
* Disconnect from db
*
* @return KDatabaseAdapterAbstract
*/
public function disconnect()
{
$this->_connection = null;
$this->_connected = false;
return $this;
}
/**
* Get the database name
*
* @return string The database name
*/
abstract function getDatabase();
/**
* Set the database name
*
* @param string The database name
* @return KDatabaseAdapterAbstract
*/
abstract function setDatabase($database);
/**
* Get the connection
*
* Provides access to the underlying database connection. Useful for when
* you need to call a proprietary method such as postgresql's lo_* methods
*
* @return resource
*/
public function getConnection()
{
return $this->_connection;
}
/**
* Set the connection
*
* @param resource The connection resource
* @return KDatabaseAdapterAbstract
*/
public function setConnection($resource)
{
$this->_connection = $resource;
return $this;
}
/**
* Get the insert id of the last insert operation
*
* @return mixed The id of the last inserted row(s)
*/
public function getInsertId()
{
return $this->_insert_id;
}
/**
* Preforms a select query
*
* Use for SELECT and anything that returns rows.
*
* If <var>key</var> is not empty then the returned array is indexed by the value
* of the database key. Returns <var>null</var> if the query fails.
*
* @param string|object A full SQL query to run. Data inside the query should be properly escaped.
* @param integer The fetch mode. Controls how the result will be returned to the caller. This
* value must be one of the KDatabase::FETCH_* constants.
* @param string The column name of the index to use
* @return mixed The return value of this function on success depends on the fetch type.
* In all cases, FALSE is returned on failure.
*/
public function select($query, $mode = KDatabase::FETCH_ARRAY_LIST, $key = '')
{
$context = $this->getCommandContext();
$context->query = $query;
$context->operation = KDatabase::OPERATION_SELECT;
$context->mode = $mode;
// Excute the insert operation
if($this->getCommandChain()->run('before.select', $context) !== false)
{
if($result = $this->execute( $context->query, KDatabase::RESULT_USE))
{
switch($context->mode)
{
case KDatabase::FETCH_ARRAY :
$context->result = $this->_fetchArray($result);
break;
case KDatabase::FETCH_ARRAY_LIST :
$context->result = $this->_fetchArrayList($result, $key);
break;
case KDatabase::FETCH_FIELD :
$context->result = $this->_fetchField($result, $key);
break;
case KDatabase::FETCH_FIELD_LIST :
$context->result = $this->_fetchFieldList($result, $key);
break;
case KDatabase::FETCH_OBJECT :
$context->result = $this->_fetchObject($result);
break;
case KDatabase::FETCH_OBJECT_LIST :
$context->result = $this->_fetchObjectList($result, $key);
break;
default : $result->free();
}
}
$this->getCommandChain()->run('after.select', $context);
}
return KConfig::unbox($context->result);
}
/**
* Preforms a show query
*
* @param string|object A full SQL query to run. Data inside the query should be properly escaped.
* @param integer The fetch mode. Controls how the result will be returned to the caller. This
* value must be one of the KDatabase::FETCH_* constants.
* @return mixed The return value of this function on success depends on the fetch type.
* In all cases, FALSE is returned on failure.
*/
public function show($query, $mode = KDatabase::FETCH_ARRAY_LIST)
{
$context = $this->getCommandContext();
$context->query = $query;
$context->operation = KDatabase::OPERATION_SHOW;
$context->mode = $mode;
// Excute the insert operation
if($this->getCommandChain()->run('before.show', $context) !== false)
{
if($result = $this->execute( $context->query, KDatabase::RESULT_USE))
{
switch($context->mode)
{
case KDatabase::FETCH_ARRAY :
$context->result = $this->_fetchArray($result);
break;
case KDatabase::FETCH_ARRAY_LIST :
$context->result = $this->_fetchArrayList($result);
break;
case KDatabase::FETCH_FIELD :
$context->result = $this->_fetchField($result);
break;
case KDatabase::FETCH_FIELD_LIST :
$context->result = $this->_fetchFieldList($result);
break;
case KDatabase::FETCH_OBJECT :
$context->result = $this->_fetchObject($result);
break;
case KDatabase::FETCH_OBJECT_LIST :
$context->result = $this->_fetchObjectList($result);
break;
default : $result->free();
}
}
$this->getCommandChain()->run('after.show', $context);
}
return KConfig::unbox($context->result);
}
/**
* Inserts a row of data into a table.
*
* Automatically quotes the data values
*
* @param string The table to insert data into.
* @param array An associative array where the key is the colum name and
* the value is the value to insert for that column.
* @return bool|integer If the insert query was executed returns the number of rows updated, or 0 if
* no rows where updated, or -1 if an error occurred. Otherwise FALSE.
*/
public function insert($table, array $data)
{
$context = $this->getCommandContext();
$context->table = $table;
$context->data = $data;
$context->operation = KDatabase::OPERATION_INSERT;
//Excute the insert operation
if($this->getCommandChain()->run('before.insert', $context) !== false)
{
//Check if we have valid data to insert, if not return false
if(count($context->data))
{
foreach($context->data as $key => $val)
{
$vals[] = $this->quoteValue($val);
$keys[] = '`'.$key.'`';
}
$context->query = 'INSERT INTO '.$this->quoteName($this->getTableNeedle().$context->table )
. '('.implode(', ', $keys).') VALUES ('.implode(', ', $vals).')';
//Execute the query
$context->result = $this->execute($context->query);
$context->affected = $this->_affected_rows;
$this->getCommandChain()->run('after.insert', $context);
}
else $context->affected = false;
}
return $context->affected;
}
/**
* Updates a table with specified data based on a WHERE clause
*
* Automatically quotes the data values
*
* @param string The table to update
* @param array An associative array where the key is the column name and
* the value is the value to use ofr that column.
* @param mixed A sql string or KDatabaseQuery object to limit which rows are updated.
* @return integer If the update query was executed returns the number of rows updated, or 0 if
* no rows where updated, or -1 if an error occurred. Otherwise FALSE.
*/
public function update($table, array $data, $where = null)
{
$context = $this->getCommandContext();
$context->table = $table;
$context->data = $data;
$context->where = $where;
$context->operation = KDatabase::OPERATION_UPDATE;
//Excute the update operation
if($this->getCommandChain()->run('before.update', $context) !== false)
{
if(count($context->data))
{
foreach($context->data as $key => $val) {
$vals[] = '`'.$key.'` = '.$this->quoteValue($val);
}
//Create query statement
$context->query = 'UPDATE '.$this->quoteName($this->getTableNeedle().$context->table)
.' SET '.implode(', ', $vals)
.' '.$context->where
;
//Execute the query
$context->result = $this->execute($context->query);
$context->affected = $this->_affected_rows;
$this->getCommandChain()->run('after.update', $context);
}
else $context->affected = false;
}
return $context->affected;
}
/**
* Deletes rows from the table based on a WHERE clause.
*
* @param string The table to update
* @param mixed A query string or a KDatabaseQuery object to limit which rows are updated.
* @return integer Number of rows affected, or -1 if an error occured.
*/
public function delete($table, $where)
{
$context = $this->getCommandContext();
$context->table = $table;
$context->data = null;
$context->where = $where;
$context->operation = KDatabase::OPERATION_DELETE;
//Excute the delete operation
if($this->getCommandChain()->run('before.delete', $context) !== false)
{
//Create query statement
$context->query = 'DELETE FROM '.$this->quoteName($this->getTableNeedle().$context->table)
.' '.$context->where
;
//Execute the query
$context->result = $this->execute($context->query);
$context->affected = $this->_affected_rows;
$this->getCommandChain()->run('after.delete', $context);
}
return $context->affected;
}
/**
* Use and other queries that don't return rows
*
* @param string The query to run. Data inside the query should be properly escaped.
* @param integer The result maode, either the constant KDatabase::RESULT_USE or KDatabase::RESULT_STORE
* depending on the desired behavior. By default, KDatabase::RESULT_STORE is used. If you
* use KDatabase::RESULT_USE all subsequent calls will return error Commands out of sync
* unless you free the result first.
* @throws KDatabaseException
* @return boolean For SELECT, SHOW, DESCRIBE or EXPLAIN will return a result object.
* For other successful queries return TRUE.
*/
public function execute($sql, $mode = KDatabase::RESULT_STORE )
{
//Replace the database table prefix
$sql = $this->replaceTableNeedle( $sql );
$result = $this->_connection->query($sql, $mode);
if($result === false) {
throw new KDatabaseException($this->_connection->error.' of the following query : '.$sql, $this->_connection->errno);
}
$this->_affected_rows = $this->_connection->affected_rows;
$this->_insert_id = $this->_connection->insert_id;
return $result;
}
/**
* Set the table prefix
*
* @param string The table prefix
* @return KDatabaseAdapterAbstract
* @see KDatabaseAdapterAbstract::replaceTableNeedle
*/
public function setTablePrefix($prefix)
{
$this->_table_prefix = $prefix;
return $this;
}
/**
* Get the table prefix
*
* @return string The table prefix
* @see KDatabaseAdapterAbstract::replaceTableNeedle
*/
public function getTablePrefix()
{
return $this->_table_prefix;
}
/**
* Get the table needle
*
* @return string The table needle
* @see KDatabaseAdapterAbstract::replaceTableNeedle
*/
public function getTableNeedle()
{
return $this->_table_needle;
}
/**
* This function replaces the table needles in a query string with the actual table prefix.
*
* @param string The SQL query string
* @return string The SQL query string
*/
public function replaceTableNeedle( $sql, $replace = null)
{
$needle = $this->getTableNeedle();
$replace = isset($replace) ? $replace : $this->getTablePrefix();
$sql = trim( $sql );
$pattern = "($needle(?=[a-z0-9]))";
$sql = preg_replace($pattern, $replace, $sql);
return $sql;
}
/**
* Safely quotes a value for an SQL statement.
*
* If an array is passed as the value, the array values are quoted
* and then returned as a comma-separated string; this is useful
* for generating IN() lists.
*
* @param mixed The value to quote.
* @return string An SQL-safe quoted value (or a string of separated-
* and-quoted values).
*/
public function quoteValue($value)
{
if (is_array($value))
{
//Quote array values, not keys, then combine with commas.
foreach ($value as $k => $v) {
$value[$k] = $this->quoteValue($v);
}
$value = implode(', ', $value);
}
else
{
if(is_string($value) && !is_null($value)) {
$value = $this->_quoteValue($value);
}
}
return $value;
}
/**
* Quotes a single identifier name (table, table alias, table column,
* index, sequence). Ignores empty values.
*
* This function requires all SQL statements, operators and functions to be
* uppercased.
*
* @param string|array The identifier name to quote. If an array, quotes
* each element in the array as an identifier name.
* @return string|array The quoted identifier name (or array of names).
*
* @see _quoteName()
*/
public function quoteName($spec)
{
if (is_array($spec))
{
foreach ($spec as $key => $val) {
$spec[$key] = $this->quoteName($val);
}
return $spec;
}
// String spaces around the identifier
$spec = trim($spec);
// Quote all the lower case parts
$spec = preg_replace_callback('#(?:\b|\#)+(?<!`)([a-z0-9\.\#\-_]+)(?!`)\b#', array($this, '_quoteName') , $spec);
return $spec;
}
/**
* Fetch the first field of the first row
*
* @param mysqli_result The result object. A result set identifier returned by the select() function
* @param integer The index to use
* @return The value returned in the query or null if the query failed.
*/
abstract protected function _fetchField($result, $key = 0);
/**
* Fetch an array of single field results
*
* @param mysqli_result The result object. A result set identifier returned by the select() function
* @param integer The index to use
* @return array A sequential array of returned rows.
*/
abstract protected function _fetchFieldList($result, $key = 0);
/**
* Fetch the first row of a result set as an associative array
*
* @param mysqli_result The result object. A result set identifier returned by the select() function
* @return array
*/
abstract protected function _fetchArray($sql);
/**
* Fetch all result rows of a result set as an array of associative arrays
*
* If <var>key</var> is not empty then the returned array is indexed by the value
* of the database key. Returns <var>null</var> if the query fails.
*
* @param mysqli_result The result object. A result set identifier returned by the select() function
* @param string The column name of the index to use
* @return array If key is empty as sequential list of returned records.
*/
abstract protected function _fetchArrayList($result, $key = '');
/**
* Fetch the first row of a result set as an object
*
* @param mysqli_result The result object. A result set identifier returned by the select() function
* @param object
*/
abstract protected function _fetchObject($result);
/**
* Fetch all rows of a result set as an array of objects
*
* If <var>key</var> is not empty then the returned array is indexed by the value
* of the database key. Returns <var>null</var> if the query fails.
*
* @param mysqli_result The result object. A result set identifier returned by the select() function
* @param string The column name of the index to use
* @return array If <var>key</var> is empty as sequential array of returned rows.
*/
abstract protected function _fetchObjectList($result, $key='' );
/**
* Parse the raw table schema information
*
* @param object The raw table schema information
* @return KDatabaseSchemaTable
*/
abstract protected function _parseTableInfo($info);
/**
* Parse the raw column schema information
*
* @param object The raw column schema information
* @return KDatabaseSchemaColumn
*/
abstract protected function _parseColumnInfo($info);
/**
* Given a raw column specification, parse into datatype, size, and decimal scope.
*
* @param string The column specification; for example,
* "VARCHAR(255)" or "NUMERIC(10,2)".
*
* @return array A sequential array of the column type, size, and scope.
*/
abstract protected function _parseColumnType($spec);
/**
* Safely quotes a value for an SQL statement.
*
* @param mixed The value to quote
* @return string An SQL-safe quoted value
*/
abstract protected function _quoteValue($value);
/**
* Quotes an identifier name (table, index, etc). Ignores empty values.
*
* If the name contains a dot, this method will separately quote the
* parts before and after the dot.
*
* @param string The identifier name to quote.
* @return string The quoted identifier name.
* @see quoteName()
*/
protected function _quoteName($name)
{
$result = '';
if(is_array($name)) {
$name = $name[0];
}
$name = trim($name);
//Special cases
if ($name == '*' || is_numeric($name)) {
return $name;
}
if ($pos = strrpos($name, '.'))
{
$table = $this->_quoteName(substr($name, 0, $pos));
$column = $this->_quoteName(substr($name, $pos + 1));
$result = "$table.$column";
}
else $result = $this->_name_quote. $name.$this->_name_quote;
return $result;
}
}