您的位置:首页 > 编程语言 > PHP开发

[置顶] orm 用多了,忽然发觉SQL不会写了... 整个基本的功能重新学习SQL,改自fleaphp

2016-08-25 17:06 597 查看
<?php
/**
* 数据库封装对象,对Mysql的一个操作封装
*
*/
class CoreDB {

/**
* 数据库操作实用工具对象
*
* @var CoreDbUtils
*/
protected $_dbUtils = NULL;

/**
* 链接资源标志
*
* @var resource
*/
protected $_link_identifier = NULL ;

protected $_dsn = null;

/**
* 执行的查询计数
*
* @var int
*/
protected $querycount = 0;

/**
* 最后一次数据库操作的错误信息
*
* @var mixed
*/
public $lasterr = null;

/**
* 最后一次数据库操作的错误代码
*
* @var mixed
*/
public $lasterrcode = null;

/**
* 最近一次插入操作或者 lastInsertId() 操作返回的插入 ID
*
* @var mixed
*/
protected $_lastInsertId = null;

/**
* 指示数据库是否支持事务
*
* @var boolean
*/
protected $_has_transaction = false;

/**
* 指示数据库是否支持事务中的 SAVEPOINT 功能
*
* @var boolean
*/
protected $_has_savepoint = false;

/**
* 指示事务启动次数
*
* @var int
*/
protected $_trans_count = 0;

/**
* 指示事务执行期间是否发生了错误
*
* @var boolean
*/
protected $_has_failed_query = false;

/**
* SAVEPOINT 堆栈
*
* @var array
*/
protected $_savepoint_stack = array();

/**
* 数据库程序版本号
*/
private $_version = NULL;

function __construct(array $dsn,$doParse=true){
$this->_dsn = $doParse ? self::parseDSN($dsn) : $dsn;
}

/**
* 连接数据库
*
* @return bool
* @throw SqlQueryException
*/
function connect(){
if (is_resource($this->_link_identifier)) return;
$host = $this->_dsn['host'] . ( empty($this->_dsn['port']) ? '' : ":{$this->_dsn['port']}" );

if (!empty($this->_dsn['options'])) {
$this->_link_identifier = @mysql_connect($host, $dsn['login'], $dsn['password'], false, $this->_dsn['options']);
} else {
$this->_link_identifier = @mysql_connect($host,$this->_dsn['login'] ,$this->_dsn['password']);
}
//		$this->_log_($this->_link_identifier);

if (!$this->_link_identifier){
$this->lasterr = mysql_error();
$this->lasterrcode = mysql_errno();
throw new SqlQueryException("connect('{$host}','{$this->_dsn['login']}') failed!", $this->lasterr, $this->lasterrcode);
}

if (!empty($this->_dsn['database'])) {
$this->selectDb($this->_dsn['database']);
}

$this->_version = $this->getOne('SELECT VERSION()');
if ($this->_version >= '5.0') {
$this->_has_transaction = true;
}

// 设置字符集
if (!empty($this->_dsn['charset'])) {
$this->execute("SET NAMES '{$this->_dsn['charset']}'");
}

return true;
}

/**
* 关闭数据库连接
*/
function close(){
if($this->_link_identifier){
mysql_close($this->_link_identifier);
}
$this->_link_identifier = NULL ;
$this->_lastInsertId = null;
$this->_trans_count = 0;
}

/**
* 选择要操作的数据库
*
* @param string $database
*
* @return boolean
*/
function selectDb($database)
{
if (!mysql_select_db($database, $this->_link_identifier)) {
$this->lasterr = mysql_error($this->_link_identifier);
$this->lasterrcode = mysql_errno($this->_link_identifier);
throw new SqlQueryException("SELECT DATABASE: '{$database}' FAILED!", $this->lasterr,$this->lasterrcode);
}
return true;
}

/**
* 启动事务
*/
function startTrans()
{
if ($this->_has_transaction){

if ($this->_trans_count == 0) {
$this->execute('START TRANSACTION');
$this->_has_failed_query = false;
}
$this->_trans_count++;

if ($this->_trans_count > 1 && $this->_has_savepoint) {
$savepoint = 'savepoint_' . $this->_trans_count;
$this->execute("SAVEPOINT {$savepoint}");
array_push($this->_savepoint_stack, $savepoint);
}
}
}

/**
* 完成事务,根据查询是否出错决定是提交事务还是回滚事务
*
* 如果 $commitOnNoErrors 参数为 true,当事务中所有查询都成功完成时,则提交事务,否则回滚事务
* 如果 $commitOnNoErrors 参数为 false,则强制回滚事务
*
* @param $commitOnNoErrors 指示在没有错误时是否提交事务
*/
function completeTrans($commitOnNoErrors = true)
{
if ($this->_has_transaction && $this->_trans_count > 0){
$this->_trans_count--;
if ($this->_trans_count > 0 && $this->_has_savepoint) {
$savepoint = array_pop($this->_savepoint_stack);
if ($this->_has_failed_query || $commitOnNoErrors == false) {
$this->execute("ROLLBACK TO SAVEPOINT {$savepoint}");
}
} else {
if ($this->_has_failed_query == false && $commitOnNoErrors) {
$this->execute('COMMIT');
} else {
$this->execute('ROLLBACK');
}
}
}
}

/**
* 强制指示在调用 completeTrans() 时回滚事务
*/
function failTrans()
{
$this->_has_failed_query = true;
}

/**
* 返回事务是否失败的状态
*/
function hasFailedTrans()
{
return $this->_has_failed_query;
}

/**
* 执行一个查询,返回一个 resource 或者 boolean 值
*
* @param string $sql
* @param array $inputarr
* @param boolean $throw 指示查询出错时是否抛出异常
*
* @return resource|boolean
*/
function execute($sql, $inputarr = null, $throw = true)
{
if (is_array($inputarr)) {
$sql = $this->bind($sql, $inputarr);
}

$this->_log_($sql);

$this->querycount++;
$result = mysql_query($sql, $this->_link_identifier);
if ($result !== false) {
return $result;
}
$this->lasterr = mysql_error($this->_link_identifier);
$this->lasterrcode = mysql_errno($this->_link_identifier);

if ($throw) {
throw new SqlQueryException($sql, $this->lasterr, $this->lasterrcode);
}
return false;
}

/**
* 返回最近一次数据库操作受到影响的记录数
*
* @return int
*/
function lastQueryAffectedRows(){
return mysql_affected_rows($this->_link_identifier);
}

/**
* 获取最后一次 nextId 操作获得的值
*
* @return int
*/
function lastInsertId(){
return mysql_insert_id($this->_link_identifier);
}

/**
* 执行一个查询,返回查询结果记录集
*
* @param string|resource $sql
*
* @return array
*/
function getAll($sql)
{
$res = is_resource($sql) ? $sql : $this->execute($sql);
$rowset = array();
while ($row = mysql_fetch_assoc($res)) {
$rowset[] = $row;
}
mysql_free_result($res);
return $rowset;
}

/**
* 执行查询,返回第一条记录的第一个字段
*
* @param string|resource $sql
*
* @return mixed
*/
function getOne($sql)
{
$res = is_resource($sql) ? $sql : $this->execute($sql);
$row = mysql_fetch_row($res);
mysql_free_result($res);
return isset($row[0]) ? $row[0] : null;
}

/**
* 执行查询,返回第一条记录
*
* @param string|resource $sql
*
* @return mixed
*/
function getRow($sql)
{
$res = is_resource($sql) ? $sql : $this->execute($sql);
$row = mysql_fetch_assoc($res);
mysql_free_result($res);
return $row;
}

/**
* 执行查询,返回结果集的指定列
*
* @param string|resource $sql
* @param int $col 要返回的列,0 为第一列
*
* @return mixed
*/
function getCol($sql, $col = 0)
{
$res = is_resource($sql) ? $sql : $this->execute($sql);
$data = array();
while ($row = mysql_fetch_row($res)) {
$data[] = $row[$col];
}
mysql_free_result($res);
return $data;
}

/**
* 从记录集中返回一行数据
*
* @param resouce $res
*
* @return array
*/
function fetchRow($res)
{
return mysql_fetch_row($res);
}

/**
* 从记录集中返回一行数据,字段名作为键名
*
* @param resouce $res
*
* @return array
*/
function fetchAssoc($res)
{
return mysql_fetch_assoc($res);
}

/**
* 释放查询句柄
*
* @param resource $res
*
* @return boolean
*/
function freeRes($res)
{
return mysql_free_result($res);
}

/**
* 转义字符串
*
* @param string $value
*
* @return mixed
*/
function qstr($value)
{
if (is_int($value) || is_float($value)) { return $value; }
if (is_bool($value)) { return $value ? 1 : 0; }
if (is_null($value)) { return 'NULL'; }
return "'" . mysql_real_escape_string($value, $this->_link_identifier) . "'";
}

/**
* 执行一个查询,返回分组后的查询结果记录集
*
* $groupBy 参数如果为字符串或整数,表示结果集根据 $groupBy 参数指定的字段进行分组。
* 如果 $groupBy 参数为 true,则表示根据每行记录的第一个字段进行分组。
*
* @param string|resource $sql
* @param string $groupBy
*
* @return array
*/
function getAllGroupBy($sql, & $groupBy)
{
$res = is_resource($sql) ? $sql : $this->execute($sql);
$data = array();
$row = mysql_fetch_assoc($res);
if ($row != false) {
if (empty($groupBy)) {
$groupBy = key($row);
}
do {
$rkv = $row[$groupBy];
unset($row[$groupBy]);
$data[$rkv][] = $row;
} while ($row = mysql_fetch_assoc($res));
}
mysql_free_result($res);
return $data;
}

/**
* 分析 DSN 数组,返回包含 DSN 连接信息的数组,失败返回 false
*
* @param array $dsn
*
* @return array
*/
static function parseDSN(array $dsn)
{
if (empty($dsn)) return NULL;

$dsn['host'] = isset($dsn['host']) ? $dsn['host'] : '';
$dsn['port'] = isset($dsn['port']) ? $dsn['port'] : '';
$dsn['login'] = isset($dsn['login']) ? $dsn['login'] : '';
$dsn['password'] = isset($dsn['password']) ? $dsn['password'] : '';
$dsn['database'] = isset($dsn['database']) ? $dsn['database'] : '';
$dsn['charset'] = isset($dsn['charset']) ? $dsn['charset'] : 'utf8';
$dsn['options'] = isset($dsn['options']) ? $dsn['options'] : '';
$dsn['prefix'] = isset($dsn['prefix']) ? $dsn['prefix'] : '';
$dsn['schema'] = isset($dsn['schema']) ? $dsn['schema'] : '';

$dsnid = "mysql://{$dsn['login']}:{$dsn['password']}@{$dsn['host']}_{$dsn['prefix']}/{$dsn['database']}/{$dsn['schema']}/{$dsn['options']}";
$dsn['id'] = $dsnid;
return $dsn;
}

/**
* 返回数据库访问对象实例
*
* 必须提供 $dsn 参数
*
* DSN 是 Database Source Name 的缩写,可以理解为数据源名字。
* DSN 是一个数组,包含了连接数据库需要的各种信息,例如主机、用户名、密码等。
*
* DSN 的正确写法:
*
* example:
* <code>
* $dsn = array(
*      'host'     => 'localhost',
*      'login'    => 'username',
*      'password' => 'password',
*      'database' => 'test_db',
*      'charset'  => 'utf8',
* );
*
* $dbo = CoreDB::instance($dsn);
* </code>
*
* @param array $dsn
*
* @return CoreDB
*/
static function instance(array $dsn)
{
$dsn = self::parseDSN($dsn);

$dsnid = "core-db/[{$dsn['id']}]";
if (App::isRegistered($dsnid)) return App::registry($dsnid);

return App::register(new self($dsn,false),$dsnid);
}

/**
* 返回 数据库操作工具对象
*
* @return CoreDbUtils
*/
function getDbUtils(){
if (!$this->_dbUtils){
$this->_dbUtils = new CoreDbUtils($this);
}
return $this->_dbUtils;
}

private function _log_($statement)
{
App::$_logWriter_->append($statement,'sql','debug');
}

}

/**
* InvalidDSNException 异常指示没有提供有效的 DSN 设置
*
*/
class InvalidDSNException extends Exception
{
public $dsn;

/**
* 构造函数
*
* @param array $dsn
*/
function __construct(array $dsn)
{
unset($dsn['password']);
$this->dsn = $dsn;
parent::__construct('无效的数据源名称“Data-Source-Name (DSN)”.');
}
}

/**
* SqlQueryException 异常指示一个 SQL 语句执行错误
*
*/
class SqlQueryException extends Exception
{
public $sql;
public $error;
public $errno;

/**
* 构造函数
*
* @param string $sql sql语句
* @param string $error 错误文本
* @param int $errno 错误号
*/
function __construct($sql, $error ,$errno)
{
$this->sql = $sql;
$this->error = $error;
$this->errno = $errno;

$msg = sprintf('SQL: "%s"\nError: "%s"\nErrno: "%s"', $sql, $error ,$errno);
parent::__construct($msg);
}
}

require_once 'dbutils.php';

 
<?php
/**
* CoreDb 工具
*
*/
final class CoreDbUtils {

/**
* @var CoreDb
*/
private $_dbo = NULL;

function __construct(CoreDb $dbo){
$this->_dbo = $dbo;
}

/**
*  C CHAR 或 VARCHAR 类型字段
*  X TEXT 或 CLOB 类型字段
*  B 二进制数据(BLOB)
*  N 数值或者浮点数
*  D 日期
*  T TimeStamp
*  L 逻辑布尔值
*  I 整数
*  R 自动增量或计数器
*/
private static $typeMap = array(
'BIT'           => 'I',
'TINYINT'       => 'I',
'BOOL'          => 'L',
'BOOLEAN'       => 'L',
'SMALLINT'      => 'I',
'MEDIUMINT'     => 'I',
'INT'           => 'I',
'INTEGER'       => 'I',
'BIGINT'        => 'I',
'FLOAT'         => 'N',
'DOUBLE'        => 'N',
'DOUBLEPRECISION' => 'N',
'FLOAT'         => 'N',
'DECIMAL'       => 'N',
'DEC'           => 'N',

'DATE'          => 'D',
'DATETIME'      => 'T',
'TIMESTAMP'     => 'T',
'TIME'          => 'T',
'YEAR'          => 'I',

'CHAR'          => 'C',
'NCHAR'         => 'C',
'VARCHAR'       => 'C',
'NVARCHAR'      => 'C',
'BINARY'        => 'B',
'VARBINARY'     => 'B',
'TINYBLOB'      => 'X',
'TINYTEXT'      => 'X',
'BLOB'          => 'X',
'TEXT'          => 'X',
'MEDIUMBLOB'    => 'X',
'MEDIUMTEXT'    => 'X',
'LONGBLOB'      => 'X',
'LONGTEXT'      => 'X',
'ENUM'          => 'C',
'SET'           => 'C',
);

/**
* 按照指定的类型,返回值
*
* @param mixed $value
* @param string $type
*
* @return mixed
*/
static function setValueByType($value, $type)
{
/**
*  C CHAR 或 VARCHAR 类型字段
*  X TEXT 或 CLOB 类型字段
*  B 二进制数据(BLOB)
*  N 数值或者浮点数
*  D 日期
*  T TimeStamp
*  L 逻辑布尔值
*  I 整数
*  R 自动增量或计数器
*/
switch (strtoupper($type)) {
case 'I':
return (int)$value;
case 'N':
return (float)$value;
case 'L':
return (bool)$value;
default:
return $value;
}
}

/**
* 返回指定表(或者视图)的元数据
*
* 部分代码参考 ADOdb 实现。
*
* 每个字段包含下列属性:
*
* name:            字段名
* scale:           小数位数
* type:            字段类型
* simpleType:      简单字段类型(与数据库无关)
* maxLength:       最大长度
* notNull:         是否不允许保存 NULL 值
* primaryKey:      是否是主键
* autoIncrement:   是否是自动增量字段
* binary:          是否是二进制数据
* unsigned:        是否是无符号数值
* hasDefault:      是否有默认值
* defaultValue:    默认值
*
* @param string $table
*
* @return array
*/
function metaColumns($table)
{
$rs = $this->_dbo->execute(sprintf('SHOW FULL COLUMNS FROM %s', $table));
if (!$rs) { return false; }
$retarr = array();
while (($row = $this->_dbo->fetchAssoc($rs))) {
$field = array();
$field['name'] = $row['Field'];
$type = $row['Type'];

$field['scale'] = null;
$queryArray = false;
if (preg_match('/^(.+)\((\d+),(\d+)/', $type, $queryArray)) {
$field['type'] = $queryArray[1];
$field['maxLength'] = is_numeric($queryArray[2]) ? $queryArray[2] : -1;
$field['scale'] = is_numeric($queryArray[3]) ? $queryArray[3] : -1;
} elseif (preg_match('/^(.+)\((\d+)/', $type, $queryArray)) {
$field['type'] = $queryArray[1];
$field['maxLength'] = is_numeric($queryArray[2]) ? $queryArray[2] : -1;
} elseif (preg_match('/^(enum)\((.*)\)$/i', $type, $queryArray)) {
$field['type'] = $queryArray[1];
$arr = explode(",",$queryArray[2]);
$field['enums'] = $arr;
$zlen = max(array_map("strlen",$arr)) - 2; // PHP >= 4.0.6
$field['maxLength'] = ($zlen > 0) ? $zlen : 1;
} else {
$field['type'] = $type;
$field['maxLength'] = -1;
}
$field['simpleType'] = self::$typeMap[strtoupper($field['type'])];
// if ($field['simpleType'] == 'C' && $field['maxLength'] > 250) {
// $field['simpleType'] = 'X';
// }
$field['notNull'] = ($row['Null'] != 'YES');
$field['primaryKey'] = ($row['Key'] == 'PRI');
$field['autoIncrement'] = (strpos($row['Extra'], 'auto_increment') !== false);
if ($field['autoIncrement']) { $field['simpleType'] = 'R'; }
$field['binary'] = (strpos($type,'blob') !== false);
$field['unsigned'] = (strpos($type,'unsigned') !== false);

if ($field['type'] == 'tinyint' && $field['maxLength'] == 1) {
$field['simpleType'] = 'L';
}

if (!$field['binary']) {
$d = $row['Default'];
if ($d != '' && $d != 'NULL') {
$field['hasDefault'] = true;
$field['defaultValue'] = self::setValueByType($d, $field['simpleType']);
} else {
$field['hasDefault'] = false;
}
}

$field['description'] = isset($row['Comment']) ? $row['Comment'] : '';

$retarr[strtoupper($field['name'])] = $field;
}
$this->_dbo->freeRes($rs);
return $retarr;
}

/**
* 获得所有数据表的名称
*
* @param string $pattern
* @param string $schema
*
* @return array
*/
function metaTables($pattern = null, $schema = null)
{
$sql = 'SHOW TABLES';
if (!empty($schema)) {
$sql .= " FROM {$schema}";
}
if (!empty($pattern)) {
$sql .= ' LIKE ' . $this->_dbo->qstr($schema);
}
$res = $this->_dbo->execute($sql, null, false);
$tables = array();
while (($row = $this->_dbo->fetchRow($res))) {
$tables[] = reset($row);
}
$this->_dbo->freeRes($res);
return $tables;
}

/**
* 为数据表产生下一个序列值
*
* @param string $seqName
* @param string $startValue
*
* @return int
*/
function nextId($seqName = 'coredb_seq', $startValue = 1)
{
$getNextIdSql = sprintf('UPDATE %s SET id = LAST_INSERT_ID(id + 1)', $seqName);
$result = $this->_dbo->execute($getNextIdSql, null, false);
if (!$result) {
if (!$this->createSeq($seqName, $startValue)) { return false; }
$result = $this->_dbo->execute($getNextIdSql);
if (!$result) { return false; }
}
return $this->_dbo->lastInsertId();
}

/**
* 创建一个新的序列,成功返回 true,失败返回 false
*
* @param string $seqName
* @param int $startValue
*
* @return boolean
*/
function createSeq($seqName = 'coredb_seq', $startValue = 1)
{
if ($this->_dbo->execute(sprintf('CREATE TABLE %s (id INT NOT NULL)', $seqName))) {
return $this->_dbo->execute(sprintf('INSERT INTO %s VALUES (%s)', $seqName, $startValue - 1));
} else {
return false;
}
}

/**
* 删除一个序列
*
* @param string $seqName
*/
function dropSeq($seqName = 'coredb_seq')
{
return $this->_dbo->execute(sprintf('DROP TABLE %s', $seqName));
}

/**
* 执行一个查询,返回查询结果记录集、指定字段的值集合以及以该字段值分组后的记录集
*
* @param string|resource $sql
* @param string $field
* @param array $fieldValues
* @param array $reference
*
* @return array
*/
function getAllWithFieldRefs($sql, $field, & $fieldValues, & $reference)
{
$res = is_resource($sql) ? $sql : $this->_dbo->execute($sql);
$fieldValues = array();
$reference = array();
$offset = 0;
$data = array();

while ($row = $this->_dbo->fetchAssoc($res)) {
$fieldValue = $row[$field];
unset($row[$field]);
$data[$offset] = $row;
$fieldValues[$offset] = $fieldValue;
$reference[$fieldValue] =& $data[$offset];
$offset++;
}
$this->_dbo->freeRes($res);
return $data;
}

/**
* 执行一个查询,并将数据按照指定字段分组后与 $assocRowset 记录集组装在一起
*
* @param string|resource $sql
* @param array $assocRowset
* @param string $mappingName
* @param boolean $oneToOne
* @param string $refKeyName
* @param mixed $limit
*/
function assemble($sql, & $assocRowset, $mappingName, $oneToOne, $refKeyName, $limit = null)
{
if (is_resource($sql)) {
$res = $sql;
} else {
if (!is_null($limit)) {
if (is_array($limit)) {
list($length, $offset) = $limit;
} else {
$length = $limit;
$offset = 0;
}
$res = $this->_dbo->selectLimit($sql, $length, $offset);
} else {
$res = $this->_dbo->execute($sql);
}
}

if ($oneToOne) {
// 一对一组装数据
while ($row = $this->_dbo->fetchAssoc($res)) {
$rkv = $row[$refKeyName];
unset($row[$refKeyName]);
$assocRowset[$rkv][$mappingName] = $row;
}
} else {
// 一对多组装数据
while ($row = $this->_dbo->fetchAssoc($res)) {
$rkv = $row[$refKeyName];
unset($row[$refKeyName]);
$assocRowset[$rkv][$mappingName][] = $row;
}
}
$this->_dbo->freeRes($res);
}
}

/**
* SqlHelper 类提供了各种生成 SQL 语句的辅助方法
*
*/
final class CoreDbSqlHelper {

/**
* 分析查询条件
*
* @param CoreDb $dbo
* @param mixed $conditions
*
* @return string
*/
static function parseConditions(CoreDb $dbo, $conditions)
{
// 对于 NULL,直接返回 NULL
if (is_null($conditions)) { return null; }

// 如果是字符串,则假定为自定义条件
if (is_string($conditions)) {
return $conditions;
}

// 如果不是数组,说明提供的查询条件有误
if (!is_array($conditions)) {
return null;
}
$where = '';
$expr = '';

/**
* 不过何种条件形式,一律为  字段名 => (值, 操作, 连接运算符, 值是否是SQL命令) 的形式
*/
foreach ($conditions as $field => $cond) {

$expr = 'AND';

if (!is_string($field)) {
continue;
}
if (!is_array($cond)) {
// 字段名 => 值
$cond = array($cond);
}
reset($cond);
// 第一个元素是值
if (!isset($cond[1])) { $cond[1] = '='; }
if (!isset($cond[2])) { $cond[2] = $expr; }
if (!isset($cond[3])) { $cond[3] = false; }

list($value, $op, $expr, $isCommand) = $cond;

if (is_array($value)){
$value = '(' . implode(',',array_map(array($dbo, 'qstr'),$value)) . ')' ;
$op = 'IN';
$isCommand = true;
}

if (!$isCommand) {
$value = $dbo->qstr($value);
}

$where .= "{$field} {$op} {$value} {$expr} ";
}

$where = substr($where, 0, - (strlen($expr) + 2));
return $where;
}

/**
* 返回 limit sql字串
*
* @param int|array $limit
* @return string
*/
static function getLimitSql($limit){
if (is_null($limit)) return '';

if (is_array($limit)) {
list($length, $offset) = $limit;
} else {
$length = $limit;
$offset = null;
}

if (!is_null($offset)) {
$sql = " LIMIT " . (int)$offset;
if (!is_null($length)) {
$sql .= ', ' . (int)$length;
} else {
$sql .= ', 4294967294';
}
} elseif (!is_null($length)) {
$sql = " LIMIT " . (int)$length;
}
return $sql;
}

/**
* 返回数据库可以接受的日期格式
*
* @param int $timestamp
* @return string
*/
static function dbTimeStamp($timestamp)
{
return date('Y-m-d H:i:s', $timestamp);
}

/**
* 将数据表名字转换为完全限定名
*
* @param string $tableName
* @param string $schema
*
* @return string
*/
static function qtable($tableName, $schema = null)
{
return $schema != '' ? "`{$schema}`.`{$tableName}`" : "`{$tableName}`";
}

/**
* 将字段名转换为完全限定名,避免因为字段名和数据库关键词相同导致的错误
*
* @param string $fieldName
* @param string $tableName
* @param string $schema
*
* @return string
*/
static function qfield($fieldName, $tableName = null, $schema = null)
{
$fieldName = ($fieldName == '*') ? '*' : "`{$fieldName}`";
return $tableName != '' ? self::qtable($tableName, $schema) . '.' . $fieldName : $fieldName;
}

/**
* 一次性将多个字段名转换为完全限定名
*
* @param string|array $fields
* @param string $tableName
* @param string $schema
* @param boolean $returnArray
*
* @return string
*/
static function qfields($fields, $tableName = null, $schema = null, $returnArray = false)
{
if (!is_array($fields)) {
$fields = explode(',', $fields);
$fields = array_map('trim', $fields);
}
$return = array();
foreach ($fields as $fieldName) {
$return[] = self::qfield($fieldName, $tableName, $schema);
}
return $returnArray ? $return : implode(', ', $return);
}

/**
* 根据 SQL 语句和提供的参数数组,生成最终的 SQL 语句
*
* @param CoreDb $dbo
* @param string $sql
* @param array $inputarr
*
* @return string
*/
static function bind(CoreDb $dbo, $sql, & $inputarr)
{
$arr = explode('?', $sql);
$sql = array_shift($arr);
foreach ($inputarr as $value) {
if (isset($arr[0])) {
$sql .= $dbo->qstr($value) . array_shift($arr);
}
}
return $sql;
}

/**
* 根据包含记录内容的数组返回一条有效的 SQL 插入记录语句
*
* @param array $row
* @param string $table 要插入的数据表
* @param string $schema
*
* @return string
*/
static function getInsertSQL(& $row, $table, $schema = null)
{
list($holders, $values) = self::getPlaceholder($row);
$holders = implode(',', $holders);
$fields = self::qfields(array_keys($values));
$table = self::qtable($table, $schema);
$sql = "INSERT INTO {$table} ({$fields}) VALUES ({$holders})";
return $sql;
}

/**
* 根据包含记录内容的数组返回一条有效的 SQL 更新记录语句
*
* @param CoreDb $dbo
* @param array $row
* @param array $pk 表主键字段
* @param string $table 要插入的数据表
* @param string $schema
*
* @return string
*/
static function getUpdateSQL(CoreDb $dbo, & $row, $pk, $table, $schema = null)
{
$pkv = $row[$pk];
unset($row[$pk]);
list($pairs, $values) = self::getPlaceholderPair($dbo,$row);
$row[$pk] = $pkv;
$pairs = implode(',', $pairs);
$table = self::qtable($table, $schema);
$pk = self::qfield($pk);
$sql = "UPDATE {$table} SET {$pairs} WHERE {$pk} = " . $dbo->qstr($pkv);
return $sql;
}

/**
* 根据参数占位符样式,返回包含参数占位符及有效数据的数组
*
* @param array $inputarr
* @param array $fields
*
* @return array
*/
static function getPlaceholder(& $inputarr, $fields = null)
{
$holders = array();
$values = array();
if (is_array($fields)) {
$fields = array_change_key_case(array_flip($fields), CASE_LOWER);
foreach (array_keys($inputarr) as $key) {
if (!isset($fields[strtolower($key)])) { continue; }
$holders[] = '?';
$values[$key] =& $inputarr[$key];
}
} else {
foreach (array_keys($inputarr) as $key) {
$holders[] = '?';
$values[$key] =& $inputarr[$key];
}
}
return array($holders, $values);
}

/**
* 根据驱动的参数占位符样式,返回包含参数及占位符字符串对、有效数据的数组
*
* @param CoreDb $dbo
* @param array $inputarr
* @param array $fields
*
* @return array
*/
static function getPlaceholderPair(CoreDb $dbo, & $inputarr, $fields = null)
{
$pairs = array();
$values = array();
if (is_array($fields)) {
$fields = array_change_key_case(array_flip($fields), CASE_LOWER);
foreach (array_keys($inputarr) as $key) {
if (!isset($fields[strtolower($key)])) { continue; }
$qkey = $this->qfield($key);
$pairs[] = "{$qkey}=?";
$values[$key] =& $inputarr[$key];
}
} else {
foreach (array_keys($inputarr) as $key) {
$qkey = $this->qfield($key);
$pairs[] = "{$qkey}=?";
$values[$key] =& $inputarr[$key];
}
}
return array($pairs, $values);
}
}

 代码例子:

 

$dbo = CoreDB::instance(App::ini('_dsn/default'));
$dbo->connect();
//
//		$sqlCond = SqlHelper::parseConditions(array(
//			'name' => 'asfdfds',
//			'id' => array(array(123),'IN','OR'),
//			'role.name' => array('%ha%','Like')
//		),$dbo);

$row = array(
'name' => 'asfdfds',
'id' => 112.5
);
$sqlCond = CoreDbSqlHelper::getInsertSQL($row,'users');
$sqlCond = CoreDbSqlHelper::bind($dbo,$sqlCond,$row);

dump($dbo->getCol('show tables'),$sqlCond);
dump($dbo->getDbUtils()->metaTables(),'metaTables');
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: