DbManager.php 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types = 1);
  12. namespace think;
  13. use InvalidArgumentException;
  14. use Psr\Log\LoggerInterface;
  15. use Psr\SimpleCache\CacheInterface;
  16. use think\db\BaseQuery;
  17. use think\db\ConnectionInterface;
  18. use think\db\Query;
  19. use think\db\Raw;
  20. /**
  21. * Class DbManager
  22. * @package think
  23. * @mixin BaseQuery
  24. * @mixin Query
  25. */
  26. class DbManager
  27. {
  28. /**
  29. * 数据库连接实例
  30. * @var array
  31. */
  32. protected $instance = [];
  33. /**
  34. * 数据库配置
  35. * @var array
  36. */
  37. protected $config = [];
  38. /**
  39. * Event对象或者数组
  40. * @var array|object
  41. */
  42. protected $event;
  43. /**
  44. * SQL监听
  45. * @var array
  46. */
  47. protected $listen = [];
  48. /**
  49. * SQL日志
  50. * @var array
  51. */
  52. protected $dbLog = [];
  53. /**
  54. * 查询次数
  55. * @var int
  56. */
  57. protected $queryTimes = 0;
  58. /**
  59. * 查询缓存对象
  60. * @var CacheInterface
  61. */
  62. protected $cache;
  63. /**
  64. * 查询日志对象
  65. * @var LoggerInterface
  66. */
  67. protected $log;
  68. /**
  69. * 架构函数
  70. * @access public
  71. */
  72. public function __construct()
  73. {
  74. $this->modelMaker();
  75. }
  76. /**
  77. * 注入模型对象
  78. * @access public
  79. * @return void
  80. */
  81. protected function modelMaker()
  82. {
  83. $this->triggerSql();
  84. Model::setDb($this);
  85. if (is_object($this->event)) {
  86. Model::setEvent($this->event);
  87. }
  88. Model::maker(function (Model $model) {
  89. $isAutoWriteTimestamp = $model->getAutoWriteTimestamp();
  90. if (is_null($isAutoWriteTimestamp)) {
  91. // 自动写入时间戳
  92. $model->isAutoWriteTimestamp($this->getConfig('auto_timestamp', true));
  93. }
  94. $dateFormat = $model->getDateFormat();
  95. if (is_null($dateFormat)) {
  96. // 设置时间戳格式
  97. $model->setDateFormat($this->getConfig('datetime_format', 'Y-m-d H:i:s'));
  98. }
  99. });
  100. }
  101. /**
  102. * 监听SQL
  103. * @access protected
  104. * @return void
  105. */
  106. protected function triggerSql(): void
  107. {
  108. // 监听SQL
  109. $this->listen(function ($sql, $time, $master) {
  110. if (0 === strpos($sql, 'CONNECT:')) {
  111. $this->log($sql);
  112. return;
  113. }
  114. // 记录SQL
  115. if (is_bool($master)) {
  116. // 分布式记录当前操作的主从
  117. $master = $master ? 'master|' : 'slave|';
  118. } else {
  119. $master = '';
  120. }
  121. $this->log($sql . ' [ ' . $master . 'RunTime:' . $time . 's ]');
  122. });
  123. }
  124. /**
  125. * 初始化配置参数
  126. * @access public
  127. * @param array $config 连接配置
  128. * @return void
  129. */
  130. public function setConfig($config): void
  131. {
  132. $this->config = $config;
  133. }
  134. /**
  135. * 设置缓存对象
  136. * @access public
  137. * @param CacheInterface $cache 缓存对象
  138. * @return void
  139. */
  140. public function setCache(CacheInterface $cache): void
  141. {
  142. $this->cache = $cache;
  143. }
  144. /**
  145. * 设置日志对象
  146. * @access public
  147. * @param LoggerInterface $log 日志对象
  148. * @return void
  149. */
  150. public function setLog(LoggerInterface $log): void
  151. {
  152. $this->log = $log;
  153. }
  154. /**
  155. * 记录SQL日志
  156. * @access protected
  157. * @param string $log SQL日志信息
  158. * @param string $type 日志类型
  159. * @return void
  160. */
  161. public function log(string $log, string $type = 'sql')
  162. {
  163. if ($this->log) {
  164. $this->log->log($type, $log);
  165. } else {
  166. $this->dbLog[$type][] = $log;
  167. }
  168. }
  169. /**
  170. * 获得查询日志(没有设置日志对象使用)
  171. * @access public
  172. * @param bool $clear 是否清空
  173. * @return array
  174. */
  175. public function getDbLog(bool $clear = false): array
  176. {
  177. $logs = $this->dbLog;
  178. if ($clear) {
  179. $this->dbLog = [];
  180. }
  181. return $logs;
  182. }
  183. /**
  184. * 获取配置参数
  185. * @access public
  186. * @param string $name 配置参数
  187. * @param mixed $default 默认值
  188. * @return mixed
  189. */
  190. public function getConfig(string $name = '', $default = null)
  191. {
  192. if ('' === $name) {
  193. return $this->config;
  194. }
  195. return $this->config[$name] ?? $default;
  196. }
  197. /**
  198. * 创建/切换数据库连接查询
  199. * @access public
  200. * @param string|null $name 连接配置标识
  201. * @param bool $force 强制重新连接
  202. * @return BaseQuery
  203. */
  204. public function connect(string $name = null, bool $force = false): BaseQuery
  205. {
  206. $connection = $this->instance($name, $force);
  207. $class = $connection->getQueryClass();
  208. $query = new $class($connection);
  209. $timeRule = $this->getConfig('time_query_rule');
  210. if (!empty($timeRule)) {
  211. $query->timeRule($timeRule);
  212. }
  213. return $query;
  214. }
  215. /**
  216. * 创建数据库连接实例
  217. * @access protected
  218. * @param string|null $name 连接标识
  219. * @param bool $force 强制重新连接
  220. * @return ConnectionInterface
  221. */
  222. protected function instance(string $name = null, bool $force = false): ConnectionInterface
  223. {
  224. if (empty($name)) {
  225. $name = $this->getConfig('default', 'mysql');
  226. }
  227. if ($force || !isset($this->instance[$name])) {
  228. $this->instance[$name] = $this->createConnection($name);
  229. }
  230. return $this->instance[$name];
  231. }
  232. /**
  233. * 获取连接配置
  234. * @param string $name
  235. * @return array
  236. */
  237. protected function getConnectionConfig(string $name): array
  238. {
  239. $connections = $this->getConfig('connections');
  240. if (!isset($connections[$name])) {
  241. throw new InvalidArgumentException('Undefined db config:' . $name);
  242. }
  243. return $connections[$name];
  244. }
  245. /**
  246. * 创建连接
  247. * @param $name
  248. * @return ConnectionInterface
  249. */
  250. protected function createConnection(string $name): ConnectionInterface
  251. {
  252. $config = $this->getConnectionConfig($name);
  253. $type = !empty($config['type']) ? $config['type'] : 'mysql';
  254. if (false !== strpos($type, '\\')) {
  255. $class = $type;
  256. } else {
  257. $class = '\\think\\db\\connector\\' . ucfirst($type);
  258. }
  259. /** @var ConnectionInterface $connection */
  260. $connection = new $class($config);
  261. $connection->setDb($this);
  262. if ($this->cache) {
  263. $connection->setCache($this->cache);
  264. }
  265. return $connection;
  266. }
  267. /**
  268. * 使用表达式设置数据
  269. * @access public
  270. * @param string $value 表达式
  271. * @return Raw
  272. */
  273. public function raw(string $value): Raw
  274. {
  275. return new Raw($value);
  276. }
  277. /**
  278. * 更新查询次数
  279. * @access public
  280. * @return void
  281. */
  282. public function updateQueryTimes(): void
  283. {
  284. $this->queryTimes++;
  285. }
  286. /**
  287. * 重置查询次数
  288. * @access public
  289. * @return void
  290. */
  291. public function clearQueryTimes(): void
  292. {
  293. $this->queryTimes = 0;
  294. }
  295. /**
  296. * 获得查询次数
  297. * @access public
  298. * @return integer
  299. */
  300. public function getQueryTimes(): int
  301. {
  302. return $this->queryTimes;
  303. }
  304. /**
  305. * 监听SQL执行
  306. * @access public
  307. * @param callable $callback 回调方法
  308. * @return void
  309. */
  310. public function listen(callable $callback): void
  311. {
  312. $this->listen[] = $callback;
  313. }
  314. /**
  315. * 获取监听SQL执行
  316. * @access public
  317. * @return array
  318. */
  319. public function getListen(): array
  320. {
  321. return $this->listen;
  322. }
  323. /**
  324. * 注册回调方法
  325. * @access public
  326. * @param string $event 事件名
  327. * @param callable $callback 回调方法
  328. * @return void
  329. */
  330. public function event(string $event, callable $callback): void
  331. {
  332. $this->event[$event][] = $callback;
  333. }
  334. /**
  335. * 触发事件
  336. * @access public
  337. * @param string $event 事件名
  338. * @param mixed $params 传入参数
  339. * @return mixed
  340. */
  341. public function trigger(string $event, $params = null)
  342. {
  343. if (isset($this->event[$event])) {
  344. foreach ($this->event[$event] as $callback) {
  345. call_user_func_array($callback, [$this]);
  346. }
  347. }
  348. }
  349. public function __call($method, $args)
  350. {
  351. return call_user_func_array([$this->connect(), $method], $args);
  352. }
  353. }