DBCache.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. <?php
  2. namespace App\Model;
  3. use Cache;
  4. use Closure;
  5. use DateTime;
  6. use Illuminate\Pagination\Paginator;
  7. /**
  8. * 数据库模型 缓存读取
  9. *
  10. * Class DBCache
  11. * @package App\Model
  12. */
  13. class DBCache
  14. {
  15. protected $table = null;
  16. protected $attributes = [];
  17. protected $builder = null;
  18. private $__cache = true; //启用缓存(默认启用)
  19. private $__cacheKeyname = null; //缓存名称(默认自动生成)
  20. private $__cacheMinutes = 1; //缓存时间(分钟, 默认1分钟)
  21. private $__removeCache = false; //删除缓存
  22. private $__join = [];
  23. private $__take = [];
  24. private $__where = [];
  25. private $__whereRaw = [];
  26. private $__whereIn = [];
  27. private $__select = [];
  28. private $__selectRaw = [];
  29. private $__orderBy = [];
  30. private $__orderByRaw = [];
  31. private $__inRandomOrder = false;
  32. public function __construct($tabel = null, array $attributes = [])
  33. {
  34. $this->initParameter();
  35. if ($tabel) {
  36. $this->table = $tabel;
  37. }
  38. if ($attributes) {
  39. $this->attributes = $attributes;
  40. }
  41. }
  42. public function setTable($table)
  43. {
  44. $this->table = $table;
  45. return $this;
  46. }
  47. public function setAttributes($attributes)
  48. {
  49. $this->attributes = $attributes;
  50. return $this;
  51. }
  52. /**
  53. * 是否缓存
  54. *
  55. * @param bool $isCache
  56. * @return $this
  57. */
  58. public function cache($isCache = true)
  59. {
  60. $this->__cache = $isCache ? true : false;
  61. return $this;
  62. }
  63. public function noCache()
  64. {
  65. $this->__cache = false;
  66. return $this;
  67. }
  68. /**
  69. * 缓存名称
  70. *
  71. * @param $name
  72. * @return $this
  73. */
  74. public function cacheKeyname($name)
  75. {
  76. $this->__cacheKeyname = $name ?: null;
  77. return $this;
  78. }
  79. /**
  80. * 缓存时间(分钟)
  81. *
  82. * @param $Minutes
  83. * @return $this
  84. */
  85. public function cacheMinutes($Minutes)
  86. {
  87. if ($Minutes === 'year') {
  88. $Minutes = 365 * 24 * 60;
  89. }elseif ($Minutes === 'month') {
  90. $Minutes = 30 * 24 * 60;
  91. }elseif ($Minutes === 'day') {
  92. $Minutes = 24 * 60;
  93. }elseif ($Minutes === 'hour') {
  94. $Minutes = 60;
  95. }
  96. if ($Minutes instanceof DateTime) {
  97. $this->__cacheMinutes = $Minutes;
  98. }else{
  99. $this->__cacheMinutes = max($Minutes, 1);
  100. }
  101. return $this;
  102. }
  103. /**
  104. * 删除缓存
  105. */
  106. public function removeCache()
  107. {
  108. $this->__removeCache = true;
  109. return $this;
  110. }
  111. public function forgetCache($cacheKey)
  112. {
  113. $this->__removeCache = false;
  114. return Cache::forget($cacheKey);
  115. }
  116. /* ******************************************************************************** */
  117. /* ******************************************************************************** */
  118. public function join($table, $first, $operator = null, $second = null, $type = 'inner', $where = false)
  119. {
  120. $this->__join[] = [
  121. $table,
  122. $first,
  123. $operator,
  124. $second,
  125. $type,
  126. $where
  127. ];
  128. return $this;
  129. }
  130. public function take($var)
  131. {
  132. $this->__take[] = $var;
  133. return $this;
  134. }
  135. public function where($column, $operator = null, $value = null, $boolean = 'and')
  136. {
  137. $this->__where[] = [
  138. $column,
  139. $operator,
  140. $value,
  141. $boolean
  142. ];
  143. return $this;
  144. }
  145. public function whereRaw($sql, $bindings = [], $boolean = 'and')
  146. {
  147. if ($sql === null) {
  148. return $this;
  149. }
  150. $this->__whereRaw[] = [
  151. $sql,
  152. $bindings,
  153. $boolean
  154. ];
  155. return $this;
  156. }
  157. public function whereIn($column, $values, $boolean = 'and', $not = false)
  158. {
  159. $this->__whereIn[] = [
  160. $column,
  161. $values,
  162. $boolean,
  163. $not
  164. ];
  165. return $this;
  166. }
  167. public function whereNotIn($column, $values, $boolean = 'and')
  168. {
  169. return $this->whereIn($column, $values, $boolean, true);
  170. }
  171. public function select($var = ['*'])
  172. {
  173. $this->__select[] = is_array($var) ? $var : func_get_args();
  174. return $this;
  175. }
  176. public function selectRaw($expression, array $bindings = [])
  177. {
  178. $this->__selectRaw[] = [
  179. $expression,
  180. $bindings
  181. ];
  182. return $this;
  183. }
  184. public function orderBy($column, $direction = 'asc')
  185. {
  186. $this->__orderBy[] = [
  187. $column,
  188. $direction
  189. ];
  190. return $this;
  191. }
  192. public function orderByDesc($column)
  193. {
  194. return $this->orderBy($column, 'desc');
  195. }
  196. public function orderByRaw($sql, $bindings = [])
  197. {
  198. $this->__orderByRaw[] = [
  199. $sql,
  200. $bindings
  201. ];
  202. return $this;
  203. }
  204. public function inRandomOrder($isRand = true)
  205. {
  206. $this->__inRandomOrder = $isRand?true:false;
  207. return $this;
  208. }
  209. /* ******************************************************************************** */
  210. /* ******************************************************************************** */
  211. /* ******************************************************************************** */
  212. /**
  213. * 初始化参数
  214. */
  215. private function initParameter() {
  216. $this->__cache = true;
  217. $this->__cacheKeyname = null;
  218. $this->__cacheMinutes = 1;
  219. $this->__removeCache = false;
  220. //
  221. $this->__join = [];
  222. $this->__take = [];
  223. $this->__where = [];
  224. $this->__whereRaw = [];
  225. $this->__whereIn = [];
  226. $this->__select = [];
  227. $this->__selectRaw = [];
  228. $this->__orderBy = [];
  229. $this->__orderByRaw = [];
  230. $this->__inRandomOrder = false;
  231. }
  232. /**
  233. * 获取缓存标识
  234. * @param string $type 查询方式
  235. * @param string $attach 附加标识
  236. * @return string
  237. */
  238. private function identify($type, $attach = '') {
  239. if ($this->__cacheKeyname) {
  240. return $this->__cacheKeyname;
  241. }
  242. //
  243. $identify = $this->addEncode($this->attributes);
  244. $identify.= $this->addEncode($this->__join);
  245. $identify.= $this->addEncode($this->__take);
  246. $identify.= $this->addEncode($this->__where);
  247. $identify.= $this->addEncode($this->__whereRaw);
  248. $identify.= $this->addEncode($this->__whereIn);
  249. $identify.= $this->addEncode($this->__select);
  250. $identify.= $this->addEncode($this->__selectRaw);
  251. $identify.= $this->addEncode($this->__orderBy);
  252. $identify.= $this->addEncode($this->__orderByRaw);
  253. $identify.= $this->addEncode($this->__inRandomOrder);
  254. $identify.= $this->addEncode($attach);
  255. //
  256. return 'DBCache:' . $this->table . ':' . $type . '::' . md5($identify);
  257. }
  258. private function addEncode($value)
  259. {
  260. $encodeName = '';
  261. if (is_array($value)) {
  262. sort($value);
  263. foreach ($value AS $key => $val) {
  264. $encodeName .= ':' . $key . '=' . $this->addEncode($val) . ';';
  265. }
  266. } elseif ($value instanceof Closure) {
  267. $join = new DBClause();
  268. call_user_func($value, $join);
  269. $encodeName .= ':' . $join->toString() . ';';
  270. } elseif (is_string($value) || is_numeric($value)) {
  271. $encodeName .= ':' . $value . ';';
  272. } else {
  273. $encodeName .= ':' . var_export($value, true) . ';';
  274. }
  275. return $encodeName;
  276. }
  277. /**
  278. * 创建对象
  279. * @return $this|DOModel|null
  280. */
  281. private function builder() {
  282. if ($this->builder === null) {
  283. $this->builder = new DOModel($this->table, $this->attributes);
  284. }
  285. $builder = $this->builder;
  286. //
  287. foreach ($this->__join AS $item) {
  288. $builder = $builder->join($item[0], $item[1], $item[2], $item[3], $item[4], $item[5]);
  289. }
  290. foreach ($this->__take AS $item) {
  291. $builder = $builder->take($item);
  292. }
  293. foreach ($this->__where AS $item) {
  294. $builder = $builder->where($item[0], $item[1], $item[2], $item[3]);
  295. }
  296. foreach ($this->__whereRaw AS $item) {
  297. $builder = $builder->whereRaw($item[0], $item[1], $item[2]);
  298. }
  299. foreach ($this->__whereIn AS $item) {
  300. $builder = $builder->whereIn($item[0], $item[1], $item[2], $item[3]);
  301. }
  302. foreach ($this->__select AS $item) {
  303. $builder = $builder->select($item);
  304. }
  305. foreach ($this->__selectRaw AS $item) {
  306. $builder = $builder->selectRaw($item[0], $item[1]);
  307. }
  308. foreach ($this->__orderBy AS $item) {
  309. $builder = $builder->orderBy($item[0], $item[1]);
  310. }
  311. foreach ($this->__orderByRaw AS $item) {
  312. $builder = $builder->orderByRaw($item[0], $item[1]);
  313. }
  314. if ($this->__inRandomOrder) {
  315. $builder = $builder->inRandomOrder();
  316. }
  317. //
  318. $this->initParameter();
  319. return $builder;
  320. }
  321. /* ******************************************************************************** */
  322. /* ******************************************************************************** */
  323. /* ******************************************************************************** */
  324. /**
  325. * 静态方法
  326. *
  327. * @param string $tabel
  328. * @return DBCache
  329. */
  330. public static function table($tabel = '')
  331. {
  332. return new DBCache($tabel);
  333. }
  334. /**
  335. * 获取一条数据
  336. *
  337. * @param array $columns
  338. * @return mixed
  339. */
  340. public function first($columns = ['*'])
  341. {
  342. if ($this->__cache) {
  343. $cacheKey = $this->identify('first', $columns);
  344. if ($this->__removeCache) {
  345. return $this->forgetCache($cacheKey);
  346. }
  347. $result = Cache::remember($cacheKey, $this->__cacheMinutes, function() use ($columns) {
  348. return $this->builder()->first($columns);
  349. });
  350. }else{
  351. $result = $this->builder()->first($columns);
  352. }
  353. return isset($result->original)?$result->original:null;
  354. }
  355. /**
  356. * 获取所有数据
  357. *
  358. * @param array $columns
  359. * @return array|bool
  360. */
  361. public function get($columns = ['*'])
  362. {
  363. if ($this->__cache) {
  364. $cacheKey = $this->identify('get', $columns);
  365. if ($this->__removeCache) {
  366. return $this->forgetCache($cacheKey);
  367. }
  368. $result = Cache::remember($cacheKey, $this->__cacheMinutes, function() use ($columns) {
  369. return $this->builder()->get($columns);
  370. });
  371. }else{
  372. $result = $this->builder()->get($columns);
  373. }
  374. //
  375. $array = [];
  376. foreach ($result AS $key=>$item) {
  377. $array[$key] = isset($item->original)?$item->original:null;
  378. }
  379. return $array;
  380. }
  381. /**
  382. * 查询结果的计数
  383. *
  384. * @param string $columns
  385. * @return int|bool
  386. */
  387. public function count($columns = '*')
  388. {
  389. if ($this->__cache) {
  390. $cacheKey = $this->identify('count', $columns);
  391. if ($this->__removeCache) {
  392. return $this->forgetCache($cacheKey);
  393. }
  394. $result = Cache::remember($cacheKey, $this->__cacheMinutes, function() use ($columns) {
  395. return $this->builder()->count($columns);
  396. });
  397. }else{
  398. $result = $this->builder()->count($columns);
  399. }
  400. return intval($result);
  401. }
  402. /**
  403. * 从查询的第一个结果中获得一个列的值
  404. *
  405. * @param $column
  406. * @return mixed
  407. */
  408. public function value($column)
  409. {
  410. if ($this->__cache) {
  411. $cacheKey = $this->identify('value', $column);
  412. if ($this->__removeCache) {
  413. return $this->forgetCache($cacheKey);
  414. }
  415. $result = Cache::remember($cacheKey, $this->__cacheMinutes, function() use ($column) {
  416. $value = $this->builder()->value($column);
  417. return $value ? $value : '';
  418. });
  419. }else{
  420. $result = $this->builder()->value($column);
  421. }
  422. return $result;
  423. }
  424. /**
  425. * 统计输出
  426. *
  427. * @param $column
  428. * @return bool|mixed
  429. */
  430. public function sum($column)
  431. {
  432. if ($this->__cache) {
  433. $cacheKey = $this->identify('sum', $column);
  434. if ($this->__removeCache) {
  435. return $this->forgetCache($cacheKey);
  436. }
  437. $result = Cache::remember($cacheKey, $this->__cacheMinutes, function() use ($column) {
  438. $sum = $this->builder()->sum($column);
  439. return $sum ? $sum : 0;
  440. });
  441. }else{
  442. $result = $this->builder()->sum($column);
  443. }
  444. return $result;
  445. }
  446. /**
  447. * 获取分页数据
  448. * @param null $perPage
  449. * @param array $columns
  450. * @param string $pageName
  451. * @param null $page
  452. * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator|mixed
  453. */
  454. public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)
  455. {
  456. if ($this->__cache) {
  457. $attach = $this->addEncode($perPage);
  458. $attach.= $this->addEncode($columns);
  459. $attach.= $this->addEncode($pageName);
  460. $attach.= $this->addEncode(Paginator::resolveCurrentPage($pageName));
  461. $cacheKey = $this->identify('paginate', $attach);
  462. if ($this->__removeCache) {
  463. return $this->forgetCache($cacheKey);
  464. }
  465. $result = Cache::remember($cacheKey, $this->__cacheMinutes, function() use ($perPage, $columns, $pageName, $page) {
  466. return $this->builder()->paginate($perPage, $columns, $pageName, $page);
  467. });
  468. }else{
  469. $result = $this->builder()->paginate($perPage, $columns, $pageName, $page);
  470. }
  471. $array = [];
  472. foreach ($result AS $key=>$item) {
  473. $array[$key] = isset($item->original)?$item->original:null;
  474. }
  475. return [
  476. "currentPage" => $result->currentPage(),
  477. "firstItem" => $result->firstItem(),
  478. "hasMorePages" => $result->hasMorePages(),
  479. "lastItem" => $result->lastItem(),
  480. "lastPage" => $result->lastPage(),
  481. "nextPageUrl" => $result->nextPageUrl(),
  482. "previousPageUrl" => $result->previousPageUrl(),
  483. "perPage" => $result->perPage(),
  484. "total" => $result->total(),
  485. "lists" => $array,
  486. ];
  487. }
  488. }