TableManager.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. <?php
  2. namespace ba;
  3. use Throwable;
  4. use think\facade\Db;
  5. use think\facade\Config;
  6. use think\migration\db\Table;
  7. use Phinx\Db\Adapter\AdapterFactory;
  8. use Phinx\Db\Adapter\AdapterInterface;
  9. /**
  10. * 数据表管理类
  11. */
  12. class TableManager
  13. {
  14. /**
  15. * 返回一个 Phinx/Db/Table 实例 用于操作数据表
  16. * @param string $table 表名
  17. * @param array $options 传递给 Phinx/Db/Table 的 options
  18. * @param bool $prefixWrapper 是否使用表前缀包装表名
  19. * @param ?string $connection 连接配置标识
  20. * @return Table
  21. * @throws Throwable
  22. */
  23. public static function phinxTable(string $table, array $options = [], bool $prefixWrapper = true, ?string $connection = null): Table
  24. {
  25. return new Table($table, $options, self::phinxAdapter($prefixWrapper, $connection));
  26. }
  27. /**
  28. * 返回 Phinx\Db\Adapter\AdapterFactory (适配器/连接驱动)实例
  29. * @param bool $prefixWrapper 是否使用表前缀包装表名
  30. * @param ?string $connection 连接配置标识
  31. * @return AdapterInterface
  32. * @throws Throwable
  33. */
  34. public static function phinxAdapter(bool $prefixWrapper = true, ?string $connection = null): AdapterInterface
  35. {
  36. $config = static::getPhinxDbConfig($connection);
  37. $factory = AdapterFactory::instance();
  38. $adapter = $factory->getAdapter($config['adapter'], $config);
  39. if ($prefixWrapper) return $factory->getWrapper('prefix', $adapter);
  40. return $adapter;
  41. }
  42. /**
  43. * 数据表名
  44. * @param string $table 表名,带不带前缀均可
  45. * @param bool $fullName 是否返回带前缀的表名
  46. * @param ?string $connection 连接配置标识
  47. * @return string 表名
  48. * @throws Exception
  49. */
  50. public static function tableName(string $table, bool $fullName = true, ?string $connection = null): string
  51. {
  52. $connection = self::getConnectionConfig($connection);
  53. $pattern = '/^' . $connection['prefix'] . '/i';
  54. return ($fullName ? $connection['prefix'] : '') . (preg_replace($pattern, '', $table));
  55. }
  56. /**
  57. * 数据表列表
  58. * @param ?string $connection 连接配置标识
  59. * @throws Exception
  60. */
  61. public static function getTableList(?string $connection = null): array
  62. {
  63. $tableList = [];
  64. $config = self::getConnectionConfig($connection);
  65. $connection = self::getConnection($connection);
  66. $tables = Db::connect($connection)->query("SELECT TABLE_NAME,TABLE_COMMENT FROM information_schema.TABLES WHERE table_schema = ? ", [$config['database']]);
  67. foreach ($tables as $row) {
  68. $tableList[$row['TABLE_NAME']] = $row['TABLE_NAME'] . ($row['TABLE_COMMENT'] ? ' - ' . $row['TABLE_COMMENT'] : '');
  69. }
  70. return $tableList;
  71. }
  72. /**
  73. * 获取数据表所有列
  74. * @param string $table 数据表名
  75. * @param bool $onlyCleanComment 只要干净的字段注释信息
  76. * @param ?string $connection 连接配置标识
  77. * @throws Throwable
  78. */
  79. public static function getTableColumns(string $table, bool $onlyCleanComment = false, ?string $connection = null): array
  80. {
  81. if (!$table) return [];
  82. $table = self::tableName($table, true, $connection);
  83. $config = self::getConnectionConfig($connection);
  84. $connection = self::getConnection($connection);
  85. // 从数据库中获取表字段信息
  86. // Phinx 目前无法正确获取到列注释信息,故使用 sql
  87. $sql = "SELECT * FROM `information_schema`.`columns` "
  88. . "WHERE TABLE_SCHEMA = ? AND table_name = ? "
  89. . "ORDER BY ORDINAL_POSITION";
  90. $columnList = Db::connect($connection)->query($sql, [$config['database'], $table]);
  91. $fieldList = [];
  92. foreach ($columnList as $item) {
  93. if ($onlyCleanComment) {
  94. $fieldList[$item['COLUMN_NAME']] = '';
  95. if ($item['COLUMN_COMMENT']) {
  96. $comment = explode(':', $item['COLUMN_COMMENT']);
  97. $fieldList[$item['COLUMN_NAME']] = $comment[0];
  98. }
  99. continue;
  100. }
  101. $fieldList[$item['COLUMN_NAME']] = $item;
  102. }
  103. return $fieldList;
  104. }
  105. /**
  106. * 系统是否存在多个数据库连接配置
  107. */
  108. public static function isMultiDatabase(): bool
  109. {
  110. return count(Config::get("database.connections")) > 1;
  111. }
  112. /**
  113. * 获取数据库连接配置标识
  114. * @param ?string $source
  115. * @return string 连接配置标识
  116. */
  117. public static function getConnection(?string $source = null): string
  118. {
  119. if (!$source || $source === 'default') {
  120. return Config::get('database.default');
  121. }
  122. return $source;
  123. }
  124. /**
  125. * 获取某个数据库连接的配置数组
  126. * @param ?string $connection 连接配置标识
  127. * @throws Exception
  128. */
  129. public static function getConnectionConfig(?string $connection = null): array
  130. {
  131. $connection = self::getConnection($connection);
  132. $connection = config("database.connections.$connection");
  133. if (!is_array($connection)) {
  134. throw new Exception('Database connection configuration error');
  135. }
  136. // 分布式
  137. if ($connection['deploy'] == 1) {
  138. $keys = ['type', 'hostname', 'database', 'username', 'password', 'hostport', 'charset', 'prefix'];
  139. foreach ($connection as $key => $item) {
  140. if (in_array($key, $keys)) {
  141. $connection[$key] = is_array($item) ? $item[0] : explode(',', $item)[0];
  142. }
  143. }
  144. }
  145. return $connection;
  146. }
  147. /**
  148. * 获取 Phinx 适配器需要的数据库配置
  149. * @param ?string $connection 连接配置标识
  150. * @return array
  151. * @throws Throwable
  152. */
  153. protected static function getPhinxDbConfig(?string $connection = null): array
  154. {
  155. $config = self::getConnectionConfig($connection);
  156. $connection = self::getConnection($connection);
  157. $db = Db::connect($connection);
  158. // 数据库为懒连接,执行 sql 命令为 $db 实例连接数据库
  159. $db->query('SELECT 1');
  160. $table = Config::get('database.migration_table', 'migrations');
  161. return [
  162. 'adapter' => $config['type'],
  163. 'connection' => $db->getPdo(),
  164. 'name' => $config['database'],
  165. 'table_prefix' => $config['prefix'],
  166. 'migration_table' => $config['prefix'] . $table,
  167. ];
  168. }
  169. }