WhereQuery.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  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\db\concern;
  13. use Closure;
  14. use think\db\BaseQuery;
  15. use think\db\Raw;
  16. trait WhereQuery
  17. {
  18. /**
  19. * 指定AND查询条件
  20. * @access public
  21. * @param mixed $field 查询字段
  22. * @param mixed $op 查询表达式
  23. * @param mixed $condition 查询条件
  24. * @return $this
  25. */
  26. public function where($field, $op = null, $condition = null)
  27. {
  28. if ($field instanceof $this) {
  29. $this->parseQueryWhere($field);
  30. return $this;
  31. } elseif (true === $field || 1 === $field) {
  32. $this->options['where']['AND'][] = true;
  33. return $this;
  34. }
  35. $param = func_get_args();
  36. array_shift($param);
  37. return $this->parseWhereExp('AND', $field, $op, $condition, $param);
  38. }
  39. /**
  40. * 解析Query对象查询条件
  41. * @access public
  42. * @param BaseQuery $query 查询对象
  43. * @return void
  44. */
  45. protected function parseQueryWhere(BaseQuery $query): void
  46. {
  47. $this->options['where'] = $query->getOptions('where');
  48. if ($query->getOptions('via')) {
  49. $via = $query->getOptions('via');
  50. foreach ($this->options['where'] as $logic => &$where) {
  51. foreach ($where as $key => &$val) {
  52. if (is_array($val) && !strpos($val[0], '.')) {
  53. $val[0] = $via . '.' . $val[0];
  54. }
  55. }
  56. }
  57. }
  58. $this->bind($query->getBind(false));
  59. }
  60. /**
  61. * 指定OR查询条件
  62. * @access public
  63. * @param mixed $field 查询字段
  64. * @param mixed $op 查询表达式
  65. * @param mixed $condition 查询条件
  66. * @return $this
  67. */
  68. public function whereOr($field, $op = null, $condition = null)
  69. {
  70. $param = func_get_args();
  71. array_shift($param);
  72. return $this->parseWhereExp('OR', $field, $op, $condition, $param);
  73. }
  74. /**
  75. * 指定XOR查询条件
  76. * @access public
  77. * @param mixed $field 查询字段
  78. * @param mixed $op 查询表达式
  79. * @param mixed $condition 查询条件
  80. * @return $this
  81. */
  82. public function whereXor($field, $op = null, $condition = null)
  83. {
  84. $param = func_get_args();
  85. array_shift($param);
  86. return $this->parseWhereExp('XOR', $field, $op, $condition, $param);
  87. }
  88. /**
  89. * 指定Null查询条件
  90. * @access public
  91. * @param mixed $field 查询字段
  92. * @param string $logic 查询逻辑 and or xor
  93. * @return $this
  94. */
  95. public function whereNull(string $field, string $logic = 'AND')
  96. {
  97. return $this->parseWhereExp($logic, $field, 'NULL', null, [], true);
  98. }
  99. /**
  100. * 指定NotNull查询条件
  101. * @access public
  102. * @param mixed $field 查询字段
  103. * @param string $logic 查询逻辑 and or xor
  104. * @return $this
  105. */
  106. public function whereNotNull(string $field, string $logic = 'AND')
  107. {
  108. return $this->parseWhereExp($logic, $field, 'NOTNULL', null, [], true);
  109. }
  110. /**
  111. * 指定Exists查询条件
  112. * @access public
  113. * @param mixed $condition 查询条件
  114. * @param string $logic 查询逻辑 and or xor
  115. * @return $this
  116. */
  117. public function whereExists($condition, string $logic = 'AND')
  118. {
  119. if (is_string($condition)) {
  120. $condition = new Raw($condition);
  121. }
  122. $this->options['where'][strtoupper($logic)][] = ['', 'EXISTS', $condition];
  123. return $this;
  124. }
  125. /**
  126. * 指定NotExists查询条件
  127. * @access public
  128. * @param mixed $condition 查询条件
  129. * @param string $logic 查询逻辑 and or xor
  130. * @return $this
  131. */
  132. public function whereNotExists($condition, string $logic = 'AND')
  133. {
  134. if (is_string($condition)) {
  135. $condition = new Raw($condition);
  136. }
  137. $this->options['where'][strtoupper($logic)][] = ['', 'NOT EXISTS', $condition];
  138. return $this;
  139. }
  140. /**
  141. * 指定In查询条件
  142. * @access public
  143. * @param mixed $field 查询字段
  144. * @param mixed $condition 查询条件
  145. * @param string $logic 查询逻辑 and or xor
  146. * @return $this
  147. */
  148. public function whereIn(string $field, $condition, string $logic = 'AND')
  149. {
  150. return $this->parseWhereExp($logic, $field, 'IN', $condition, [], true);
  151. }
  152. /**
  153. * 指定NotIn查询条件
  154. * @access public
  155. * @param mixed $field 查询字段
  156. * @param mixed $condition 查询条件
  157. * @param string $logic 查询逻辑 and or xor
  158. * @return $this
  159. */
  160. public function whereNotIn(string $field, $condition, string $logic = 'AND')
  161. {
  162. return $this->parseWhereExp($logic, $field, 'NOT IN', $condition, [], true);
  163. }
  164. /**
  165. * 指定Like查询条件
  166. * @access public
  167. * @param mixed $field 查询字段
  168. * @param mixed $condition 查询条件
  169. * @param string $logic 查询逻辑 and or xor
  170. * @return $this
  171. */
  172. public function whereLike(string $field, $condition, string $logic = 'AND')
  173. {
  174. return $this->parseWhereExp($logic, $field, 'LIKE', $condition, [], true);
  175. }
  176. /**
  177. * 指定NotLike查询条件
  178. * @access public
  179. * @param mixed $field 查询字段
  180. * @param mixed $condition 查询条件
  181. * @param string $logic 查询逻辑 and or xor
  182. * @return $this
  183. */
  184. public function whereNotLike(string $field, $condition, string $logic = 'AND')
  185. {
  186. return $this->parseWhereExp($logic, $field, 'NOT LIKE', $condition, [], true);
  187. }
  188. /**
  189. * 指定Between查询条件
  190. * @access public
  191. * @param mixed $field 查询字段
  192. * @param mixed $condition 查询条件
  193. * @param string $logic 查询逻辑 and or xor
  194. * @return $this
  195. */
  196. public function whereBetween(string $field, $condition, string $logic = 'AND')
  197. {
  198. return $this->parseWhereExp($logic, $field, 'BETWEEN', $condition, [], true);
  199. }
  200. /**
  201. * 指定NotBetween查询条件
  202. * @access public
  203. * @param mixed $field 查询字段
  204. * @param mixed $condition 查询条件
  205. * @param string $logic 查询逻辑 and or xor
  206. * @return $this
  207. */
  208. public function whereNotBetween(string $field, $condition, string $logic = 'AND')
  209. {
  210. return $this->parseWhereExp($logic, $field, 'NOT BETWEEN', $condition, [], true);
  211. }
  212. /**
  213. * 指定FIND_IN_SET查询条件
  214. * @access public
  215. * @param mixed $field 查询字段
  216. * @param mixed $condition 查询条件
  217. * @param string $logic 查询逻辑 and or xor
  218. * @return $this
  219. */
  220. public function whereFindInSet(string $field, $condition, string $logic = 'AND')
  221. {
  222. return $this->parseWhereExp($logic, $field, 'FIND IN SET', $condition, [], true);
  223. }
  224. /**
  225. * 比较两个字段
  226. * @access public
  227. * @param string $field1 查询字段
  228. * @param string $operator 比较操作符
  229. * @param string $field2 比较字段
  230. * @param string $logic 查询逻辑 and or xor
  231. * @return $this
  232. */
  233. public function whereColumn(string $field1, string $operator, string $field2 = null, string $logic = 'AND')
  234. {
  235. if (is_null($field2)) {
  236. $field2 = $operator;
  237. $operator = '=';
  238. }
  239. return $this->parseWhereExp($logic, $field1, 'COLUMN', [$operator, $field2], [], true);
  240. }
  241. /**
  242. * 设置软删除字段及条件
  243. * @access public
  244. * @param string $field 查询字段
  245. * @param mixed $condition 查询条件
  246. * @return $this
  247. */
  248. public function useSoftDelete(string $field, $condition = null)
  249. {
  250. if ($field) {
  251. $this->options['soft_delete'] = [$field, $condition];
  252. }
  253. return $this;
  254. }
  255. /**
  256. * 指定Exp查询条件
  257. * @access public
  258. * @param mixed $field 查询字段
  259. * @param string $where 查询条件
  260. * @param array $bind 参数绑定
  261. * @param string $logic 查询逻辑 and or xor
  262. * @return $this
  263. */
  264. public function whereExp(string $field, string $where, array $bind = [], string $logic = 'AND')
  265. {
  266. if (!empty($bind)) {
  267. $this->bindParams($where, $bind);
  268. }
  269. $this->options['where'][$logic][] = [$field, 'EXP', new Raw($where)];
  270. return $this;
  271. }
  272. /**
  273. * 指定字段Raw查询
  274. * @access public
  275. * @param string $field 查询字段表达式
  276. * @param mixed $op 查询表达式
  277. * @param string $condition 查询条件
  278. * @param string $logic 查询逻辑 and or xor
  279. * @return $this
  280. */
  281. public function whereFieldRaw(string $field, $op, $condition = null, string $logic = 'AND')
  282. {
  283. if (is_null($condition)) {
  284. $condition = $op;
  285. $op = '=';
  286. }
  287. $this->options['where'][$logic][] = [new Raw($field), $op, $condition];
  288. return $this;
  289. }
  290. /**
  291. * 指定表达式查询条件
  292. * @access public
  293. * @param string $where 查询条件
  294. * @param array $bind 参数绑定
  295. * @param string $logic 查询逻辑 and or xor
  296. * @return $this
  297. */
  298. public function whereRaw(string $where, array $bind = [], string $logic = 'AND')
  299. {
  300. if (!empty($bind)) {
  301. $this->bindParams($where, $bind);
  302. }
  303. $this->options['where'][$logic][] = new Raw($where);
  304. return $this;
  305. }
  306. /**
  307. * 指定表达式查询条件 OR
  308. * @access public
  309. * @param string $where 查询条件
  310. * @param array $bind 参数绑定
  311. * @return $this
  312. */
  313. public function whereOrRaw(string $where, array $bind = [])
  314. {
  315. return $this->whereRaw($where, $bind, 'OR');
  316. }
  317. /**
  318. * 分析查询表达式
  319. * @access protected
  320. * @param string $logic 查询逻辑 and or xor
  321. * @param mixed $field 查询字段
  322. * @param mixed $op 查询表达式
  323. * @param mixed $condition 查询条件
  324. * @param array $param 查询参数
  325. * @param bool $strict 严格模式
  326. * @return $this
  327. */
  328. protected function parseWhereExp(string $logic, $field, $op, $condition, array $param = [], bool $strict = false)
  329. {
  330. $logic = strtoupper($logic);
  331. if (is_string($field) && !empty($this->options['via']) && false === strpos($field, '.')) {
  332. $field = $this->options['via'] . '.' . $field;
  333. }
  334. if ($field instanceof Raw) {
  335. return $this->whereRaw($field, is_array($op) ? $op : [], $logic);
  336. } elseif ($strict) {
  337. // 使用严格模式查询
  338. if ('=' == $op) {
  339. $where = $this->whereEq($field, $condition);
  340. } else {
  341. $where = [$field, $op, $condition, $logic];
  342. }
  343. } elseif (is_array($field)) {
  344. // 解析数组批量查询
  345. return $this->parseArrayWhereItems($field, $logic);
  346. } elseif ($field instanceof Closure) {
  347. $where = $field;
  348. } elseif (is_string($field)) {
  349. if (preg_match('/[,=\<\'\"\(\s]/', $field)) {
  350. return $this->whereRaw($field, is_array($op) ? $op : [], $logic);
  351. } elseif (is_string($op) && strtolower($op) == 'exp') {
  352. $bind = isset($param[2]) && is_array($param[2]) ? $param[2] : [];
  353. return $this->whereExp($field, $condition, $bind, $logic);
  354. }
  355. $where = $this->parseWhereItem($logic, $field, $op, $condition, $param);
  356. }
  357. if (!empty($where)) {
  358. $this->options['where'][$logic][] = $where;
  359. }
  360. return $this;
  361. }
  362. /**
  363. * 分析查询表达式
  364. * @access protected
  365. * @param string $logic 查询逻辑 and or xor
  366. * @param mixed $field 查询字段
  367. * @param mixed $op 查询表达式
  368. * @param mixed $condition 查询条件
  369. * @param array $param 查询参数
  370. * @return array
  371. */
  372. protected function parseWhereItem(string $logic, $field, $op, $condition, array $param = []): array
  373. {
  374. if (is_array($op)) {
  375. // 同一字段多条件查询
  376. array_unshift($param, $field);
  377. $where = $param;
  378. } elseif ($field && is_null($condition)) {
  379. if (is_string($op) && in_array(strtoupper($op), ['NULL', 'NOTNULL', 'NOT NULL'], true)) {
  380. // null查询
  381. $where = [$field, $op, ''];
  382. } elseif ('=' === $op || is_null($op)) {
  383. $where = [$field, 'NULL', ''];
  384. } elseif ('<>' === $op) {
  385. $where = [$field, 'NOTNULL', ''];
  386. } else {
  387. // 字段相等查询
  388. $where = $this->whereEq($field, $op);
  389. }
  390. } elseif (is_string($op) && in_array(strtoupper($op), ['EXISTS', 'NOT EXISTS', 'NOTEXISTS'], true)) {
  391. $where = [$field, $op, is_string($condition) ? new Raw($condition) : $condition];
  392. } else {
  393. $where = $field ? [$field, $op, $condition, $param[2] ?? null] : [];
  394. }
  395. return $where;
  396. }
  397. /**
  398. * 相等查询的主键处理
  399. * @access protected
  400. * @param string $field 字段名
  401. * @param mixed $value 字段值
  402. * @return array
  403. */
  404. protected function whereEq(string $field, $value): array
  405. {
  406. if ($this->getPk() == $field) {
  407. $this->options['key'] = $value;
  408. }
  409. return [$field, '=', $value];
  410. }
  411. /**
  412. * 数组批量查询
  413. * @access protected
  414. * @param array $field 批量查询
  415. * @param string $logic 查询逻辑 and or xor
  416. * @return $this
  417. */
  418. protected function parseArrayWhereItems(array $field, string $logic)
  419. {
  420. if (key($field) !== 0) {
  421. $where = [];
  422. foreach ($field as $key => $val) {
  423. if ($val instanceof Raw) {
  424. $where[] = [$key, 'exp', $val];
  425. } else {
  426. $where[] = is_null($val) ? [$key, 'NULL', ''] : [$key, is_array($val) ? 'IN' : '=', $val];
  427. }
  428. }
  429. } else {
  430. // 数组批量查询
  431. $where = $field;
  432. }
  433. if (!empty($where)) {
  434. $this->options['where'][$logic] = isset($this->options['where'][$logic]) ?
  435. array_merge($this->options['where'][$logic], $where) : $where;
  436. }
  437. return $this;
  438. }
  439. /**
  440. * 去除某个查询条件
  441. * @access public
  442. * @param string $field 查询字段
  443. * @param string $logic 查询逻辑 and or xor
  444. * @return $this
  445. */
  446. public function removeWhereField(string $field, string $logic = 'AND')
  447. {
  448. $logic = strtoupper($logic);
  449. if (isset($this->options['where'][$logic])) {
  450. foreach ($this->options['where'][$logic] as $key => $val) {
  451. if (is_array($val) && $val[0] == $field) {
  452. unset($this->options['where'][$logic][$key]);
  453. }
  454. }
  455. }
  456. return $this;
  457. }
  458. /**
  459. * 条件查询
  460. * @access public
  461. * @param mixed $condition 满足条件(支持闭包)
  462. * @param Closure|array $query 满足条件后执行的查询表达式(闭包或数组)
  463. * @param Closure|array $otherwise 不满足条件后执行
  464. * @return $this
  465. */
  466. public function when($condition, $query, $otherwise = null)
  467. {
  468. if ($condition instanceof Closure) {
  469. $condition = $condition($this);
  470. }
  471. if ($condition) {
  472. if ($query instanceof Closure) {
  473. $query($this, $condition);
  474. } elseif (is_array($query)) {
  475. $this->where($query);
  476. }
  477. } elseif ($otherwise) {
  478. if ($otherwise instanceof Closure) {
  479. $otherwise($this, $condition);
  480. } elseif (is_array($otherwise)) {
  481. $this->where($otherwise);
  482. }
  483. }
  484. return $this;
  485. }
  486. }