You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

442 lines
11 KiB

<?php
/**
* Typecho Blog Platform
*
* @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
* @license GNU General Public License 2.0
* @version $Id: Db.php 107 2008-04-11 07:14:43Z magike.net $
*/
/**
* 包含获取数据支持方法的类.
* 必须定义__TYPECHO_DB_HOST__, __TYPECHO_DB_PORT__, __TYPECHO_DB_NAME__,
* __TYPECHO_DB_USER__, __TYPECHO_DB_PASS__, __TYPECHO_DB_CHAR__
*
* @package Db
*/
class Typecho_Db
{
/** 读取数据库 */
const READ = 1;
/** 写入数据库 */
const WRITE = 2;
/** 升序方式 */
const SORT_ASC = 'ASC';
/** 降序方式 */
const SORT_DESC = 'DESC';
/** 表内连接方式 */
const INNER_JOIN = 'INNER';
/** 表外连接方式 */
const OUTER_JOIN = 'OUTER';
/** 表左连接方式 */
const LEFT_JOIN = 'LEFT';
/** 表右连接方式 */
const RIGHT_JOIN = 'RIGHT';
/** 数据库查询操作 */
const SELECT = 'SELECT';
/** 数据库更新操作 */
const UPDATE = 'UPDATE';
/** 数据库插入操作 */
const INSERT = 'INSERT';
/** 数据库删除操作 */
const DELETE = 'DELETE';
/**
* 数据库适配器
* @var Typecho_Db_Adapter
*/
private $_adapter;
/**
* 默认配置
*
* @access private
* @var Typecho_Config
*/
private $_config;
/**
* 连接池
*
* @access private
* @var array
*/
private $_pool;
/**
* 已经连接
*
* @access private
* @var array
*/
private $_connectedPool;
/**
* 前缀
*
* @access private
* @var string
*/
private $_prefix;
/**
* 适配器名称
*
* @access private
* @var string
*/
private $_adapterName;
/**
* 实例化的数据库对象
* @var Typecho_Db
*/
private static $_instance;
/**
* 数据库类构造函数
*
* @param mixed $adapterName 适配器名称
* @param string $prefix 前缀
* @throws Typecho_Db_Exception
*/
public function __construct($adapterName, $prefix = 'typecho_')
{
/** 获取适配器名称 */
$this->_adapterName = $adapterName;
/** 数据库适配器 */
$adapterName = 'Typecho_Db_Adapter_' . $adapterName;
if (!call_user_func(array($adapterName, 'isAvailable'))) {
throw new Typecho_Db_Exception("Adapter {$adapterName} is not available");
}
$this->_prefix = $prefix;
/** 初始化内部变量 */
$this->_pool = array();
$this->_connectedPool = array();
$this->_config = array();
//实例化适配器对象
$this->_adapter = new $adapterName();
}
/**
* 获取适配器名称
*
* @access public
* @return string
*/
public function getAdapterName()
{
return $this->_adapterName;
}
/**
* 获取表前缀
*
* @access public
* @return string
*/
public function getPrefix()
{
return $this->_prefix;
}
/**
* getConfig
*
* @access public
* @return array
*/
public function getConfig()
{
return $this->_config;
}
/**
* 重置连接池
*
* @return void
*/
public function flushPool()
{
$this->_connectedPool = array();
}
/**
* 选择数据库
*
* @param int $op
* @return Typecho_Db_Adapter
* @throws Typecho_Db_Exception
*/
public function selectDb($op)
{
if (!isset($this->_connectedPool[$op])) {
if (empty($this->_pool[$op])) {
/** Typecho_Db_Exception */
throw new Typecho_Db_Exception('Missing Database Connection');
}
//获取相应读或写服务器连接池中的一个
$selectConnection = rand(0, count($this->_pool[$op]) - 1);
//获取随机获得的连接池配置
$selectConnectionConfig = $this->_config[$this->_pool[$op][$selectConnection]];
$selectConnectionHandle = $this->_adapter->connect($selectConnectionConfig);
$this->_connectedPool[$op] = &$selectConnectionHandle;
}
return $this->_connectedPool[$op];
}
/**
* 获取SQL词法构建器实例化对象
*
* @return Typecho_Db_Query
*/
public function sql()
{
return new Typecho_Db_Query($this->_adapter, $this->_prefix);
}
/**
* 为多数据库提供支持
*
* @access public
* @param Typecho_Db $db 数据库实例
* @param integer $op 数据库操作
* @return void
*/
public function addServer($config, $op)
{
$this->_config[] = Typecho_Config::factory($config);
$key = count($this->_config) - 1;
/** 将连接放入池中 */
switch ($op) {
case self::READ:
case self::WRITE:
$this->_pool[$op][] = $key;
break;
default:
$this->_pool[self::READ][] = $key;
$this->_pool[self::WRITE][] = $key;
break;
}
}
/**
* 获取版本
*
* @param int $op
* @return string
*/
public function getVersion($op = self::READ)
{
return $this->_adapter->getVersion($this->selectDb($op));
}
/**
* 设置默认数据库对象
*
* @access public
* @param Typecho_Db $db 数据库对象
* @return void
*/
public static function set(Typecho_Db $db)
{
self::$_instance = $db;
}
/**
* 获取数据库实例化对象
* 用静态变量存储实例化的数据库对象,可以保证数据连接仅进行一次
*
* @return Typecho_Db
* @throws Typecho_Db_Exception
*/
public static function get()
{
if (empty(self::$_instance)) {
/** Typecho_Db_Exception */
throw new Typecho_Db_Exception('Missing Database Object');
}
return self::$_instance;
}
/**
* 选择查询字段
*
* @access public
* @param mixed $field 查询字段
* @return Typecho_Db_Query
*/
public function select()
{
$args = func_get_args();
return call_user_func_array(array($this->sql(), 'select'), $args ? $args : array('*'));
}
/**
* 更新记录操作(UPDATE)
*
* @param string $table 需要更新记录的表
* @return Typecho_Db_Query
*/
public function update($table)
{
return $this->sql()->update($table);
}
/**
* 删除记录操作(DELETE)
*
* @param string $table 需要删除记录的表
* @return Typecho_Db_Query
*/
public function delete($table)
{
return $this->sql()->delete($table);
}
/**
* 插入记录操作(INSERT)
*
* @param string $table 需要插入记录的表
* @return Typecho_Db_Query
*/
public function insert($table)
{
return $this->sql()->insert($table);
}
/**
* 执行查询语句
*
* @param mixed $query 查询语句或者查询对象
* @param boolean $op 数据库读写状态
* @param string $action 操作动作
* @return mixed
*/
public function query($query, $op = self::READ, $action = self::SELECT)
{
/** 在适配器中执行查询 */
if ($query instanceof Typecho_Db_Query) {
$action = $query->getAttribute('action');
$op = (self::UPDATE == $action || self::DELETE == $action
|| self::INSERT == $action) ? self::WRITE : self::READ;
} else if (!is_string($query)) {
/** 如果query不是对象也不是字符串,那么将其判断为查询资源句柄,直接返回 */
return $query;
}
/** 选择连接池 */
$handle = $this->selectDb($op);
/** 提交查询 */
$resource = $this->_adapter->query($query instanceof Typecho_Db_Query ?
$query->prepare($query) : $query, $handle, $op, $action);
if ($action) {
//根据查询动作返回相应资源
switch ($action) {
case self::UPDATE:
case self::DELETE:
return $this->_adapter->affectedRows($resource, $handle);
case self::INSERT:
return $this->_adapter->lastInsertId($resource, $handle);
case self::SELECT:
default:
return $resource;
}
} else {
//如果直接执行查询语句则返回资源
return $resource;
}
}
/**
* 一次取出所有行
*
* @param mixed $query 查询对象
* @param array $filter 行过滤器函数,将查询的每一行作为第一个参数传入指定的过滤器中
* @return array
*/
public function fetchAll($query, array $filter = NULL)
{
//执行查询
$resource = $this->query($query, self::READ);
$result = array();
/** 取出过滤器 */
if (!empty($filter)) {
list($object, $method) = $filter;
}
//取出每一行
while ($rows = $this->_adapter->fetch($resource)) {
//判断是否有过滤器
$result[] = $filter ? call_user_func(array(&$object, $method), $rows) : $rows;
}
return $result;
}
/**
* 一次取出一行
*
* @param mixed $query 查询对象
* @param array $filter 行过滤器函数,将查询的每一行作为第一个参数传入指定的过滤器中
* @return mixed
*/
public function fetchRow($query, array $filter = NULL)
{
$resource = $this->query($query, self::READ);
/** 取出过滤器 */
if ($filter) {
list($object, $method) = $filter;
}
return ($rows = $this->_adapter->fetch($resource)) ?
($filter ? $object->$method($rows) : $rows) :
array();
}
/**
* 一次取出一个对象
*
* @param mixed $query 查询对象
* @param array $filter 行过滤器函数,将查询的每一行作为第一个参数传入指定的过滤器中
* @return mixed
*/
public function fetchObject($query, array $filter = NULL)
{
$resource = $this->query($query, self::READ);
/** 取出过滤器 */
if ($filter) {
list($object, $method) = $filter;
}
return ($rows = $this->_adapter->fetchObject($resource)) ?
($filter ? $object->$method($rows) : $rows) :
new stdClass();
}
}