Initial project files: BESCMS full source
This commit is contained in:
@@ -0,0 +1,986 @@
|
||||
<?php namespace Phpcmf\Model;
|
||||
/**
|
||||
* https://www.besyun.com
|
||||
* BESCMS
|
||||
* 本文件是框架系统文件,二次开发时不可以修改本文件,可以通过继承类方法来重写此文件
|
||||
**/
|
||||
|
||||
|
||||
// 数据表(DDL 优先驱动;未实现时按 MySQL 源方言兼容,经 formatCreateSql 转换)
|
||||
class Table extends \Phpcmf\Model {
|
||||
|
||||
/**
|
||||
* MySQL 源方言标识符加反引号(供 formatCreateSql 转换)
|
||||
*
|
||||
* @param string $id
|
||||
* @return string
|
||||
*/
|
||||
protected function _mysql_qi($id) {
|
||||
return '`'.str_replace('`', '``', $this->unquote_id((string) $id)).'`';
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行 MySQL 源 DDL(_query_batch → dr_format_create_sql)
|
||||
*
|
||||
* @param string $sql
|
||||
* @return bool
|
||||
*/
|
||||
protected function _ddl_exec_mysql($sql) {
|
||||
|
||||
$sql = trim((string) $sql);
|
||||
if ($sql === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$rt = $this->_query_batch($sql);
|
||||
if (!empty($rt['code'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
log_message('error', 'DDL compat: '.($rt['msg'] ?? $sql));
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改字段(优先驱动 editField)
|
||||
*
|
||||
* @param string $table
|
||||
* @param string $name
|
||||
* @param string $type
|
||||
* @param string $info
|
||||
* @param string $note
|
||||
* @return mixed
|
||||
*/
|
||||
public function edit_field($table, $name, $type, $info, $note) {
|
||||
|
||||
if (method_exists($this->db, 'editField')) {
|
||||
return $this->db->editField($table, $name, $type, $info, $note);
|
||||
}
|
||||
|
||||
return $this->_edit_field_compat($table, $name, $type, $info, $note);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
* @param string $name
|
||||
* @param string $type
|
||||
* @param string $info
|
||||
* @param string $note
|
||||
* @return bool
|
||||
*/
|
||||
protected function _edit_field_compat($table, $name, $type, $info, $note) {
|
||||
|
||||
$table = $this->unquote_id((string) $table);
|
||||
$name = $this->unquote_id((string) $name);
|
||||
if ($table === '' || $name === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$qi = $this->_mysql_qi($name);
|
||||
$sql = 'ALTER TABLE '.$this->_mysql_qi($table).' CHANGE '.$qi.' '.$qi
|
||||
.' '.$type.' '.$info;
|
||||
$note = (string) $note;
|
||||
if ($note !== '') {
|
||||
$sql .= " COMMENT '".str_replace("'", "''", $note)."'";
|
||||
}
|
||||
|
||||
return $this->_ddl_exec_mysql($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加字段(优先驱动 addField)
|
||||
*
|
||||
* @param string $table
|
||||
* @param string $name
|
||||
* @param string $type
|
||||
* @param string $info
|
||||
* @param string $note
|
||||
* @return mixed
|
||||
*/
|
||||
public function add_field($table, $name, $type, $info, $note) {
|
||||
|
||||
if (method_exists($this->db, 'addField')) {
|
||||
return $this->db->addField($table, $name, $type, $info, $note);
|
||||
}
|
||||
|
||||
return $this->_add_field_compat($table, $name, $type, $info, $note);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
* @param string $name
|
||||
* @param string $type
|
||||
* @param string $info
|
||||
* @param string $note
|
||||
* @return bool
|
||||
*/
|
||||
protected function _add_field_compat($table, $name, $type, $info, $note) {
|
||||
|
||||
$table = $this->unquote_id((string) $table);
|
||||
$name = $this->unquote_id((string) $name);
|
||||
if ($table === '' || $name === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sql = 'ALTER TABLE '.$this->_mysql_qi($table).' ADD '.$this->_mysql_qi($name)
|
||||
.' '.$type.' '.$info;
|
||||
$note = (string) $note;
|
||||
if ($note !== '') {
|
||||
$sql .= " COMMENT '".str_replace("'", "''", $note)."'";
|
||||
}
|
||||
|
||||
return $this->_ddl_exec_mysql($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除字段(优先驱动 dropField)
|
||||
*
|
||||
* @param string $table
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function drop_field($table, $name) {
|
||||
|
||||
if (method_exists($this->db, 'dropField')) {
|
||||
return $this->db->dropField($table, $name);
|
||||
}
|
||||
|
||||
return $this->_drop_field_compat($table, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
protected function _drop_field_compat($table, $name) {
|
||||
|
||||
$table = $this->unquote_id((string) $table);
|
||||
$name = $this->unquote_id((string) $name);
|
||||
if ($table === '' || $name === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->_ddl_exec_mysql(
|
||||
'ALTER TABLE '.$this->_mysql_qi($table).' DROP '.$this->_mysql_qi($name)
|
||||
);
|
||||
}
|
||||
|
||||
// 根据配置创建字段(字段类 create_sql 经驱动 sqlAddField 生成)
|
||||
public function create_field($table, $config) {
|
||||
|
||||
if (!$config || !$table) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tablename = $this->dbprefix($table);
|
||||
foreach ($config as $field) {
|
||||
|
||||
if ($this->db->fieldExists($field['fieldname'], $tablename)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$obj = \Phpcmf\Service::L('field')->get($field['fieldtype']);
|
||||
if (!$obj) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sql = $obj->create_sql($field['fieldname'], $field['setting']['option'], dr_safe_filename($field['name']));
|
||||
if (!$sql) {
|
||||
continue;
|
||||
}
|
||||
// create_sql 为 MySQL 源(含 {tablename}),走兼容执行
|
||||
$sql = str_replace('{tablename}', $this->unquote_id($tablename), $sql);
|
||||
$this->_ddl_exec_mysql($sql);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建表(优先驱动 createTable;未实现时拼 MySQL 源 SQL 经 formatCreateSql 兼容执行)
|
||||
*
|
||||
* @param string $table 表名(可含前缀)
|
||||
* @param array $fields ['字段名'=>'类型属性'] 或 [0=>'完整列定义']
|
||||
* @param array $indexs ['PRIMARY KEY (`id`)', 'KEY `name` (`name`)', ...]
|
||||
* @param string $note 表注释
|
||||
* @return array
|
||||
*/
|
||||
public function create_table($table, $fields, $indexs, $note) {
|
||||
|
||||
try {
|
||||
if (method_exists($this->db, 'createTable')) {
|
||||
$rt = $this->db->createTable($table, $fields, $indexs, $note);
|
||||
if ($rt === false) {
|
||||
$error = $this->db->error();
|
||||
return dr_return_data(0, $error['message'] ?? 'createTable failed');
|
||||
}
|
||||
return dr_return_data(1);
|
||||
}
|
||||
return $this->_create_table_compat($table, $fields, $indexs, $note);
|
||||
} catch (\Throwable $e) {
|
||||
log_message('error', 'createTable: '.$e->getMessage());
|
||||
return dr_return_data(0, $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 驱动未实现 createTable 时的兼容建表
|
||||
*
|
||||
* @param string $table
|
||||
* @param array $fields
|
||||
* @param array $indexs
|
||||
* @param string $note
|
||||
* @return array
|
||||
*/
|
||||
protected function _create_table_compat($table, $fields, $indexs, $note) {
|
||||
|
||||
$table = $this->unquote_id((string) $table);
|
||||
if ($table === '' || !is_array($fields) || !$fields) {
|
||||
return dr_return_data(0, 'createTable 参数无效');
|
||||
}
|
||||
|
||||
$lines = [];
|
||||
foreach ($fields as $name => $def) {
|
||||
if (is_int($name)) {
|
||||
$lines[] = (string) $def;
|
||||
} else {
|
||||
$lines[] = $this->_mysql_qi($name).' '.(string) $def;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($indexs)) {
|
||||
foreach ($indexs as $idx) {
|
||||
$idx = trim((string) $idx);
|
||||
if ($idx !== '') {
|
||||
$lines[] = $idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$lines) {
|
||||
return dr_return_data(0, 'createTable 无字段定义');
|
||||
}
|
||||
|
||||
$sql = 'CREATE TABLE IF NOT EXISTS '.$this->_mysql_qi($table).' (
|
||||
'.implode(",\n", $lines).'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT=\''
|
||||
.str_replace("'", "''", (string) $note).'\'';
|
||||
|
||||
$rt = $this->_query_batch($sql);
|
||||
if (empty($rt['code'])) {
|
||||
return dr_return_data(0, $rt['msg'] ?? 'createTable compat failed');
|
||||
}
|
||||
|
||||
return dr_return_data(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除表(优先驱动 dropTable;未实现时走兼容 SQL)
|
||||
*
|
||||
* @param string $table
|
||||
* @param bool $ifExists
|
||||
* @return array
|
||||
*/
|
||||
public function drop_table($table, $ifExists = true) {
|
||||
|
||||
try {
|
||||
if (method_exists($this->db, 'dropTable')) {
|
||||
$rt = $this->db->dropTable($table, $ifExists);
|
||||
} else {
|
||||
$rt = $this->_drop_table_compat($table, $ifExists);
|
||||
}
|
||||
if ($rt === false) {
|
||||
$error = $this->db->error();
|
||||
return dr_return_data(0, $error['message'] ?? 'dropTable failed');
|
||||
}
|
||||
return dr_return_data(1);
|
||||
} catch (\Throwable $e) {
|
||||
log_message('error', 'dropTable: '.$e->getMessage());
|
||||
return dr_return_data(0, $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 驱动未实现 dropTable 时的兼容删除
|
||||
*
|
||||
* @param string $table
|
||||
* @param bool $ifExists
|
||||
* @return bool
|
||||
*/
|
||||
protected function _drop_table_compat($table, $ifExists = true) {
|
||||
|
||||
$table = $this->unquote_id((string) $table);
|
||||
if ($table === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($ifExists && method_exists($this->db, 'tableExists') && !$this->db->tableExists($table)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$sql = ($ifExists ? 'DROP TABLE IF EXISTS ' : 'DROP TABLE ').$this->_mysql_qi($table);
|
||||
if ($this->_ddl_exec_mysql($sql)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// IF EXISTS 不被支持时退化
|
||||
if ($ifExists) {
|
||||
return $this->_ddl_exec_mysql('DROP TABLE '.$this->_mysql_qi($table));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 Schema 安装表结构与种子数据(Config/Install.php)
|
||||
*
|
||||
* @param array $schema ['tables'=>[name=>['fields','indexes','comment','drop']], 'seeds'=>[['table','data']]]
|
||||
* @return array
|
||||
*/
|
||||
public function install_schema(array $schema) {
|
||||
|
||||
$tables = isset($schema['tables']) && is_array($schema['tables']) ? $schema['tables'] : [];
|
||||
$seeds = isset($schema['seeds']) && is_array($schema['seeds']) ? $schema['seeds'] : [];
|
||||
|
||||
foreach ($tables as $name => $def) {
|
||||
if (!$name || !is_array($def) || empty($def['fields'])) {
|
||||
continue;
|
||||
}
|
||||
$table = $this->dbprefix($name);
|
||||
if (!empty($def['drop'])) {
|
||||
$rt = $this->drop_table($table, true);
|
||||
if (!$rt['code']) {
|
||||
return $rt;
|
||||
}
|
||||
}
|
||||
$rt = $this->create_table(
|
||||
$table,
|
||||
$def['fields'],
|
||||
isset($def['indexes']) ? $def['indexes'] : [],
|
||||
isset($def['comment']) ? $def['comment'] : ''
|
||||
);
|
||||
if (!$rt['code']) {
|
||||
return dr_return_data(0, dr_lang('创建表失败(%s):%s', $table, $rt['msg']));
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($seeds as $seed) {
|
||||
if (empty($seed['table']) || empty($seed['data']) || !is_array($seed['data'])) {
|
||||
continue;
|
||||
}
|
||||
$rt = \Phpcmf\Service::M()->table($seed['table'])->replace($seed['data']);
|
||||
if (is_array($rt) && isset($rt['code']) && !$rt['code']) {
|
||||
return dr_return_data(0, dr_lang('写入初始数据失败(%s):%s', $seed['table'], $rt['msg']));
|
||||
}
|
||||
}
|
||||
|
||||
return dr_return_data(1, '', ['tables' => dr_count($tables), 'seeds' => dr_count($seeds)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取建表 SQL(优先驱动 createTableSql)
|
||||
*
|
||||
* @param string $table
|
||||
* @return array [createSql, fieldFragments, table]
|
||||
*/
|
||||
public function create_table_sql($table) {
|
||||
|
||||
if (method_exists($this->db, 'createTableSql')) {
|
||||
$create = $this->db->createTableSql($table);
|
||||
} else {
|
||||
$create = $this->_create_table_sql_compat($table);
|
||||
}
|
||||
|
||||
if (!$create) {
|
||||
return ['', [], $table];
|
||||
}
|
||||
|
||||
$char = '`';
|
||||
if (isset($this->db->escapeChar) && is_string($this->db->escapeChar) && $this->db->escapeChar !== '') {
|
||||
$char = $this->db->escapeChar;
|
||||
}
|
||||
$quote = preg_quote($char, '/');
|
||||
|
||||
$arr = explode(PHP_EOL, $create);
|
||||
$sql = [];
|
||||
foreach ($arr as $t) {
|
||||
if (preg_match('/'.$quote.'(.+)'.$quote.'/U', $t, $mt)
|
||||
&& strpos($t, ' KEY ') === false
|
||||
&& strpos($t, $char.$this->dbprefix()) === false
|
||||
) {
|
||||
$sql[$mt[1]] = trim($t, ',');
|
||||
}
|
||||
}
|
||||
|
||||
return [$create, $sql, $table];
|
||||
}
|
||||
|
||||
/**
|
||||
* 驱动未实现 createTableSql:先试 SHOW CREATE TABLE,再按字段元数据拼装
|
||||
*
|
||||
* @param string $table
|
||||
* @return string
|
||||
*/
|
||||
protected function _create_table_sql_compat($table) {
|
||||
|
||||
$table = $this->unquote_id((string) $table);
|
||||
if ($table === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
try {
|
||||
$query = $this->db->query('SHOW CREATE TABLE '.$this->_mysql_qi($table));
|
||||
$row = $query ? $query->getRowArray() : null;
|
||||
if ($row) {
|
||||
foreach ($row as $k => $v) {
|
||||
if (stripos((string) $k, 'create') !== false && $v) {
|
||||
return str_replace('CREATE TABLE', 'CREATE TABLE IF NOT EXISTS', (string) $v);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// 非 MySQL 忽略
|
||||
}
|
||||
|
||||
if (!method_exists($this->db, 'getFieldData')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$fds = $this->db->getFieldData($table);
|
||||
if (!$fds) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$lines = [];
|
||||
$pk = [];
|
||||
foreach ($fds as $f) {
|
||||
$name = isset($f->name) ? $f->name : '';
|
||||
if ($name === '') {
|
||||
continue;
|
||||
}
|
||||
$type = isset($f->type) ? $f->type : 'TEXT';
|
||||
if (!empty($f->max_length) && !preg_match('/\(/', $type)
|
||||
&& !preg_match('/(TEXT|BLOB|DATE|TIME|INT|FLOAT|DOUBLE|REAL|BOOL)/i', $type)
|
||||
) {
|
||||
$type .= '('.$f->max_length.')';
|
||||
}
|
||||
$null = (isset($f->nullable) ? $f->nullable : true) ? 'NULL' : 'NOT NULL';
|
||||
$def = '';
|
||||
if (isset($f->default) && $f->default !== null) {
|
||||
$def = " DEFAULT '".str_replace("'", "''", (string) $f->default)."'";
|
||||
}
|
||||
$extra = '';
|
||||
if (!empty($f->primary_key)) {
|
||||
$pk[] = $this->_mysql_qi($name);
|
||||
}
|
||||
if (!empty($f->auto_increment)) {
|
||||
$extra = ' AUTO_INCREMENT';
|
||||
}
|
||||
$lines[] = $this->_mysql_qi($name).' '.$type.' '.$null.$def.$extra;
|
||||
}
|
||||
if ($pk) {
|
||||
$lines[] = 'PRIMARY KEY ('.implode(',', $pk).')';
|
||||
}
|
||||
|
||||
return 'CREATE TABLE IF NOT EXISTS '.$this->_mysql_qi($table).' (
|
||||
'.implode(",\n", $lines).'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci';
|
||||
}
|
||||
|
||||
/**
|
||||
* 从表结构导出规范化 Schema(fields / indexes / comment)
|
||||
* 供 Dever 导出 Config/Content.php、Form.php 等使用
|
||||
*/
|
||||
public function create_table_schema($table) {
|
||||
|
||||
list($create) = $this->create_table_sql($table);
|
||||
if (!$create) {
|
||||
return [
|
||||
'comment' => '',
|
||||
'fields' => [],
|
||||
'indexes' => [],
|
||||
];
|
||||
}
|
||||
|
||||
$comment = '';
|
||||
if (preg_match("/COMMENT='([^']*)'/", $create, $cm)) {
|
||||
$comment = $cm[1];
|
||||
} elseif (preg_match('/COMMENT="([^"]*)"/', $create, $cm)) {
|
||||
$comment = $cm[1];
|
||||
}
|
||||
|
||||
$inner = $create;
|
||||
if (preg_match('/\((.*)\)\s*ENGINE/is', $create, $m)) {
|
||||
$inner = $m[1];
|
||||
}
|
||||
|
||||
$fields = [];
|
||||
$indexes = [];
|
||||
$parts = preg_split("/,\s*\n/", trim($inner));
|
||||
if (dr_count($parts) < 2) {
|
||||
$parts = [];
|
||||
$buf = '';
|
||||
$depth = 0;
|
||||
$len = strlen($inner);
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
$ch = $inner[$i];
|
||||
if ($ch === '(') {
|
||||
$depth++;
|
||||
$buf .= $ch;
|
||||
} elseif ($ch === ')') {
|
||||
$depth = max(0, $depth - 1);
|
||||
$buf .= $ch;
|
||||
} elseif ($ch === ',' && $depth === 0) {
|
||||
$parts[] = trim($buf);
|
||||
$buf = '';
|
||||
} else {
|
||||
$buf .= $ch;
|
||||
}
|
||||
}
|
||||
if (trim($buf) !== '') {
|
||||
$parts[] = trim($buf);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($parts as $line) {
|
||||
$line = trim($line);
|
||||
$line = rtrim($line, ',');
|
||||
if ($line === '') {
|
||||
continue;
|
||||
}
|
||||
if (preg_match('/^(PRIMARY KEY|UNIQUE KEY|KEY|FULLTEXT KEY)\s/i', $line)) {
|
||||
$indexes[] = $line;
|
||||
continue;
|
||||
}
|
||||
if (preg_match('/^`([^`]+)`\s+(.+)$/s', $line, $fm)) {
|
||||
$fields[$fm[1]] = trim($fm[2]);
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'comment' => $comment,
|
||||
'fields' => $fields,
|
||||
'indexes' => $indexes,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 表完整字段信息(优先驱动 showFullColunms)
|
||||
*
|
||||
* @param string $table
|
||||
* @return array
|
||||
*/
|
||||
public function show_full_colunms($table) {
|
||||
|
||||
if (method_exists($this->db, 'showFullColunms')) {
|
||||
return $this->db->showFullColunms($table);
|
||||
}
|
||||
|
||||
return $this->_show_full_colunms_compat($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
* @return array
|
||||
*/
|
||||
protected function _show_full_colunms_compat($table) {
|
||||
|
||||
$table = $this->unquote_id((string) $table);
|
||||
if ($table === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
$query = $this->db->query('SHOW FULL COLUMNS FROM '.$this->_mysql_qi($table));
|
||||
if ($query) {
|
||||
$rows = $query->getResultArray();
|
||||
if ($rows) {
|
||||
return $rows;
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// 非 MySQL
|
||||
}
|
||||
|
||||
if (!method_exists($this->db, 'getFieldData')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$out = [];
|
||||
foreach ($this->db->getFieldData($table) as $f) {
|
||||
$out[] = [
|
||||
'Field' => isset($f->name) ? $f->name : '',
|
||||
'Type' => isset($f->type) ? $f->type : '',
|
||||
'Collation' => null,
|
||||
'Null' => (isset($f->nullable) && !$f->nullable) ? 'NO' : 'YES',
|
||||
'Key' => !empty($f->primary_key) ? 'PRI' : '',
|
||||
'Default' => isset($f->default) ? $f->default : null,
|
||||
'Extra' => !empty($f->auto_increment) ? 'auto_increment' : '',
|
||||
'Privileges' => '',
|
||||
'Comment' => '',
|
||||
];
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* 全部表状态(优先驱动 showTableStatus)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function show_table_status() {
|
||||
|
||||
if (method_exists($this->db, 'showTableStatus')) {
|
||||
return $this->db->showTableStatus();
|
||||
}
|
||||
|
||||
return $this->_show_table_status_compat();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function _show_table_status_compat() {
|
||||
|
||||
try {
|
||||
$query = $this->db->query('SHOW TABLE STATUS');
|
||||
if ($query) {
|
||||
$rows = $query->getResultArray();
|
||||
if ($rows) {
|
||||
return $rows;
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// 非 MySQL
|
||||
}
|
||||
|
||||
$out = [];
|
||||
if (method_exists($this->db, 'listTables')) {
|
||||
foreach ($this->db->listTables() as $name) {
|
||||
$out[] = [
|
||||
'Name' => $name,
|
||||
'Engine' => '',
|
||||
'Version' => '',
|
||||
'Row_format' => '',
|
||||
'Rows' => 0,
|
||||
'Avg_row_length' => 0,
|
||||
'Data_length' => 0,
|
||||
'Max_data_length' => 0,
|
||||
'Index_length' => 0,
|
||||
'Data_free' => 0,
|
||||
'Auto_increment' => null,
|
||||
'Create_time' => null,
|
||||
'Update_time' => null,
|
||||
'Check_time' => null,
|
||||
'Collation' => '',
|
||||
'Checksum' => null,
|
||||
'Create_options' => '',
|
||||
'Comment' => '',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修复表(优先驱动;兼容执行 MySQL REPAIR TABLE,失败则视为跳过成功)
|
||||
*
|
||||
* @param string $table
|
||||
* @return mixed
|
||||
*/
|
||||
public function repair_table($table) {
|
||||
|
||||
if (method_exists($this->db, 'repairTable')) {
|
||||
return $this->db->repairTable($table);
|
||||
}
|
||||
|
||||
return $this->_maintenance_table_compat('REPAIR TABLE', $table);
|
||||
}
|
||||
|
||||
/**
|
||||
* 优化表
|
||||
*
|
||||
* @param string $table
|
||||
* @return mixed
|
||||
*/
|
||||
public function optimize_table($table) {
|
||||
|
||||
if (method_exists($this->db, 'optimizeTable')) {
|
||||
return $this->db->optimizeTable($table);
|
||||
}
|
||||
|
||||
return $this->_maintenance_table_compat('OPTIMIZE TABLE', $table);
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新表
|
||||
*
|
||||
* @param string $table
|
||||
* @return mixed
|
||||
*/
|
||||
public function flush_table($table) {
|
||||
|
||||
if (method_exists($this->db, 'flushTable')) {
|
||||
return $this->db->flushTable($table);
|
||||
}
|
||||
|
||||
return $this->_maintenance_table_compat('FLUSH TABLE', $table);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查表
|
||||
*
|
||||
* @param string $table
|
||||
* @return array
|
||||
*/
|
||||
public function check_table($table) {
|
||||
|
||||
if (method_exists($this->db, 'checkTable')) {
|
||||
return $this->db->checkTable($table);
|
||||
}
|
||||
|
||||
$table = $this->unquote_id((string) $table);
|
||||
if ($table === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
$query = $this->db->query('CHECK TABLE '.$this->_mysql_qi($table));
|
||||
$row = $query ? $query->getRowArray() : null;
|
||||
if ($row) {
|
||||
return $row;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// 非 MySQL:返回通过状态,避免后台报错
|
||||
}
|
||||
|
||||
return ['Msg_text' => 'OK', 'Msg_type' => 'status'];
|
||||
}
|
||||
|
||||
/**
|
||||
* MySQL 维护类语句兼容(不支持的库跳过并返回 true)
|
||||
*
|
||||
* @param string $verb REPAIR TABLE / OPTIMIZE TABLE / FLUSH TABLE
|
||||
* @param string $table
|
||||
* @return bool
|
||||
*/
|
||||
protected function _maintenance_table_compat($verb, $table) {
|
||||
|
||||
$table = $this->unquote_id((string) $table);
|
||||
if ($table === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$rt = $this->db->query($verb.' '.$this->_mysql_qi($table));
|
||||
if ($rt !== false) {
|
||||
return $rt;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改表默认字符集(优先驱动 setTableCharset)
|
||||
*
|
||||
* @param string $table
|
||||
* @param string $charset
|
||||
* @param string $collate
|
||||
* @return mixed
|
||||
*/
|
||||
public function set_table_charset($table, $charset = 'utf8mb4', $collate = 'utf8mb4_unicode_ci') {
|
||||
|
||||
if (method_exists($this->db, 'setTableCharset')) {
|
||||
return $this->db->setTableCharset($table, $charset, $collate);
|
||||
}
|
||||
|
||||
return $this->_set_table_charset_compat($table, $charset, $collate);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
* @param string $charset
|
||||
* @param string $collate
|
||||
* @return bool
|
||||
*/
|
||||
protected function _set_table_charset_compat($table, $charset = 'utf8mb4', $collate = 'utf8mb4_unicode_ci') {
|
||||
|
||||
$table = $this->unquote_id((string) $table);
|
||||
if ($table === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$charset = preg_replace('/[^a-z0-9_]/i', '', (string) $charset);
|
||||
$collate = preg_replace('/[^a-z0-9_]/i', '', (string) $collate);
|
||||
$sql = 'ALTER TABLE '.$this->_mysql_qi($table).' DEFAULT CHARSET='.$charset.' COLLATE '.$collate;
|
||||
|
||||
if ($this->_ddl_exec_mysql($sql)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 不支持字符集的库视为跳过
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建索引(优先驱动;否则 MySQL CREATE INDEX 经 formatCreateSql)
|
||||
*
|
||||
* @param string $table
|
||||
* @param string $name
|
||||
* @param string|array $columns
|
||||
* @return mixed
|
||||
*/
|
||||
public function add_index($table, $name, $columns) {
|
||||
|
||||
$table = $this->unquote_id((string) $table);
|
||||
$name = $this->unquote_id((string) $name);
|
||||
if ($table === '' || $name === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_array($columns)) {
|
||||
$cols = [];
|
||||
foreach ($columns as $c) {
|
||||
$cols[] = $this->_mysql_qi($c);
|
||||
}
|
||||
$colsql = implode(', ', $cols);
|
||||
} else {
|
||||
$colsql = (string) $columns;
|
||||
if (!$this->has_id_quotes($colsql)) {
|
||||
$parts = array_map('trim', explode(',', $colsql));
|
||||
$tmp = [];
|
||||
foreach ($parts as $p) {
|
||||
$p !== '' && $tmp[] = $this->_mysql_qi($p);
|
||||
}
|
||||
$colsql = implode(', ', $tmp);
|
||||
}
|
||||
}
|
||||
|
||||
if (method_exists($this->db, 'addIndex')) {
|
||||
return $this->db->addIndex($table, $name, $columns);
|
||||
}
|
||||
|
||||
return $this->_ddl_exec_mysql(
|
||||
'CREATE INDEX '.$this->_mysql_qi($name).' ON '.$this->_mysql_qi($table).'('.$colsql.')'
|
||||
);
|
||||
}
|
||||
|
||||
// 表结构缓存
|
||||
public function cache($siteid = SITE_ID, $module = null) {
|
||||
|
||||
$cache = [];
|
||||
$paytable = []; // 付款表名 支持模块和表单 后期淘汰
|
||||
// 生成模块表结构
|
||||
if (dr_is_use_module()) {
|
||||
$obj = \Phpcmf\Service::M('module', 'cms');
|
||||
if (method_exists($obj, 'paytable')) {
|
||||
list($cache, $paytable) = $obj->paytable($cache, $paytable, $module, $siteid);
|
||||
}
|
||||
}
|
||||
|
||||
// 网站表单
|
||||
if (dr_is_app('form') && $this->is_table_exists($siteid.'_form')) {
|
||||
$obj = \Phpcmf\Service::M('form', 'form');
|
||||
if (method_exists($obj, 'paytable')) {
|
||||
list($cache, $paytable) = $obj->paytable($cache, $paytable, $siteid);
|
||||
}
|
||||
}
|
||||
|
||||
// 会员表
|
||||
$table = $this->dbprefix('member');
|
||||
$cache[$table] = $this->db->getFieldNames($table);
|
||||
|
||||
// 会员附表
|
||||
$table = $this->dbprefix('member_data');
|
||||
$cache[$table] = $this->db->getFieldNames($table);
|
||||
|
||||
// 缓存表结构
|
||||
\Phpcmf\Service::L('cache')->set_file('table-'.$siteid, $cache);
|
||||
|
||||
// 缓存的字段类型
|
||||
//$type = ['Select', 'Checkbox', 'Radio', 'Pay', 'Pays', 'File', 'Files', 'Image', 'Images', 'Ftable'];
|
||||
$cache = [];
|
||||
$field = $this->db->table('field')->where('disabled', 0)->orderBy('id ASC')->get()->getResultArray();
|
||||
if ($field) {
|
||||
foreach ($field as $f) {
|
||||
$f['setting'] = dr_string2array($f['setting']);
|
||||
$cache[$f['id']] = $f;
|
||||
}
|
||||
}
|
||||
\Phpcmf\Service::L('cache')->set_file('table-field', $cache);
|
||||
|
||||
// 缓存付款表
|
||||
\Phpcmf\Service::L('cache')->set_file('table-pay-'.$siteid, $paytable);
|
||||
/*
|
||||
* $paytable字段主键为 自定义字段rname-rid
|
||||
* */
|
||||
}
|
||||
|
||||
// 获取字段结构
|
||||
public function get_field($table) {
|
||||
return $this->db->getFieldNames($this->dbprefix($table));
|
||||
}
|
||||
|
||||
// 获取缓存的字段结构
|
||||
public function get_cache_field($table) {
|
||||
|
||||
$tableinfo = \Phpcmf\Service::L('cache')->get('table-'.SITE_ID);
|
||||
if (!$tableinfo) {
|
||||
// 没有表结构缓存时返回空
|
||||
return [];
|
||||
}
|
||||
|
||||
return isset($tableinfo[$this->dbprefix($table)]) ? $tableinfo[$this->dbprefix($table)] : [];
|
||||
}
|
||||
|
||||
// 执行批量sql
|
||||
public function _query($sql, $replace = []) {
|
||||
return $this->_query_batch($sql, $replace);
|
||||
}
|
||||
|
||||
// 网站表单--------------------------------------------------------------------
|
||||
|
||||
// 创建
|
||||
public function create_form($data) {
|
||||
if (dr_is_app('form')) {
|
||||
\Phpcmf\Service::M('form', 'form')->create_form($data);
|
||||
}
|
||||
}
|
||||
|
||||
// 删除表单
|
||||
public function delete_form($data) {
|
||||
if (dr_is_app('form')) {
|
||||
\Phpcmf\Service::M('form', 'form')->delete_form_table($data);
|
||||
}
|
||||
}
|
||||
|
||||
// 模块表单--------------------------------------------------------------------
|
||||
|
||||
// 创建
|
||||
public function create_module_form($data) {
|
||||
if (dr_is_app('mform')) {
|
||||
\Phpcmf\Service::M('mform', 'mform')->create_module_form($data);
|
||||
}
|
||||
}
|
||||
|
||||
// 删除模块表单
|
||||
public function delete_module_form($data) {
|
||||
if (dr_is_app('mform')) {
|
||||
\Phpcmf\Service::M('mform', 'mform')->delete_module_form($data);
|
||||
}
|
||||
}
|
||||
|
||||
// 项目--------------------------------------------------------------------
|
||||
|
||||
// 创建项目
|
||||
public function create_site($siteid) {
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user