1
0

TenantCreatService.php 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | likeadmin快速开发前后端分离管理后台(PHP版)
  4. // +----------------------------------------------------------------------
  5. // | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
  6. // | 开源版本可自由商用,可去除界面版权logo
  7. // | gitee下载:https://gitee.com/likeshop_gitee/likeadmin
  8. // | github下载:https://github.com/likeshop-github/likeadmin
  9. // | 访问官网:https://www.likeadmin.cn
  10. // | likeadmin团队 版权所有 拥有最终解释权
  11. // +----------------------------------------------------------------------
  12. // | author: likeadminTeam
  13. // +----------------------------------------------------------------------
  14. namespace app\adminapi\service;
  15. use Exception;
  16. use PDO;
  17. use PDOException;
  18. use think\facade\Config;
  19. /**
  20. * 创建租户service
  21. * Class TenantCreatService
  22. * @package app\adminapi\service
  23. */
  24. class TenantCreatService
  25. {
  26. /**
  27. * 数据库连接
  28. */
  29. private $dbh = null;
  30. /**
  31. * @notes 创建租户模式分表
  32. * @param $tenantSn
  33. * @return bool
  34. * @throws \Random\RandomException
  35. * @author yfdong
  36. * @date 2024/09/28 10:55
  37. */
  38. public function createTenantTable($tenantSn)
  39. {
  40. // 创建数据库链接
  41. $this->dbh = self::connectDB();
  42. // 获取数据库版本
  43. $version = self::getMysqlVersion($this->dbh);
  44. // 获取数据库SQL文件路径
  45. $dbFile = dirname(__DIR__) . '/db/tenant.sql';
  46. // 检查文件是否存在,若不存在,直接返回错误
  47. if (!file_exists($dbFile)) {
  48. throw new Exception("SQL file not found: $dbFile");
  49. }
  50. // 读取并规范化SQL文件内容
  51. $content = str_replace(";\r\n", ";\n", file_get_contents($dbFile));
  52. // 对数据库中的脚本进行租户唯一标识替换
  53. $content = str_replace("{tenantSn}", $tenantSn, $content);
  54. // 分割SQL语句
  55. $tables = explode(";\n", $content);
  56. // 初始化安装时间戳
  57. $installTime = microtime(true) * 10000;
  58. // 循环处理每个SQL语句
  59. foreach ($tables as $table) {
  60. // 去除前后空白字符
  61. $table = trim($table);
  62. // 跳过空的SQL语句
  63. if (empty($table)) continue;
  64. // 处理数据库版本兼容性问题(版本<=4.1时移除CHARSET)
  65. if (strpos($table, 'CREATE') !== false && $version <= 4.1) {
  66. $table = str_replace('DEFAULT CHARSET=utf8', '', $table);
  67. }
  68. // 跳过注释的SQL语句
  69. if (strpos($table, '--') === 0) continue;
  70. // 替换表前缀
  71. $table = str_replace('`la_', env('database.database', 'likeadmin_saas') . '.`la_', $table);
  72. $table = str_replace('`la_', '`' . env('database.prefix', 'la_'), $table);
  73. // 如果是创建表的SQL,记录表名和时间戳
  74. // if (strpos($table, 'CREATE') !== false) {
  75. // $tableName = explode('`', $table)[1];
  76. // $installTime += random_int(3000, 7000); // 随机递增安装时间
  77. // $successTable[] = [$tableName, date('Y-m-d H:i:s', $installTime / 10000)];
  78. // }
  79. // 执行SQL语句
  80. try {
  81. if (!$this->dbh->query($table)) {
  82. throw new Exception("SQL execution failed: $table");
  83. }
  84. } catch (Exception $e) {
  85. // 捕获异常并输出详细错误信息
  86. echo 'Error executing SQL: ' . htmlspecialchars($table) . "<br>";
  87. echo 'Error message: ' . $e->getMessage() . "<br>";
  88. return false;
  89. }
  90. }
  91. return true;
  92. }
  93. /**
  94. * @notes 初始化租户数据
  95. * @param $tenantSn
  96. * @return bool
  97. * @throws \Random\RandomException
  98. * @author yfdong
  99. * @date 2024/10/01 15:43
  100. */
  101. public function initializationTenantData($tenantId, $tenantSn, $param)
  102. {
  103. // 创建数据库链接
  104. $this->dbh = self::connectDB();
  105. // 获取数据库版本
  106. $version = self::getMysqlVersion($this->dbh);
  107. // 获取数据库SQL文件路径
  108. $dbFile = dirname(__DIR__) . '/db/tenantData.sql';
  109. // 检查文件是否存在,若不存在,直接返回错误
  110. if (!file_exists($dbFile)) {
  111. throw new Exception("SQL file not found: $dbFile");
  112. }
  113. // 读取并规范化SQL文件内容
  114. $content = str_replace(";\r\n", ";\n", file_get_contents($dbFile));
  115. // 对数据库中的脚本进行租户唯一标识替换
  116. $content = str_replace("{tenantSn}", $tenantSn, $content);
  117. // 对数据库中的脚本进行租户唯一标识替换
  118. $content = str_replace("{tenantId}", $tenantId, $content);
  119. // 分割SQL语句
  120. $tables = explode(";\n", $content);
  121. // 初始化安装时间戳
  122. $installTime = microtime(true) * 10000;
  123. // 创建管理员账号
  124. $tables[] = $this->initAccount($tenantId, $tenantSn, $param);
  125. // 循环处理每个SQL语句
  126. foreach ($tables as $table) {
  127. // 去除前后空白字符
  128. $table = trim($table);
  129. // 跳过空的SQL语句
  130. if (empty($table)) continue;
  131. // 处理数据库版本兼容性问题(版本<=4.1时移除CHARSET)
  132. if (strpos($table, 'CREATE') !== false && $version <= 4.1) {
  133. $table = str_replace('DEFAULT CHARSET=utf8', '', $table);
  134. }
  135. // 跳过注释的SQL语句
  136. if (strpos($table, '--') === 0) continue;
  137. // 替换表前缀
  138. $table = str_replace('`la_', env('database.database', 'likeadmin_saas') . '.`la_', $table);
  139. $table = str_replace('`la_', '`' . env('database.prefix', 'la_'), $table);
  140. // 执行SQL语句
  141. try {
  142. if (!$this->dbh->query($table)) {
  143. throw new Exception("SQL execution failed: $table");
  144. }
  145. } catch (Exception $e) {
  146. // 捕获异常并输出详细错误信息
  147. echo "初始化租户初始数据失败";
  148. echo 'Error executing SQL: ' . htmlspecialchars($table) . "<br>";
  149. echo 'Error message: ' . $e->getMessage() . "<br>";
  150. return false;
  151. }
  152. }
  153. return true;
  154. }
  155. /**
  156. * @notes 检查数据库版本
  157. * @return string
  158. * @author yfdong
  159. * @date 2024/10/01 13:39
  160. */
  161. public function getMysqlVersion($dbh)
  162. {
  163. $sql = "SELECT VERSION() AS version";
  164. $result = $dbh->query($sql)->fetch();
  165. return substr($result->version, 0, 3);
  166. }
  167. /**
  168. * @notes 创建数据库链接
  169. * @return PDO|string
  170. * @author yfdong
  171. * @date 2024/10/01 13:39
  172. */
  173. public function connectDB()
  174. {
  175. // 获取数据库链接
  176. $host = env('database.hostname', '');
  177. $port = env('database.hostport', '');
  178. $user = env('database.username', '');
  179. $password = env('database.password', '');
  180. $dsn = "mysql:host={$host}; port={$port}";
  181. try {
  182. $this->dbh = new PDO($dsn, $user, $password);
  183. $this->dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
  184. $this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  185. $this->dbh->exec("SET NAMES 'utf8mb4'");
  186. $this->dbh->exec("SET NAMES 'utf8mb4'");
  187. try {
  188. $this->dbh->exec("SET GLOBAL sql_mode='STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';");
  189. } catch (Exception $e) {
  190. }
  191. return $this->dbh;
  192. } catch (PDOException $exception) {
  193. return $exception->getMessage();
  194. }
  195. }
  196. /**
  197. * @notes 创建管理员账号
  198. * @param $post
  199. * @return string
  200. * @author yfdong
  201. * @date 2024/10/01 16:02
  202. */
  203. public function initAccount($tenantId, $tenantSn, $param)
  204. {
  205. $time = time();
  206. $salt = Config::get('project.unique_identification');
  207. $defaultPassword = Config::get('project.default_password');
  208. global $uniqueSalt;
  209. $uniqueSalt = $salt;
  210. // 账号
  211. if (isset($param['account'])) {
  212. $account = $param['account'];
  213. } else {
  214. $account = 'admin';
  215. }
  216. //设置密码
  217. if (isset($param['password'])) {
  218. $password = md5($salt . md5($param['password'] . $salt));
  219. } else {
  220. $password = $defaultPassword;
  221. }
  222. // 超级管理员
  223. $sql = "INSERT INTO `la_tenant_admin_{$tenantSn}`(`id`, `tenant_id`,`root`, `name`, `avatar`, `account`, `password`, `login_time`, `login_ip`, `multipoint_login`, `disable`, `create_time`, `update_time`, `delete_time`) VALUES (1, {$tenantId},1, '超级管理员', '', '{$account}', '{$password}','{$time}', '', 1, 0, '{$time}', '{$time}', NULL);";
  224. // 超级管理员关联部门
  225. $sql .= "INSERT INTO `la_tenant_admin_dept_{$tenantSn}` (`admin_id`, `dept_id`) VALUES (1, 1);";
  226. return $sql;
  227. }
  228. }