1
0
mirror of https://github.com/dg/dibi.git synced 2025-02-23 02:12:25 +01:00
php-dibi/dibi/dibi.php
David Grudl 799dfcc65e
2007-04-25 06:48:26 +00:00

446 lines
11 KiB
PHP

<?php
/**
* dibi - Database Abstraction Layer according to dgx
* --------------------------------------------------
*
* Copyright (c) 2005-2007 David Grudl aka -dgx- <dave@dgx.cz>
*
* for PHP 5.0.3 and newer
*
* @link http://dibi.texy.info/
* @license GNU GENERAL PUBLIC LICENSE version 2
* @package dibi
* @category Database
* @version 0.8 (Revision: $WCREV$, Date: $WCDATE$)
*/
/**
* This file is part of the "dibi" project (http://dibi.texy.info/)
*
* Copyright (c) 2005-2007 David Grudl aka -dgx- <dave@dgx.cz>
*
* @version $Revision$ $Date$
* @package dibi
*/
define('DIBI', '0.8 (Revision: $WCREV$, Date: $WCDATE$)');
if (version_compare(PHP_VERSION , '5.0.3', '<'))
die('dibi needs PHP 5.0.3 or newer');
// libraries
require_once dirname(__FILE__).'/libs/driver.php';
require_once dirname(__FILE__).'/libs/resultset.php';
require_once dirname(__FILE__).'/libs/translator.php';
require_once dirname(__FILE__).'/libs/exception.php';
/**
* Interface for user variable, used for generating SQL
*/
interface IDibiVariable
{
/**
* Format for SQL
*
* @param object destination DibiDriver
* @param string optional modifier
* @return string SQL code
*/
public function toSQL($driver, $modifier = NULL);
}
/**
* Interface for database drivers
*
* This class is static container class for creating DB objects and
* store connections info.
*
*/
class dibi
{
/**
* Column type in relation to PHP native type
*/
const
FIELD_TEXT = 's', // as 'string'
FIELD_BINARY = 'S',
FIELD_BOOL = 'b',
FIELD_INTEGER = 'i',
FIELD_FLOAT = 'f',
FIELD_DATE = 'd',
FIELD_DATETIME = 't',
FIELD_UNKNOWN = '?',
// special
FIELD_COUNTER = 'c'; // counter or autoincrement, is integer
/**
* Connection registry storage for DibiDriver objects
* @var DibiDriver[]
*/
static private $registry = array();
/**
* Current connection
* @var DibiDriver
*/
static private $conn;
/**
* Last SQL command @see dibi::query()
* @var string
*/
static public $sql;
/**
* File for logging SQL queries
* @var string|NULL
*/
static public $logFile;
/**
* Mode parameter used by fopen()
* @var string
*/
static public $logMode = 'a';
/**
* To log all queries or error queries (debug mode)
* @var bool
*/
static public $logAll = FALSE;
/**
* dibi::query() error mode
* @var bool
*/
static public $throwExceptions = FALSE;
/**
* Substitutions for identifiers
* @var array
*/
static private $substs = array();
/**
* Monostate class
*/
private function __construct()
{}
/**
* Creates a new DibiDriver object and connects it to specified database
*
* @param array|string connection parameters
* @param string connection name
* @return void
* @throw DibiException
*/
static public function connect($config, $name=0)
{
// DSN string
if (is_string($config))
parse_str($config, $config);
// config['driver'] is required
if (empty($config['driver']))
throw new DibiException('Driver is not specified.');
// include dibi driver
$className = "Dibi$config[driver]Driver";
if (!class_exists($className)) {
include_once dirname(__FILE__) . "/drivers/$config[driver].php";
if (!class_exists($className))
throw new DibiException("Unable to create instance of dibi driver class '$className'.");
}
// create connection object and store in list
/** like $conn = $className::connect($config); */
self::$conn = self::$registry[$name] = new $className($config);
if (dibi::$logAll) dibi::log("OK: connected to DB '$config[driver]'");
}
/**
* Returns TRUE when connection was established
*
* @return bool
*/
static public function isConnected()
{
return (bool) self::$conn;
}
/**
* Retrieve active connection
*
* @param string connection registy name
* @return object DibiDriver object.
* @throw DibiException
*/
static public function getConnection($name=NULL)
{
if ($name === NULL) {
if (!self::$conn)
throw new DibiException('Dibi is not connected to database');
return self::$conn;
}
if (!isset(self::$registry[$name]))
throw new DibiException("There is no connection named '$name'.");
return self::$registry[$name];
}
/**
* Change active connection
*
* @param string connection registy name
* @return void
* @throw DibiException
*/
static public function activate($name)
{
self::$conn = self::getConnection($name);
}
/**
* Generates and executes SQL query - Monostate for DibiDriver::query()
*
* @param array|mixed one or more arguments
* @return int|DibiResult
* @throw DibiException
*/
static public function query($args)
{
$args = func_get_args();
return self::getConnection()->query($args);
}
/**
* Generates and prints SQL query
*
* @param array|mixed one or more arguments
* @return bool
*/
static public function test($args)
{
// receive arguments
if (!is_array($args))
$args = func_get_args();
// and generate SQL
$trans = new DibiTranslator(self::getConnection());
try {
$sql = $trans->translate($args);
} catch (DibiException $e) {
return FALSE;
}
if ($sql === FALSE) return FALSE;
self::dump($sql);
return TRUE;
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query
* Monostate for DibiDriver::insertId()
*
* @return int|bool int on success or FALSE on failure
*/
static public function insertId()
{
return self::getConnection()->insertId();
}
/**
* Gets the number of affected rows
* Monostate for DibiDriver::affectedRows()
*
* @return int number of rows or FALSE on error
*/
static public function affectedRows()
{
return self::getConnection()->affectedRows();
}
/**
* Executes the SQL query - Monostate for DibiDriver::nativeQuery()
*
* @param string SQL statement.
* @return object|bool Result set object or TRUE on success, FALSE on failure
*/
static public function nativeQuery($sql)
{
return self::getConnection()->nativeQuery($sql);
}
static private function dumpHighlight($matches)
{
if (!empty($matches[1])) // comment
return '<em style="color:gray">'.$matches[1].'</em>';
if (!empty($matches[2])) // error
return '<strong style="color:red">'.$matches[2].'</strong>';
if (!empty($matches[3])) // most important keywords
return '<strong style="color:blue">'.$matches[3].'</strong>';
if (!empty($matches[4])) // other keywords
return '<strong style="color:green">'.$matches[4].'</strong>';
}
/**
* Prints out a syntax highlighted version of the SQL command
*
* @param string SQL command
* @param bool return or print?
* @return void
*/
static public function dump($sql, $return=FALSE) {
static $keywords2 = 'ALL|DISTINCT|AS|ON|INTO|AND|OR|AS';
static $keywords1 = 'SELECT|UPDATE|INSERT|DELETE|FROM|WHERE|HAVING|GROUP\s+BY|ORDER\s+BY|LIMIT|SET|VALUES|LEFT\s+JOIN|INNER\s+JOIN';
// insert new lines
$sql = preg_replace("#\\b(?:$keywords1)\\b#", "\n\$0", $sql);
$sql = trim($sql);
// reduce spaces
$sql = preg_replace('# {2,}#', ' ', $sql);
$sql = wordwrap($sql, 100);
$sql = htmlSpecialChars($sql);
$sql = preg_replace("#\n{2,}#", "\n", $sql);
// syntax highlight
$sql = preg_replace_callback("#(/\\*.+?\\*/)|(\\*\\*.+?\\*\\*)|\\b($keywords1)\\b|\\b($keywords2)\\b#", array('dibi', 'dumpHighlight'), $sql);
$sql = '<pre class="dump">' . $sql . "</pre>\n";
// print & return
if (!$return) echo $sql;
return $sql;
}
/**
* Displays complete result-set as HTML table
*
* @param object DibiResult
* @return void
*/
static public function dumpResult(DibiResult $res)
{
echo '<table class="dump"><tr>';
echo '<th>#row</th>';
foreach ($res->getFields() as $field)
echo '<th>' . $field . '</th>';
echo '</tr>';
foreach ($res as $row => $fields) {
echo '<tr><th>', $row, '</th>';
foreach ($fields as $field) {
if (is_object($field)) $field = $field->__toString();
echo '<td>', htmlSpecialChars($field), '</td>';
}
echo '</tr>';
}
echo '</table>';
}
/**
* Create a new substitution pair for indentifiers
* @param string from
* @param string to
* @return void
*/
static public function addSubst($expr, $subst)
{
self::$substs[':'.$expr.':'] = $subst;
}
/**
* Remove substitution pair
* @param string from
* @return void
*/
static public function removeSubst($expr)
{
unset(self::$substs[':'.$expr.':']);
}
/**
* Process substitutions in string
* @param string
* @return string
*/
static public function substitute($s)
{
if (strpos($s, ':') === FALSE) return $s;
return strtr($s, self::$substs);
}
/**
* Error logging
* EXPERIMENTAL
*/
static public function log($message)
{
if (self::$logFile == NULL || self::$logMode == NULL) return;
$f = fopen(self::$logFile, self::$logMode);
if (!$f) return;
flock($f, LOCK_EX);
fwrite($f, $message. "\n\n");
fclose($f);
}
} // class dibi