DbCriteria.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. <?php
  2. class DbCriteria extends \CDbCriteria
  3. {
  4. // 通过 setDebugUntil 方法开启
  5. public const DEBUG_ON = 1;
  6. public const DEBUG_OFF = 0;
  7. public string $forceIndex = ''; // 强制索引
  8. private bool $lock = false; // 是否加锁
  9. private int $page = 0;
  10. private string $countSelect = 'count(*) as total';
  11. private bool $_fenye = false; // 是否分页 只有调用 setPage 才会分页
  12. private int $pageSize = 0;
  13. private int $debugMode = self::DEBUG_OFF; // 1 可以开启debug记录日志
  14. protected string $debugTag = '';
  15. /**
  16. * Adds a comparison expression to the {@link condition} property.
  17. *
  18. * This method is a helper that appends to the {@link condition} property
  19. * with a new comparison expression. The comparison is done by comparing a column
  20. * with the given value using some comparison operator.
  21. *
  22. * The comparison operator is intelligently determined based on the first few
  23. * characters in the given value. In particular, it recognizes the following operators
  24. * if they appear as the leading characters in the given value:
  25. * <ul>
  26. * <li><code>&lt;</code>: the column must be less than the given value.</li>
  27. * <li><code>&gt;</code>: the column must be greater than the given value.</li>
  28. * <li><code>&lt;=</code>: the column must be less than or equal to the given value.</li>
  29. * <li><code>&gt;=</code>: the column must be greater than or equal to the given value.</li>
  30. * <li><code>&lt;&gt;</code>: the column must not be the same as the given value.
  31. * Note that when $partialMatch is true, this would mean the value must not be a substring
  32. * of the column.</li>
  33. * <li><code>=</code>: the column must be equal to the given value.</li>
  34. * <li>none of the above: the column must be equal to the given value. Note that when $partialMatch
  35. * is true, this would mean the value must be the same as the given value or be a substring of it.</li>
  36. * </ul>
  37. *
  38. * Note that any surrounding white spaces will be removed from the value before comparison.
  39. * When the value is empty, no comparison expression will be added to the search condition.
  40. *
  41. * @param string $column the name of the column to be searched
  42. * @param mixed $value the column value to be compared with. If the value is a string, the aforementioned
  43. * intelligent comparison will be conducted. If the value is an array, the comparison is done
  44. * by exact match of any of the value in the array. If the string or the array is empty,
  45. * the existing search condition will not be modified.
  46. * @param boolean $partialMatch whether the value should consider partial text match (using LIKE and NOT LIKE operators).
  47. * Defaults to false, meaning exact comparison.
  48. * @param string $operator the operator used to concatenate the new condition with the existing one.
  49. * Defaults to 'AND'.
  50. * @param boolean $escape whether the value should be escaped if $partialMatch is true and
  51. * the value contains characters % or _. When this parameter is true (default),
  52. * the special characters % (matches 0 or more characters)
  53. * and _ (matches a single character) will be escaped, and the value will be surrounded with a %
  54. * character on both ends. When this parameter is false, the value will be directly used for
  55. * matching without any change.
  56. * @return static the criteria object itself
  57. * @since 1.1.1
  58. */
  59. public function compare($column, $value, $partialMatch = false, $operator = 'AND', $escape = true): static
  60. {
  61. if (is_array($value)) {
  62. if ($value === array()) {
  63. return $this;
  64. }
  65. return $this->addInCondition($column, $value, $operator);
  66. } else {
  67. $value = "$value";
  68. }
  69. if (preg_match('/^(?:\s*(<>|<=|>=|<|>|=|%|\!=))?(.*)$/', $value, $matches)) {
  70. $value = $matches[2];
  71. $op = $matches[1];
  72. } else {
  73. $op = '';
  74. }
  75. if ($op == '%') {
  76. //模糊匹配
  77. $partialMatch = true;
  78. $op = '';
  79. }
  80. if ($value === '') {
  81. return $this;
  82. }
  83. if ($partialMatch) {
  84. if ($op === '') {
  85. return $this->addSearchCondition($column, $value, $escape, $operator);
  86. }
  87. if ($op === '<>') {
  88. return $this->addSearchCondition($column, $value, $escape, $operator, 'NOT LIKE');
  89. }
  90. } elseif ($op === '') {
  91. $op = '=';
  92. }
  93. $this->addCondition($column.$op.self::PARAM_PREFIX.self::$paramCount, $operator);
  94. $this->params[self::PARAM_PREFIX.self::$paramCount++] = $value;
  95. return $this;
  96. }
  97. /**
  98. * 设置 分页数据
  99. * @param int $page
  100. * @param int $pageSize
  101. * @return DbCriteria
  102. */
  103. public function setPage(int $page = 1, int $pageSize = 30): static
  104. {
  105. if ($page < 0 || $pageSize < 1) {
  106. return $this;
  107. }
  108. $this->pageSize = $this->limit = $pageSize;
  109. $this->page = $page > 0 ? $page : 1;
  110. if ($this->offset > 0) {
  111. $this->offset += ($this->page - 1) * $this->limit;
  112. } else {
  113. $this->offset = ($this->page - 1) * $this->limit;
  114. }
  115. $this->_fenye = 1;
  116. return $this;
  117. }
  118. public function setLockStatus($status): static
  119. {
  120. $this->lock = (bool)$status;
  121. return $this;
  122. }
  123. public function getLockStatus(): bool
  124. {
  125. return $this->lock;
  126. }
  127. public function getPage(): int
  128. {
  129. return $this->page;
  130. }
  131. public function getPageSize(): int
  132. {
  133. return $this->pageSize;
  134. }
  135. public function setSelect($field = '*'): static
  136. {
  137. $this->select = $field;
  138. return $this;
  139. }
  140. public function setJoin($join): static
  141. {
  142. $this->join = $join;
  143. return $this;
  144. }
  145. public function addJoin($join): static
  146. {
  147. $this->join.= ' ' . $join;
  148. return $this;
  149. }
  150. public function setAlias($alias): static
  151. {
  152. $this->alias = $alias;
  153. return $this;
  154. }
  155. public function setGroup($group): static
  156. {
  157. $this->group = $group;
  158. return $this;
  159. }
  160. public function setOrder($order): static
  161. {
  162. $this->order = $order;
  163. return $this;
  164. }
  165. public function addOrder($order): static
  166. {
  167. if ($this->order) {
  168. $this->order .= ','.$order;
  169. } else {
  170. $this->order = $order;
  171. }
  172. return $this;
  173. }
  174. public function setOffset($offset): static
  175. {
  176. $this->offset = $offset;
  177. return $this;
  178. }
  179. public function addOffset($offset): static
  180. {
  181. $this->offset += $offset;
  182. return $this;
  183. }
  184. public function setLimit($limit): static
  185. {
  186. $this->limit = $limit;
  187. return $this;
  188. }
  189. public function setHaving($having): static
  190. {
  191. $this->having = $having;
  192. return $this;
  193. }
  194. public function andHaving($having): static
  195. {
  196. if (!$having) {
  197. return $this;
  198. }
  199. if (!$this->having) {
  200. $this->having = $having;
  201. } else {
  202. $this->having .= ' AND '.$having;
  203. }
  204. return $this;
  205. }
  206. public function orHaving($having): static
  207. {
  208. if (!$having) {
  209. return $this;
  210. }
  211. if (!$this->having) {
  212. $this->having = $having;
  213. } else {
  214. $this->having .= ' OR '.$having;
  215. }
  216. return $this;
  217. }
  218. public function setForceIndex($index): static
  219. {
  220. $this->forceIndex = $index;
  221. return $this;
  222. }
  223. /**
  224. * 开启线上日志记录到指定时间
  225. * @param string $tag 标记 查找日志方便
  226. * @param string $deadline 必须指定 -1永久(不建议使用)
  227. */
  228. public function setDebugUntil($tag, $deadline): static
  229. {
  230. if ($deadline != '-1' && strtotime($deadline) < time()) {
  231. $this->debugMode = self::DEBUG_OFF;
  232. return $this;
  233. }
  234. $this->debugTag = $tag;
  235. $this->debugMode = self::DEBUG_ON;
  236. return $this;
  237. }
  238. public function getDebugMode(): bool
  239. {
  240. return $this->debugMode;
  241. }
  242. /**
  243. * @return array the array representation of the criteria
  244. */
  245. public function toArray(): array
  246. {
  247. $result = array();
  248. foreach (
  249. [
  250. 'select',
  251. // 'condition',
  252. // 'params',
  253. 'limit',
  254. 'offset',
  255. 'order',
  256. 'group',
  257. 'join',
  258. 'having',
  259. 'distinct',
  260. 'scopes',
  261. 'with',
  262. 'alias',
  263. 'index',
  264. 'together',
  265. 'page',
  266. 'pageSize',
  267. 'debugTag',
  268. ] as $name
  269. ) {
  270. $result[$name] = $this->$name;
  271. }
  272. return $result;
  273. }
  274. public function getSql($sql, $params): string
  275. {
  276. if ($params) {
  277. foreach ($params as $k => $v) {
  278. if (!is_numeric($v)) {
  279. $params[$k] = "'{$v}'";
  280. }
  281. }
  282. // 这里倒序会导致 :ycp5 覆盖 :ycp50
  283. $params = array_reverse($params);
  284. $sql = str_replace(array_keys($params), array_values($params), $sql);
  285. }
  286. $sql = str_replace("\n", ' ', $sql);
  287. return $this->getLockStatus() ? $sql." FOR UPDATE" : $sql;
  288. }
  289. public function getDebugTag(): string
  290. {
  291. return $this->debugTag;
  292. }
  293. public function getUseTime()
  294. {
  295. }
  296. public function isFenye(): bool
  297. {
  298. return $this->_fenye;
  299. }
  300. /**
  301. * 分页情况下,查询总条数的 select 字段,如果含有 group 时可能需要额外插叙字段
  302. * @param $str
  303. * @return string
  304. */
  305. public function setCountSelectStr($str): string
  306. {
  307. return $this->countSelect .= ','.trim($str, ',');
  308. }
  309. public function getCountSelectStr(): string
  310. {
  311. return $this->countSelect;
  312. }
  313. /**
  314. * 简单的compare
  315. * @param array $filter
  316. * @param bool $checkPage
  317. * @return $this
  318. */
  319. public static function simpleCompare(array $filter): static
  320. {
  321. $cri = new static();
  322. foreach ($filter as $k => $v) {
  323. $cri->compare($k, $v);
  324. }
  325. return $cri;
  326. }
  327. /**
  328. * 简单的compare
  329. * @param array $filter
  330. * @param bool $checkPage
  331. * @return $this
  332. */
  333. public static function simpleCompareWithPage(array $filter): static
  334. {
  335. $cri = self::simpleCompare($filter);
  336. $cri->setPage(
  337. Helper::getArrParam($_REQUEST, 'current', 'int', 1),
  338. Helper::getArrParam($_REQUEST, 'size', 'int', 20)
  339. );
  340. return $cri;
  341. }
  342. }