Completed
Push — 6.0 ( be0b6e...c47dd5 )
by liu
06:54 queued 10s
created

WhereQuery::parseWhereExp()   D

Complexity

Conditions 18
Paths 34

Size

Total Lines 38
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 342

Importance

Changes 0
Metric Value
cc 18
eloc 24
nc 34
nop 6
dl 0
loc 38
ccs 0
cts 24
cp 0
crap 342
rs 4.8666
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 <[email protected]>
10
// +----------------------------------------------------------------------
11
declare (strict_types = 1);
12
13
namespace think\db\concern;
14
15
use Closure;
16
use think\db\Raw;
17
18
trait WhereQuery
19
{
20
    /**
21
     * 指定AND查询条件
22
     * @access public
23
     * @param mixed $field     查询字段
24
     * @param mixed $op        查询表达式
25
     * @param mixed $condition 查询条件
26
     * @return $this
27
     */
28
    public function where($field, $op = null, $condition = null)
29
    {
30
        if ($field instanceof $this) {
31
            $this->parseQueryWhere($field);
32
            return $this;
33
        }
34
35
        $param = func_get_args();
36
        array_shift($param);
37
        return $this->parseWhereExp('AND', $field, $op, $condition, $param);
38
    }
39
40
    /**
41
     * 解析Query对象查询条件
42
     * @access public
43
     * @param Query $query 查询对象
44
     * @return void
45
     */
46
    protected function parseQueryWhere(Query $query): void
0 ignored issues
show
Bug introduced by
The type think\db\concern\Query was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
47
    {
48
        $this->options['where'] = $query->getOptions('where');
0 ignored issues
show
Bug Best Practice introduced by
The property options does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
49
50
        if ($query->getOptions('via')) {
51
            $via = $query->getOptions('via');
52
            foreach ($this->options['where'] as $logic => &$where) {
53
                foreach ($where as $key => &$val) {
54
                    if (is_array($val) && !strpos($val[0], '.')) {
55
                        $val[0] = $via . '.' . $val[0];
56
                    }
57
                }
58
            }
59
        }
60
61
        $this->bind($query->getBind(false));
0 ignored issues
show
Bug introduced by
It seems like bind() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

61
        $this->/** @scrutinizer ignore-call */ 
62
               bind($query->getBind(false));
Loading history...
62
    }
63
64
    /**
65
     * 指定OR查询条件
66
     * @access public
67
     * @param mixed $field     查询字段
68
     * @param mixed $op        查询表达式
69
     * @param mixed $condition 查询条件
70
     * @return $this
71
     */
72
    public function whereOr($field, $op = null, $condition = null)
73
    {
74
        $param = func_get_args();
75
        array_shift($param);
76
        return $this->parseWhereExp('OR', $field, $op, $condition, $param);
77
    }
78
79
    /**
80
     * 指定XOR查询条件
81
     * @access public
82
     * @param mixed $field     查询字段
83
     * @param mixed $op        查询表达式
84
     * @param mixed $condition 查询条件
85
     * @return $this
86
     */
87
    public function whereXor($field, $op = null, $condition = null)
88
    {
89
        $param = func_get_args();
90
        array_shift($param);
91
        return $this->parseWhereExp('XOR', $field, $op, $condition, $param);
92
    }
93
94
    /**
95
     * 指定Null查询条件
96
     * @access public
97
     * @param mixed  $field 查询字段
98
     * @param string $logic 查询逻辑 and or xor
99
     * @return $this
100
     */
101
    public function whereNull(string $field, string $logic = 'AND')
102
    {
103
        return $this->parseWhereExp($logic, $field, 'NULL', null, [], true);
104
    }
105
106
    /**
107
     * 指定NotNull查询条件
108
     * @access public
109
     * @param mixed  $field 查询字段
110
     * @param string $logic 查询逻辑 and or xor
111
     * @return $this
112
     */
113
    public function whereNotNull(string $field, string $logic = 'AND')
114
    {
115
        return $this->parseWhereExp($logic, $field, 'NOTNULL', null, [], true);
116
    }
117
118
    /**
119
     * 指定Exists查询条件
120
     * @access public
121
     * @param mixed  $condition 查询条件
122
     * @param string $logic     查询逻辑 and or xor
123
     * @return $this
124
     */
125
    public function whereExists($condition, string $logic = 'AND')
126
    {
127
        if (is_string($condition)) {
128
            $condition = new Raw($condition);
129
        }
130
131
        $this->options['where'][strtoupper($logic)][] = ['', 'EXISTS', $condition];
0 ignored issues
show
Bug Best Practice introduced by
The property options does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
132
        return $this;
133
    }
134
135
    /**
136
     * 指定NotExists查询条件
137
     * @access public
138
     * @param mixed  $condition 查询条件
139
     * @param string $logic     查询逻辑 and or xor
140
     * @return $this
141
     */
142
    public function whereNotExists($condition, string $logic = 'AND')
143
    {
144
        if (is_string($condition)) {
145
            $condition = new Raw($condition);
146
        }
147
148
        $this->options['where'][strtoupper($logic)][] = ['', 'NOT EXISTS', $condition];
0 ignored issues
show
Bug Best Practice introduced by
The property options does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
149
        return $this;
150
    }
151
152
    /**
153
     * 指定In查询条件
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 whereIn(string $field, $condition, string $logic = 'AND')
161
    {
162
        return $this->parseWhereExp($logic, $field, 'IN', $condition, [], true);
163
    }
164
165
    /**
166
     * 指定NotIn查询条件
167
     * @access public
168
     * @param mixed  $field     查询字段
169
     * @param mixed  $condition 查询条件
170
     * @param string $logic     查询逻辑 and or xor
171
     * @return $this
172
     */
173
    public function whereNotIn(string $field, $condition, string $logic = 'AND')
174
    {
175
        return $this->parseWhereExp($logic, $field, 'NOT IN', $condition, [], true);
176
    }
177
178
    /**
179
     * 指定Like查询条件
180
     * @access public
181
     * @param mixed  $field     查询字段
182
     * @param mixed  $condition 查询条件
183
     * @param string $logic     查询逻辑 and or xor
184
     * @return $this
185
     */
186
    public function whereLike(string $field, $condition, string $logic = 'AND')
187
    {
188
        return $this->parseWhereExp($logic, $field, 'LIKE', $condition, [], true);
189
    }
190
191
    /**
192
     * 指定NotLike查询条件
193
     * @access public
194
     * @param mixed  $field     查询字段
195
     * @param mixed  $condition 查询条件
196
     * @param string $logic     查询逻辑 and or xor
197
     * @return $this
198
     */
199
    public function whereNotLike(string $field, $condition, string $logic = 'AND')
200
    {
201
        return $this->parseWhereExp($logic, $field, 'NOT LIKE', $condition, [], true);
202
    }
203
204
    /**
205
     * 指定Between查询条件
206
     * @access public
207
     * @param mixed  $field     查询字段
208
     * @param mixed  $condition 查询条件
209
     * @param string $logic     查询逻辑 and or xor
210
     * @return $this
211
     */
212
    public function whereBetween(string $field, $condition, string $logic = 'AND')
213
    {
214
        return $this->parseWhereExp($logic, $field, 'BETWEEN', $condition, [], true);
215
    }
216
217
    /**
218
     * 指定NotBetween查询条件
219
     * @access public
220
     * @param mixed  $field     查询字段
221
     * @param mixed  $condition 查询条件
222
     * @param string $logic     查询逻辑 and or xor
223
     * @return $this
224
     */
225
    public function whereNotBetween(string $field, $condition, string $logic = 'AND')
226
    {
227
        return $this->parseWhereExp($logic, $field, 'NOT BETWEEN', $condition, [], true);
228
    }
229
230
    /**
231
     * 指定FIND_IN_SET查询条件
232
     * @access public
233
     * @param mixed  $field     查询字段
234
     * @param mixed  $condition 查询条件
235
     * @param string $logic     查询逻辑 and or xor
236
     * @return $this
237
     */
238
    public function whereFindInSet(string $field, $condition, string $logic = 'AND')
239
    {
240
        return $this->parseWhereExp($logic, $field, 'FIND IN SET', $condition, [], true);
241
    }
242
243
    /**
244
     * 比较两个字段
245
     * @access public
246
     * @param string $field1   查询字段
247
     * @param string $operator 比较操作符
248
     * @param string $field2   比较字段
249
     * @param string $logic    查询逻辑 and or xor
250
     * @return $this
251
     */
252
    public function whereColumn(string $field1, string $operator, string $field2 = null, string $logic = 'AND')
253
    {
254
        if (is_null($field2)) {
255
            $field2   = $operator;
256
            $operator = '=';
257
        }
258
259
        return $this->parseWhereExp($logic, $field1, 'COLUMN', [$operator, $field2], [], true);
260
    }
261
262
    /**
263
     * 设置软删除字段及条件
264
     * @access public
265
     * @param string $field     查询字段
266
     * @param mixed  $condition 查询条件
267
     * @return $this
268
     */
269
    public function useSoftDelete(string $field, $condition = null)
270
    {
271
        if ($field) {
272
            $this->options['soft_delete'] = [$field, $condition];
0 ignored issues
show
Bug Best Practice introduced by
The property options does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
273
        }
274
275
        return $this;
276
    }
277
278
    /**
279
     * 指定Exp查询条件
280
     * @access public
281
     * @param mixed  $field 查询字段
282
     * @param string $where 查询条件
283
     * @param array  $bind  参数绑定
284
     * @param string $logic 查询逻辑 and or xor
285
     * @return $this
286
     */
287
    public function whereExp(string $field, string $where, array $bind = [], string $logic = 'AND')
288
    {
289
        if (!empty($bind)) {
290
            $this->bindParams($where, $bind);
0 ignored issues
show
Bug introduced by
It seems like bindParams() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

290
            $this->/** @scrutinizer ignore-call */ 
291
                   bindParams($where, $bind);
Loading history...
291
        }
292
293
        $this->options['where'][$logic][] = [$field, 'EXP', new Raw($where)];
0 ignored issues
show
Bug Best Practice introduced by
The property options does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
294
295
        return $this;
296
    }
297
298
    /**
299
     * 指定字段Raw查询
300
     * @access public
301
     * @param string $field     查询字段表达式
302
     * @param mixed  $op        查询表达式
303
     * @param string $condition 查询条件
304
     * @param string $logic     查询逻辑 and or xor
305
     * @return $this
306
     */
307
    public function whereFieldRaw(string $field, $op, $condition = null, string $logic = 'AND')
308
    {
309
        if (is_null($condition)) {
310
            $condition = $op;
311
            $op        = '=';
312
        }
313
314
        $this->options['where'][$logic][] = [new Raw($field), $op, $condition];
0 ignored issues
show
Bug Best Practice introduced by
The property options does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
315
        return $this;
316
    }
317
318
    /**
319
     * 指定表达式查询条件
320
     * @access public
321
     * @param string $where 查询条件
322
     * @param array  $bind  参数绑定
323
     * @param string $logic 查询逻辑 and or xor
324
     * @return $this
325
     */
326
    public function whereRaw(string $where, array $bind = [], string $logic = 'AND')
327
    {
328
        if (!empty($bind)) {
329
            $this->bindParams($where, $bind);
330
        }
331
332
        $this->options['where'][$logic][] = new Raw($where);
0 ignored issues
show
Bug Best Practice introduced by
The property options does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
333
334
        return $this;
335
    }
336
337
    /**
338
     * 指定表达式查询条件 OR
339
     * @access public
340
     * @param string $where 查询条件
341
     * @param array  $bind  参数绑定
342
     * @return $this
343
     */
344
    public function whereOrRaw(string $where, array $bind = [])
345
    {
346
        return $this->whereRaw($where, $bind, 'OR');
347
    }
348
349
    /**
350
     * 分析查询表达式
351
     * @access protected
352
     * @param string $logic     查询逻辑 and or xor
353
     * @param mixed  $field     查询字段
354
     * @param mixed  $op        查询表达式
355
     * @param mixed  $condition 查询条件
356
     * @param array  $param     查询参数
357
     * @param bool   $strict    严格模式
358
     * @return $this
359
     */
360
    protected function parseWhereExp(string $logic, $field, $op, $condition, array $param = [], bool $strict = false)
361
    {
362
        $logic = strtoupper($logic);
363
364
        if (is_string($field) && !empty($this->options['via']) && false === strpos($field, '.')) {
365
            $field = $this->options['via'] . '.' . $field;
366
        }
367
368
        if ($field instanceof Raw) {
369
            return $this->whereRaw($field, is_array($op) ? $op : [], $logic);
370
        } elseif ($strict) {
371
            // 使用严格模式查询
372
            if ('=' == $op) {
373
                $where = $this->whereEq($field, $condition);
374
            } else {
375
                $where = [$field, $op, $condition, $logic];
376
            }
377
        } elseif (is_array($field)) {
378
            // 解析数组批量查询
379
            return $this->parseArrayWhereItems($field, $logic);
380
        } elseif ($field instanceof Closure) {
381
            $where = $field;
382
        } elseif (is_string($field)) {
383
            if (preg_match('/[,=\<\'\"\(\s]/', $field)) {
384
                return $this->whereRaw($field, is_array($op) ? $op : [], $logic);
385
            } elseif (is_string($op) && strtolower($op) == 'exp') {
386
                $bind = isset($param[2]) && is_array($param[2]) ? $param[2] : [];
387
                return $this->whereExp($field, $condition, $bind, $logic);
388
            }
389
390
            $where = $this->parseWhereItem($logic, $field, $op, $condition, $param);
391
        }
392
393
        if (!empty($where)) {
394
            $this->options['where'][$logic][] = $where;
0 ignored issues
show
Bug Best Practice introduced by
The property options does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
395
        }
396
397
        return $this;
398
    }
399
400
    /**
401
     * 分析查询表达式
402
     * @access protected
403
     * @param string $logic     查询逻辑 and or xor
404
     * @param mixed  $field     查询字段
405
     * @param mixed  $op        查询表达式
406
     * @param mixed  $condition 查询条件
407
     * @param array  $param     查询参数
408
     * @return array
409
     */
410
    protected function parseWhereItem(string $logic, $field, $op, $condition, array $param = []): array
0 ignored issues
show
Unused Code introduced by
The parameter $logic is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

410
    protected function parseWhereItem(/** @scrutinizer ignore-unused */ string $logic, $field, $op, $condition, array $param = []): array

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
411
    {
412
        if (is_array($op)) {
413
            // 同一字段多条件查询
414
            array_unshift($param, $field);
415
            $where = $param;
416
        } elseif ($field && is_null($condition)) {
417
            if (is_string($op) && in_array(strtoupper($op), ['NULL', 'NOTNULL', 'NOT NULL'], true)) {
418
                // null查询
419
                $where = [$field, $op, ''];
420
            } elseif ('=' === $op || is_null($op)) {
421
                $where = [$field, 'NULL', ''];
422
            } elseif ('<>' === $op) {
423
                $where = [$field, 'NOTNULL', ''];
424
            } else {
425
                // 字段相等查询
426
                $where = $this->whereEq($field, $op);
427
            }
428
        } elseif (in_array(strtoupper($op), ['EXISTS', 'NOT EXISTS', 'NOTEXISTS'], true)) {
429
            $where = [$field, $op, is_string($condition) ? new Raw($condition) : $condition];
430
        } else {
431
            $where = $field ? [$field, $op, $condition, $param[2] ?? null] : [];
432
        }
433
434
        return $where;
435
    }
436
437
    /**
438
     * 相等查询的主键处理
439
     * @access protected
440
     * @param string $field 字段名
441
     * @param mixed  $value 字段值
442
     * @return array
443
     */
444
    protected function whereEq(string $field, $value): array
445
    {
446
        if ($this->getPk() == $field) {
0 ignored issues
show
Bug introduced by
It seems like getPk() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

446
        if ($this->/** @scrutinizer ignore-call */ getPk() == $field) {
Loading history...
447
            $this->options['key'] = $value;
0 ignored issues
show
Bug Best Practice introduced by
The property options does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
448
        }
449
450
        return [$field, '=', $value];
451
    }
452
453
    /**
454
     * 数组批量查询
455
     * @access protected
456
     * @param array  $field 批量查询
457
     * @param string $logic 查询逻辑 and or xor
458
     * @return $this
459
     */
460
    protected function parseArrayWhereItems(array $field, string $logic)
461
    {
462
        if (key($field) !== 0) {
463
            $where = [];
464
            foreach ($field as $key => $val) {
465
                if ($val instanceof Raw) {
466
                    $where[] = [$key, 'exp', $val];
467
                } else {
468
                    $where[] = is_null($val) ? [$key, 'NULL', ''] : [$key, is_array($val) ? 'IN' : '=', $val];
469
                }
470
            }
471
        } else {
472
            // 数组批量查询
473
            $where = $field;
474
        }
475
476
        if (!empty($where)) {
477
            $this->options['where'][$logic] = isset($this->options['where'][$logic]) ?
0 ignored issues
show
Bug Best Practice introduced by
The property options does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
478
            array_merge($this->options['where'][$logic], $where) : $where;
479
        }
480
481
        return $this;
482
    }
483
484
    /**
485
     * 去除某个查询条件
486
     * @access public
487
     * @param string $field 查询字段
488
     * @param string $logic 查询逻辑 and or xor
489
     * @return $this
490
     */
491
    public function removeWhereField(string $field, string $logic = 'AND')
492
    {
493
        $logic = strtoupper($logic);
494
495
        if (isset($this->options['where'][$logic])) {
496
            foreach ($this->options['where'][$logic] as $key => $val) {
497
                if (is_array($val) && $val[0] == $field) {
498
                    unset($this->options['where'][$logic][$key]);
499
                }
500
            }
501
        }
502
503
        return $this;
504
    }
505
506
    /**
507
     * 条件查询
508
     * @access public
509
     * @param mixed         $condition 满足条件(支持闭包)
510
     * @param Closure|array $query     满足条件后执行的查询表达式(闭包或数组)
511
     * @param Closure|array $otherwise 不满足条件后执行
512
     * @return $this
513
     */
514
    public function when($condition, $query, $otherwise = null)
515
    {
516
        if ($condition instanceof Closure) {
517
            $condition = $condition($this);
518
        }
519
520
        if ($condition) {
521
            if ($query instanceof Closure) {
522
                $query($this, $condition);
523
            } elseif (is_array($query)) {
0 ignored issues
show
introduced by
The condition is_array($query) is always true.
Loading history...
524
                $this->where($query);
525
            }
526
        } elseif ($otherwise) {
527
            if ($otherwise instanceof Closure) {
528
                $otherwise($this, $condition);
529
            } elseif (is_array($otherwise)) {
0 ignored issues
show
introduced by
The condition is_array($otherwise) is always true.
Loading history...
530
                $this->where($otherwise);
531
            }
532
        }
533
534
        return $this;
535
    }
536
}
537