initial commit

This commit is contained in:
whale
2020-03-02 16:14:20 +08:00
parent 517082d159
commit 769b87af6a
132 changed files with 5424 additions and 2866 deletions

120
src/ZM/DB/DB.php Normal file
View File

@@ -0,0 +1,120 @@
<?php
namespace ZM\DB;
use framework\Console;
use framework\ZMBuf;
use Swoole\Coroutine;
use Swoole\Coroutine\MySQL\Statement;
use ZM\Exception\DbException;
class DB
{
private static $table_list = [];
public static function initTableList() {
$result = self::rawQuery("select TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='" . ZMBuf::globals("sql_config")["sql_database"] . "';", []);
foreach ($result as $v) {
self::$table_list[] = $v['TABLE_NAME'];
}
}
/**
* @param $table_name
* @param bool $enable_cache
* @return Table
* @throws DbException
*/
public static function table($table_name, $enable_cache = null) {
if (Table::getTableInstance($table_name) === null) {
if (in_array($table_name, self::$table_list))
return new Table($table_name, $enable_cache ?? ZMBuf::globals("sql_config")["sql_enable_cache"]);
elseif(ZMBuf::$sql_pool !== null){
throw new DbException("Table " . $table_name . " not exist in database.");
} else {
throw new DbException("Database connection not exist or connect failed. Please check sql configuration");
}
}
return Table::getTableInstance($table_name);
}
public static function statement($line) {
self::rawQuery($line, []);
}
public static function unprepared($line) {
if (ZMBuf::get("sql_log") === true) {
$starttime = microtime(true);
}
try {
$conn = ZMBuf::$sql_pool->get();
if ($conn === false) {
throw new DbException("无法连接SQL" . $line);
}
$result = $conn->query($line) === false ? false : ($conn->errno != 0 ? false : true);
ZMBuf::$sql_pool->put($conn);
return $result;
} catch (DBException $e) {
if (ZMBuf::get("sql_log") === true) {
$log =
"[" . date("Y-m-d H:i:s") .
" " . round(microtime(true) - $starttime, 5) .
"] " . $line . " (Error:" . $e->getMessage() . ")\n";
Coroutine::writeFile(CRASH_DIR . "sql.log", $log, FILE_APPEND);
}
Console::error($e->getMessage());
return false;
}
}
public static function rawQuery(string $line, $params) {
if (ZMBuf::get("sql_log") === true) {
$starttime = microtime(true);
}
try {
$conn = ZMBuf::$sql_pool->get();
if ($conn === false) {
throw new DbException("无法连接SQL" . $line);
}
$ps = $conn->prepare($line);
if ($ps === false) {
$conn->close();
ZMBuf::$sql_pool->connect_cnt -= 1;
throw new DbException("SQL语句查询错误" . $line . ",错误信息:" . $conn->error);
} else {
if (!($ps instanceof Statement)) {
throw new DbException("语句查询错误!" . $line);
}
if ($params == []) $result = $ps->execute();
elseif (!is_array($params)) {
$result = $ps->execute([$params]);
} else $result = $ps->execute($params);
ZMBuf::$sql_pool->put($conn);
if ($ps->errno != 0) {
throw new DBException("语句[$line]错误!" . $ps->error);
//echo json_encode(debug_backtrace(), 128 | 256);
}
if (ZMBuf::get("sql_log") === true) {
$log =
"[" . date("Y-m-d H:i:s") .
" " . round(microtime(true) - $starttime, 4) .
"] " . $line . " " . json_encode($params, JSON_UNESCAPED_UNICODE) . "\n";
Coroutine::writeFile(CRASH_DIR . "sql.log", $log, FILE_APPEND);
}
return $result;
}
} catch (DBException $e) {
if (ZMBuf::get("sql_log") === true) {
$log =
"[" . date("Y-m-d H:i:s") .
" " . round(microtime(true) - $starttime, 4) .
"] " . $line . " " . json_encode($params, JSON_UNESCAPED_UNICODE) . " (Error:" . $e->getMessage() . ")\n";
Coroutine::writeFile(CRASH_DIR . "sql.log", $log, FILE_APPEND);
}
Console::error($e->getMessage());
return false;
}
}
}

28
src/ZM/DB/DeleteBody.php Normal file
View File

@@ -0,0 +1,28 @@
<?php
namespace ZM\DB;
class DeleteBody
{
use WhereBody;
/**
* @var Table
*/
private $table;
/**
* DeleteBody constructor.
* @param Table $table
*/
public function __construct(Table $table) {
$this->table = $table;
}
public function save() {
list($sql, $param) = $this->getWhereSQL();
return DB::rawQuery("DELETE FROM " . $this->table->getTableName() . " WHERE " . $sql, $param);
}
}

28
src/ZM/DB/InsertBody.php Normal file
View File

@@ -0,0 +1,28 @@
<?php
namespace ZM\DB;
class InsertBody
{
/**
* @var Table
*/
private $table;
private $row;
/**
* InsertBody constructor.
* @param Table $table
* @param $row
*/
public function __construct(Table $table, $row) {
$this->table = $table;
$this->row = $row;
}
public function save() {
DB::rawQuery('INSERT INTO ' . $this->table->getTableName() . ' VALUES ('.implode(',', array_fill(0, 5, '?')).')', $this->row);
}
}

88
src/ZM/DB/SelectBody.php Normal file
View File

@@ -0,0 +1,88 @@
<?php
namespace ZM\DB;
use Framework\Console;
class SelectBody
{
use WhereBody;
/** @var Table */
private $table;
private $select_thing;
private $result = null;
public function __construct($table, $select_thing) {
$this->table = $table;
$this->select_thing = $select_thing;
}
public function get() { return $this->fetchAll(); }
public function fetchAll() {
if ($this->table->isCacheEnabled()) {
$rr = md5(implode(",", $this->select_thing) . serialize($this->where_thing));
if (array_key_exists($rr, $this->table->cache)) {
Console::info('SQL query cached: ' . $rr, date("[H:i:s ") . 'DB] ');
return $this->table->cache[$rr]->getResult();
}
}
$this->execute();
if ($this->table->isCacheEnabled() && !in_array($rr, $this->table->cache)) {
$this->table->cache[$rr] = $this;
}
return $this->getResult();
}
public function fetchFirst() {
return $this->fetchAll()[0] ?? null;
}
public function value() {
$r = $this->fetchFirst();
if ($r === null) return null;
return current($r);
}
public function execute() {
$str = $this->queryPrepare();
$this->result = DB::rawQuery($str[0], $str[1]);
}
public function getResult() { return $this->result; }
public function equals(SelectBody $body) {
if ($this->select_thing != $body->getSelectThing()) return false;
elseif ($this->where_thing == $body->getWhereThing()) return false;
else return true;
}
/**
* @return mixed
*/
public function getSelectThing() { return $this->select_thing; }
/**
* @return array
*/
public function getWhereThing() { return $this->where_thing; }
private function queryPrepare() {
$msg = "SELECT " . implode(", ", $this->select_thing) . " FROM " . $this->table->getTableName();
$sql = $this->table->paintWhereSQL($this->where_thing['='] ?? [], '=');
if ($sql[0] != '') {
$msg .= " WHERE " . $sql[0];
$array = $sql[1];
$sql = $this->table->paintWhereSQL($this->where_thing['!='] ?? [], '!=');
if ($sql[0] != '') $msg .= " AND " . $sql[0];
$array = array_merge($array, $sql[1]);
}
return [$msg, $array ?? []];
}
}

79
src/ZM/DB/Table.php Normal file
View File

@@ -0,0 +1,79 @@
<?php
namespace ZM\DB;
class Table
{
private $table_name;
/** @var SelectBody[] */
public $cache = [];
private static $table_instance = [];
private $enable_cache;
public function __construct($table_name, $enable_cache) {
$this->enable_cache = $enable_cache;
$this->table_name = $table_name;
self::$table_instance[$table_name] = $this;
}
public static function getTableInstance($table_name) {
if (isset(self::$table_instance[$table_name])) return self::$table_instance[$table_name];
else return null;
}
public function select($what = []) {
return new SelectBody($this, $what == [] ? ["*"] : $what);
}
public function where($column, $operation_or_value, $value = null){
return (new SelectBody($this, ["*"]))->where($column, $operation_or_value, $value);
}
public function insert($row) {
$this->cache = [];
return new InsertBody($this, $row);
}
public function update(array $set_value) {
$this->cache = [];
return new UpdateBody($this, $set_value);
}
public function delete() {
$this->cache = [];
return new DeleteBody($this);
}
public function statement($line){
$this->cache = [];
//TODO: 无返回的statement语句
}
public function paintWhereSQL($rule, $operator) {
if ($rule == []) return ["", []];
$msg = "";
$param = [];
foreach ($rule as $k => $v) {
if ($msg == "") {
$msg .= $k . " $operator ? ";
} else {
$msg .= "AND " . $k . " $operator ?";
}
$param[] = $v;
}
return [$msg, $param];
}
/**
* @return mixed
*/
public function getTableName() { return $this->table_name; }
public function isCacheEnabled() { return $this->enable_cache; }
}

50
src/ZM/DB/UpdateBody.php Normal file
View File

@@ -0,0 +1,50 @@
<?php
namespace ZM\DB;
use ZM\Exception\DbException;
class UpdateBody
{
use WhereBody;
/**
* @var Table
*/
private $table;
/**
* @var array
*/
private $set_value;
/**
* UpdateBody constructor.
* @param Table $table
* @param array $set_value
*/
public function __construct(Table $table, array $set_value) {
$this->table = $table;
$this->set_value = $set_value;
}
/**
* @throws DbException
*/
public function save(){
$arr = [];
$msg = [];
foreach($this->set_value as $k => $v) {
$msg []= $k .' = ?';
$arr[]=$v;
}
if(($msg ?? []) == []) throw new DbException('update value sets can not be empty!');
$line = 'UPDATE '.$this->table->getTableName().' SET '.implode(', ', $msg);
if($this->where_thing != []) {
list($sql, $param) = $this->getWhereSQL();
$arr = array_merge($arr, $param);
$line .= ' WHERE '.$sql;
}
return DB::rawQuery($line, $arr);
}
}

33
src/ZM/DB/WhereBody.php Normal file
View File

@@ -0,0 +1,33 @@
<?php
namespace ZM\DB;
trait WhereBody
{
protected $where_thing = [];
public function where($column, $operation_or_value, $value = null) {
if (!in_array($operation_or_value, ['=', '!='])) $this->where_thing['='][$column] = $operation_or_value;
elseif ($value !== null) $this->where_thing[$operation_or_value][$column] = $value;
else $this->where_thing['='][$column] = $operation_or_value;
return $this;
}
protected function getWhereSQL(){
$param = [];
$msg = '';
foreach($this->where_thing as $k => $v) {
foreach($v as $ks => $vs) {
if($param != []) {
$msg .= ' AND '.$ks ." $k ?";
} else {
$msg .= "$ks $k ?";
}
$param []=$vs;
}
}
return [$msg, $param];
}
}