| Current Path : /home/m/a/g/magalijoj/www/blog/inc/clearbricks/dblayer/ |
| Current File : /home/m/a/g/magalijoj/www/blog/inc/clearbricks/dblayer/dblayer.php |
<?php
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Clearbricks.
# Copyright (c) 2006 Olivier Meunier and contributors. All rights
# reserved.
#
# Clearbricks is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Clearbricks is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Clearbricks; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# ***** END LICENSE BLOCK *****
/// @defgroup CB_DBLAYER Clearbricks Database Abstraction Layer
/// @ingroup CLEARBRICKS
require dirname(__FILE__).'/class.cursor.php';
/**
@ingroup CB_DBLAYER
@brief Clearbricks Database Abstraction Layer interface
All methods in this interface should be implemented in your database driver.
Database driver is a class that extends dbLayer, implements i_dbLayer and has
a name of the form (driver name)Connection.
*/
interface i_dbLayer
{
/**
This method should open a database connection and return a new resource
link.
@param host <b>string</b> Database server host
@param user <b>string</b> Database user name
@param password <b>string</b> Database password
@param database <b>string</b> Database name
@returns <b>resource</b>
*/
function db_connect($host,$user,$password,$database);
/**
This method should open a persistent database connection and return a new
resource link.
@param host <b>string</b> Database server host
@param user <b>string</b> Database user name
@param password <b>string</b> Database password
@param database <b>string</b> Database name
@returns <b>resource</b>
*/
function db_pconnect($host,$user,$password,$database);
/**
This method should close resource link.
@param handle <b>resource</b> Resource link
*/
function db_close($handle);
/**
This method should return database version number.
@param handle <b>resource</b> Resource link
@returns <b>string</b>
*/
function db_version($handle);
/**
This method should run an SQL query and return a resource result.
@param handle <b>resource</b> Resource link
@param query <b>string</b> SQL query string
@return <b>resource</b>
*/
function db_query($handle,$query);
/**
This method should run an SQL query and return a resource result.
@param handle <b>resource</b> Resource link
@param query <b>string</b> SQL query string
@return <b>resource</b>
*/
function db_exec($handle,$query);
/**
This method should return the number of fields in a result.
@param res <b>resource</b> Resource result
@return <b>integer</b>
*/
function db_num_fields($res);
/**
This method should return the number of rows in a result.
@param res <b>resource</b> Resource result
@return <b>integer</b>
*/
function db_num_rows($res);
/**
This method should return the name of the field at the given position
<var>$position</var>.
@param res <b>resource</b> Resource result
@param position <b>integer</b> Field position
@return <b>string</b>
*/
function db_field_name($res,$position);
/**
This method should return the field type a the given position
<var>$position</var>.
@param res <b>resource</b> Resource result
@param position <b>integer</b> Field position
@return <b>string</b>
*/
function db_field_type($res,$position);
/**
This method should fetch one line of result and return an associative array
with field name as key and field value as value.
@param res <b>resource</b> Resource result
@return <b>array</b>
*/
function db_fetch_assoc($res);
/**
This method should move result cursor on given row position <var>$row</var>
and return true on success.
@param res <b>resource</b> Resource result
@param row <b>integer</b> Row position
@return <b>boolean</b>
*/
function db_result_seek($res,$row);
/**
This method should return number of rows affected by INSERT, UPDATE or
DELETE queries.
@param handle <b>resource</b> Resource link
@param res <b>resource</b> Resource result
@return <b>integer</b>
*/
function db_changes($handle,$res);
/**
This method should return the last error string for the current connection.
@param handle <b>resource</b> Resource link
@return <b>string</b>
*/
function db_last_error($handle);
/**
This method should return an escaped string for the current connection.
@param str <b>string</b> String to escape
@param handle <b>resource</b> Resource link
@return <b>string</b>
*/
function db_escape_string($str,$handle=null);
}
/**
@ingroup CB_DBLAYER
@brief Database Abstraction Layer class
Base class for database abstraction. Each driver extends this class and
implements i_dbLayer interface.
*/
class dbLayer
{
protected $__driver = null; ///< <b>string</b> Driver name
protected $__version = null; ///< <b>string</b> Database version
protected $__link; ///< <b>resource</b> Database resource link
protected $__last_result; ///< <b>resource</b> Last result resource
/**
Static function to use to init database layer. Returns a object extending
dbLayer.
@param driver <b>string</b> Driver name
@param host <b>string</b> Database hostname
@param database <b>string</b> Database name
@param user <b>string</b> User ID
@param password <b>string</b> Password
@param persistent <b>boolean</b> Persistent connection (false)
@return <b>object</b>
*/
public static function init($driver,$host,$database,$user='',$password='',$persistent=false)
{
if (file_exists(dirname(__FILE__).'/class.'.$driver.'.php')) {
require dirname(__FILE__).'/class.'.$driver.'.php';
$driver_class = $driver.'Connection';
} else {
trigger_error('Unable to load DB layer for '.$driver,E_USER_ERROR);
exit(1);
}
return new $driver_class($host,$database,$user,$password,$persistent);
}
/**
Inits database connection.
@param host <b>string</b> User ID
@param database <b>string</b> Password
@param user <b>string</b> Server to connect
@param password <b>string</b> Database name
@param persistent <b>boolean</b> Open a persistent connection
*/
public function __construct($host,$database,$user='',$password='',$persistent=false)
{
if ($persistent) {
$this->__link = $this->db_pconnect($host,$user,$password,$database);
} else {
$this->__link = $this->db_connect($host,$user,$password,$database);
}
$this->__version = $this->db_version($this->__link);
$this->__database = $database;
}
/**
Closes database connection.
*/
public function close()
{
$this->db_close($this->__link);
}
/**
Returns database driver name
@return <b>string</b>
*/
public function driver()
{
return $this->__driver;
}
/**
Returns database driver version
@return <b>string</b>
*/
public function version()
{
return $this->__version;
}
/**
Returns current database name
@return <b>string</b>
*/
public function database()
{
return $this->__database;
}
/**
Returns link resource
@return <b>resource</b>
*/
public function link()
{
return $this->__link;
}
/**
Executes a query and return a recordset. Recordset could be either static
(default beahvior) or dynamic (useful for large results).
$query could be a string or an array of params for a previously prepared
query.
@param sql <b>string</b> SQL query
@return <b>record</b>
*/
public function select($sql)
{
$result = $this->db_query($this->__link,$sql);
$this->__last_result =& $result;
$info = array();
$info['con'] =& $this;
$info['cols'] = $this->db_num_fields($result);
$info['rows'] = $this->db_num_rows($result);
$info['info'] = array();
for ($i=0; $i<$info['cols']; $i++) {
$info['info']['name'][] = $this->db_field_name($result,$i);
$info['info']['type'][] = $this->db_field_type($result,$i);
}
return new record($result,$info);
}
/**
Executes a query and return true if query succeded.
@param sql <b>string</b> SQL query
@return <b>boolean</b>
*/
public function execute($sql)
{
$result = $this->db_exec($this->__link,$sql);
$this->__last_result =& $result;
return true;
}
/**
Begins a transaction.
*/
public function begin()
{
$this->execute('BEGIN');
}
/**
Commits a transaction.
*/
public function commit()
{
$this->execute('COMMIT');
}
/**
Rollbacks a transaction.
*/
public function rollback()
{
$this->execute('ROLLBACK');
}
/**
Vacuum the table given in argument.
@param table <b>string</b> Table name
*/
public function vacuum($table)
{
}
/**
Returns the number of lines affected by the last DELETE, INSERT or UPDATE
query.
@return <b>integer</b>
*/
public function changes()
{
return $this->db_changes($this->__link,$this->__last_result);
}
/**
Returns the last database error or false if no error.
@returns <b>string</b>
*/
public function error()
{
$err = $this->db_last_error($this->__link);
if (!$err) {
return false;
}
return $err;
}
/**
Returns a query fragment with date formater.
The following modifiers are accepted:
- %d : Day of the month, numeric
- %H : Hour 24 (00..23)
- %M : Minute (00..59)
- %m : Month numeric (01..12)
- %S : Seconds (00..59)
- %Y : Year, numeric, four digits
@param field <b>string</b> Field name
@param pattern <b>string</b> Date format
@return <b>string</b>
*/
public function dateFormat($field,$pattern)
{
return
'TO_CHAR('.$field.','."'".$this->escape($pattern)."') ";
}
/**
Returns a LIMIT query fragment.
@param arg1 <b>mixed</b> array or integer with limit intervals
@param arg2 <b>mixed</b> integer or null (null)
@return <b>string</b>
*/
public function limit($arg1, $arg2=null)
{
if (is_array($arg1))
{
$arg1 = array_values($arg1);
$arg2 = isset($arg1[1]) ? $arg1[1] : null;
$arg1 = $arg1[0];
}
if ($arg2 === null) {
$sql = ' LIMIT '.(integer) $arg1.' ';
} else {
$sql = ' LIMIT '.(integer) $arg2.' OFFSET '.$arg1.' ';
}
return $sql;
}
/**
Returns a IN query fragment where $in could be an array, a string,
an integer or null
@param in <b>mixed</b> array, string, integer or null
@return <b>string</b>
*/
public function in($in)
{
if (is_null($in))
{
return ' IN (NULL) ';
}
elseif (is_string($in))
{
return " IN ('".$this->escape($in)."') ";
}
elseif (is_array($in))
{
foreach ($in as $i => $v) {
if (is_null($v)) {
$in[$i] = 'NULL';
} elseif (is_string($v)) {
$in[$i] = "'".$this->escape($v)."'";
}
}
return ' IN ('.implode(',',$in).') ';
}
else
{
return ' IN ( '.(integer) $in.') ';
}
}
/**
Returns SQL concatenation of methods arguments. Theses arguments
should be properly escaped when needed.
@return <b>string</b>
*/
public function concat()
{
$args = func_get_args();
return implode(' || ',$args);
}
/**
Returns SQL protected string or array values.
@param i <b>mixed</b> String or array to protect
@return <b>mixed</b>
*/
public function escape($i)
{
if (is_array($i)) {
foreach ($i as $k => $s) {
$i[$k] = $this->db_escape_string($s,$this->__link);
}
return $i;
}
return $this->db_escape_string($i,$this->__link);
}
/**
Returns SQL system protected string.
@param str <b>string</b> String to protect
@return <b>string</b>
*/
public function escapeSystem($str)
{
return '"'.$str.'"';
}
/**
Returns a new instance of cursor class on <var>$table</var> for the current
connection.
@param table <b>string</b> Cursor table
@return <b>cursor</b>
*/
public function openCursor($table)
{
return new cursor($this,$table);
}
}
/**
@ingroup CB_DBLAYER
@brief Query Result Record Class
This class acts as an iterator over database query result. It does not fetch
all results on instantiation and thus, depending on database engine, should not
fill PHP process memory.
*/
class record
{
protected $__link; ///< <b>resource</b> Database resource link
protected $__result; ///< <b>resource</b> Query result resource
protected $__info; ///< <b>array</b> Result information array
protected $__extend = array(); ///< <b>array</b> List of static functions that extend record
protected $__index = 0; ///< <b>integer</b> Current result position
protected $__row = false; ///< <b>array</b> Current result row content
private $__fetch = false;
/**
Creates class instance from result link and some informations.
<var>$info</var> is an array with the following content:
- con => database object instance
- cols => number of columns
- rows => number of rows
- info
- name => an array with columns names
- type => an array with columns types
@param result <b>resource</b> Resource result
@param info <b>array</b> Information array
*/
public function __construct($result,$info)
{
$this->__result = $result;
$this->__info = $info;
$this->__link = $info['con']->link();
$this->index(0);
}
/**
Converts this record to a staticRecord instance.
*/
public function toStatic()
{
return new staticRecord($this->__result,$this->__info);
}
/**
Magic call function. Calls function in $__extend array if exists, passing it
self object and arguments.
*/
public function __call($f,$args)
{
if (isset($this->__extend[$f]))
{
array_unshift($args,$this);
return call_user_func_array($this->__extend[$f],$args);
}
trigger_error('Call to undefined method record::'.$f.'()',E_USER_ERROR);
}
/**
Magic get method. Alias for field().
*/
public function __get($n)
{
return $this->field($n);
}
/**
Alias for field().
*/
public function f($n)
{
return $this->field($n);
}
/**
Retrieve named <var>$n</var> field value.
@param n <b>string</b> Field name
@return <b>string</b>
*/
public function field($n)
{
return $this->__row[$n];
}
/**
Returns true if a field exists.
@param n <b>string</b> Field name
@return <b>string</b>
*/
public function exists($n)
{
return isset($this->__row[$n]);
}
/**
Extends this instance capabilities by adding all public static methods of
<var>$class</var> to current instance. Class methods should take at least
this record as first parameter.
@see __call()
@param class <b>string</b> Class name
*/
public function extend($class)
{
if (!class_exists($class)) {
return;
}
$c = new ReflectionClass($class);
foreach ($c->getMethods() as $m) {
if ($m->isStatic() && $m->isPublic()) {
$this->__extend[$m->name] = array($class,$m->name);
}
}
}
private function setRow()
{
$this->__row = $this->__info['con']->db_fetch_assoc($this->__result);
if ($this->__row !== false)
{
foreach ($this->__row as $k => $v) {
$this->__row[] =& $this->__row[$k];
}
return true;
}
else
{
return false;
}
}
/**
Returns the current index position (O is first) or move to <var>$row</var> if
specified.
@param row <b>integer</b> Row number to move
@return <b>integer</b>
*/
public function index($row=null)
{
if ($row === null) {
return $this->__index === null ? 0 : $this->__index;
}
if ($row < 0 || $row+1 > $this->__info['rows']) {
return false;
}
if ($this->__info['con']->db_result_seek($this->__result,(integer) $row))
{
$this->__index = $row;
$this->setRow();
$this->__info['con']->db_result_seek($this->__result,(integer) $row);
return true;
}
return false;
}
/**
This method moves index to one position and return true until index is not
the last one. You can use it to loop over record. Example:
@code
<?php
while ($rs->fetch()) {
echo $rs->field1;
}
?>
@endcode
@return <b>boolean</b>
*/
public function fetch()
{
if (!$this->__fetch) {
$this->__fetch = true;
$i = -1;
} else {
$i = $this->__index;
}
if (!$this->index($i+1)) {
$this->__fetch = false;
$this->__index = 0;
return false;
}
return true;
}
/**
Moves index to first position.
@return <b>boolean</b>
*/
public function moveStart()
{
return $this->index(0);
}
/**
Moves index to last position.
@return <b>boolean</b>
*/
public function moveEnd()
{
return $this->index($this->__info['rows']-1);
}
/**
Moves index to next position.
@return <b>boolean</b>
*/
public function moveNext()
{
return $this->index($this->__index+1);
}
/**
Moves index to previous position.
@return <b>boolean</b>
*/
public function movePrev()
{
return $this->index($this->__index-1);
}
/**
Returns true if index is at last position.
@return <b>boolean</b>
*/
public function isEnd()
{
return $this->__index+1 == $this->count();
}
/**
Returns true if index is at first position.
@return <b>boolean</b>
*/
public function isStart()
{
return $this->__index <= 0;
}
/**
Returns true if record contains no result.
@return <b>boolean</b>
*/
public function isEmpty()
{
return $this->count() == 0;
}
/**
Returns number of rows in record.
@return <b>integer</b>
*/
public function count()
{
return $this->__info['rows'];
}
/**
Returns an array of columns, with name as key and type as value.
@return <b>array</b>
*/
public function columns()
{
return $this->__info['info']['name'];
}
/**
Returns an array of all rows in record.
@return <b>array</b>
*/
public function rows()
{
return $this->getData();
}
/**
Returns an array of all rows in record. This method is called by rows().
@return <b>array</b>
*/
protected function getData()
{
$res = array();
if ($this->count() == 0) {
return $res;
}
$this->__info['con']->db_result_seek($this->__result,0);
while (($r = $this->__info['con']->db_fetch_assoc($this->__result)) !== false) {
foreach ($r as $k => $v) {
$r[] =& $r[$k];
}
$res[] = $r;
}
$this->__info['con']->db_result_seek($this->__result,$this->__index);
return $res;
}
}
/**
@ingroup CB_DBLAYER
@brief Query Result Static Record Class
Unlike record class, this one contains all results in an associative array.
*/
class staticRecord extends record
{
public $__data = array(); ///< <b>array</b> Data array
private $__sortfield;
private $__sortsign;
public function __construct($result,$info)
{
if (is_array($result))
{
$this->__info = $info;
$this->__data = $result;
}
else
{
parent::__construct($result,$info);
$this->__data = parent::getData();
}
unset($this->__link);
unset($this->__result);
}
/**
Returns a new instance of object from an associative array.
@param data <b>array</b> Data array
@return <b>staticRecord</b>
*/
public static function newFromArray($data)
{
if (!is_array($data)) {
$data = array();
}
$data = array_values($data);
if (empty($data) || !is_array($data[0])) {
$cols = 0;
} else {
$cols = count($data[0]);
}
$info = array(
'con' => null,
'info' => null,
'cols' => $cols,
'rows' => count($data)
);
return new self($data,$info);
}
public function field($n)
{
return $this->__data[$this->__index][$n];
}
public function index($row=null)
{
if ($row === null) {
return $this->__index;
}
if ($row < 0 || $row+1 > $this->__info['rows']) {
return false;
}
$this->__index = $row;
return true;
}
public function rows()
{
return $this->__data;
}
/**
Changes value of a given field in the current row.
@param n <b>string</b> Field name
@param v <b>mixed</b> Field value
*/
public function set($n,$v)
{
if ($this->__index === null) {
return false;
}
$this->__data[$this->__index][$n] = $v;
}
/**
Sorts values by a field in a given order.
@param field <b>string</b> Field name
@param order <b>string</b> Sort type (asc or desc)
*/
public function sort($field,$order='asc')
{
if (!isset($this->__data[0][$field])) {
return false;
}
$this->__sortfield = $field;
$this->__sortsign = strtolower($order) == 'asc' ? 1 : -1;
usort($this->__data,array($this,'sortCallback'));
$this->__sortfield = null;
$this->__sortsign = null;
}
private function sortCallback($a,$b)
{
$a = $a[$this->__sortfield];
$b = $b[$this->__sortfield];
# Integer values
if ($a == (string) (integer) $a && $b == (string) (integer) $b) {
$a = (integer) $a;
$b = (integer) $b;
return ($a - $b) * $this->__sortsign;
}
return strcmp($a,$b) * $this->__sortsign;
}
}
?>