DbCriteria.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  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 setAlias($alias): static
  146. {
  147. $this->alias = $alias;
  148. return $this;
  149. }
  150. public function setGroup($group): static
  151. {
  152. $this->group = $group;
  153. return $this;
  154. }
  155. public function setOrder($order): static
  156. {
  157. $this->order = $order;
  158. return $this;
  159. }
  160. public function addOrder($order): static
  161. {
  162. if ($this->order) {
  163. $this->order .= ','.$order;
  164. } else {
  165. $this->order = $order;
  166. }
  167. return $this;
  168. }
  169. public function setOffset($offset): static
  170. {
  171. $this->offset = $offset;
  172. return $this;
  173. }
  174. public function addOffset($offset): static
  175. {
  176. $this->offset += $offset;
  177. return $this;
  178. }
  179. public function setLimit($limit): static
  180. {
  181. $this->limit = $limit;
  182. return $this;
  183. }
  184. public function setHaving($having): static
  185. {
  186. $this->having = $having;
  187. return $this;
  188. }
  189. public function andHaving($having): static
  190. {
  191. if (!$having) {
  192. return $this;
  193. }
  194. if (!$this->having) {
  195. $this->having = $having;
  196. } else {
  197. $this->having .= ' AND '.$having;
  198. }
  199. return $this;
  200. }
  201. public function orHaving($having): static
  202. {
  203. if (!$having) {
  204. return $this;
  205. }
  206. if (!$this->having) {
  207. $this->having = $having;
  208. } else {
  209. $this->having .= ' OR '.$having;
  210. }
  211. return $this;
  212. }
  213. public function setForceIndex($index): static
  214. {
  215. $this->forceIndex = $index;
  216. return $this;
  217. }
  218. /**
  219. * 开启线上日志记录到指定时间
  220. * @param string $tag 标记 查找日志方便
  221. * @param string $deadline 必须指定 -1永久(不建议使用)
  222. */
  223. public function setDebugUntil($tag, $deadline): static
  224. {
  225. if ($deadline != '-1' && strtotime($deadline) < time()) {
  226. $this->debugMode = self::DEBUG_OFF;
  227. return $this;
  228. }
  229. $this->debugTag = $tag;
  230. $this->debugMode = self::DEBUG_ON;
  231. return $this;
  232. }
  233. public function getDebugMode(): bool
  234. {
  235. return $this->debugMode;
  236. }
  237. /**
  238. * @return array the array representation of the criteria
  239. */
  240. public function toArray(): array
  241. {
  242. $result = array();
  243. foreach (
  244. [
  245. 'select',
  246. // 'condition',
  247. // 'params',
  248. 'limit',
  249. 'offset',
  250. 'order',
  251. 'group',
  252. 'join',
  253. 'having',
  254. 'distinct',
  255. 'scopes',
  256. 'with',
  257. 'alias',
  258. 'index',
  259. 'together',
  260. 'page',
  261. 'pageSize',
  262. 'debugTag',
  263. ] as $name
  264. ) {
  265. $result[$name] = $this->$name;
  266. }
  267. return $result;
  268. }
  269. public function getSql($sql, $params): string
  270. {
  271. if ($params) {
  272. foreach ($params as $k => $v) {
  273. if (!is_numeric($v)) {
  274. $params[$k] = "'{$v}'";
  275. }
  276. }
  277. // 这里倒序会导致 :ycp5 覆盖 :ycp50
  278. $params = array_reverse($params);
  279. $sql = str_replace(array_keys($params), array_values($params), $sql);
  280. $sql = str_replace("\n", ' ', $sql);
  281. }
  282. return $this->getLockStatus() ? $sql." FOR UPDATE" : $sql;
  283. }
  284. public function getDebugTag(): string
  285. {
  286. return $this->debugTag;
  287. }
  288. public function getUseTime()
  289. {
  290. }
  291. public function isFenye(): bool
  292. {
  293. return $this->_fenye;
  294. }
  295. /**
  296. * 分页情况下,查询总条数的 select 字段,如果含有 group 时可能需要额外插叙字段
  297. * @param $str
  298. * @return string
  299. */
  300. public function setCountSelectStr($str): string
  301. {
  302. return $this->countSelect .= ','.trim($str, ',');
  303. }
  304. public function getCountSelectStr(): string
  305. {
  306. return $this->countSelect;
  307. }
  308. /**
  309. * 简单的compare
  310. * @param array $filter
  311. * @param bool $checkPage
  312. * @return $this
  313. */
  314. public static function simpleCompare(array $filter): static
  315. {
  316. $cri = new static();
  317. foreach ($filter as $k => $v) {
  318. $cri->compare($k, $v);
  319. }
  320. return $cri;
  321. }
  322. /**
  323. * 简单的compare
  324. * @param array $filter
  325. * @param bool $checkPage
  326. * @return $this
  327. */
  328. public static function simpleCompareWithPage(array $filter): static
  329. {
  330. $cri = self::simpleCompare($filter);
  331. $cri->setPage(
  332. Helper::getArrParam($_REQUEST, 'current', 'int', 1),
  333. Helper::getArrParam($_REQUEST, 'size', 'int', 20)
  334. );
  335. return $cri;
  336. }
  337. }