Completed
Push — 6.0 ( 800870...267f59 )
by yun
03:41 queued 17s
created

Query::chunk()   B

Complexity

Conditions 11
Paths 54

Size

Total Lines 51
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 132

Importance

Changes 0
Metric Value
cc 11
eloc 31
nc 54
nop 4
dl 0
loc 51
ccs 0
cts 29
cp 0
crap 132
rs 7.3166
c 0
b 0
f 0

How to fix   Long Method    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
// +----------------------------------------------------------------------
1 ignored issue
show
Coding Style introduced by
You must use "/**" style comments for a file comment
Loading history...
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;
14
15
use Closure;
16
use PDO;
17
use PDOStatement;
18
use think\App;
19
use think\Collection;
20
use think\Db;
21
use think\db\exception\BindParamException;
22
use think\db\exception\DataNotFoundException;
23
use think\db\exception\ModelNotFoundException;
24
use think\Exception;
25
use think\exception\DbException;
26
use think\exception\PDOException;
27
use think\Model;
28
use think\model\Collection as ModelCollection;
29
use think\model\Relation;
30
use think\model\relation\OneToOne;
31
use think\Paginator;
32
33
class Query
1 ignored issue
show
Coding Style introduced by
Missing doc comment for class Query
Loading history...
34
{
35
    /**
36
     * 当前数据库连接对象
37
     * @var Connection
38
     */
39
    protected $connection;
40
41
    /**
42
     * 当前模型对象
43
     * @var Model
44
     */
45
    protected $model;
46
47
    /**
48
     * Db对象
49
     * @var Db
50
     */
51
    protected $db;
52
53
    /**
54
     * 当前数据表名称(不含前缀)
55
     * @var string
56
     */
57
    protected $name = '';
58
59
    /**
60
     * 当前数据表主键
61
     * @var string|array
62
     */
63
    protected $pk;
64
65
    /**
66
     * 当前数据表前缀
67
     * @var string
68
     */
69
    protected $prefix = '';
70
71
    /**
72
     * 当前查询参数
73
     * @var array
74
     */
75
    protected $options = [];
76
77
    /**
78
     * 当前参数绑定
79
     * @var array
80
     */
81
    protected $bind = [];
82
83
    /**
84
     * 日期查询表达式
85
     * @var array
86
     */
87
    protected $timeRule = [
88
        'today'      => ['today', 'tomorrow'],
89
        'yesterday'  => ['yesterday', 'today'],
90
        'week'       => ['this week 00:00:00', 'next week 00:00:00'],
91
        'last week'  => ['last week 00:00:00', 'this week 00:00:00'],
92
        'month'      => ['first Day of this month 00:00:00', 'first Day of next month 00:00:00'],
93
        'last month' => ['first Day of last month 00:00:00', 'first Day of this month 00:00:00'],
94
        'year'       => ['this year 1/1', 'next year 1/1'],
95
        'last year'  => ['last year 1/1', 'this year 1/1'],
96
    ];
97
98
    /**
99
     * 架构函数
100
     * @access public
101
     * @param Connection $connection 数据库连接对象
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
102
     */
103
    public function __construct(Connection $connection)
104
    {
105
        $this->connection = $connection;
106
107
        $this->prefix = $this->connection->getConfig('prefix');
108
    }
109
110
    /**
111
     * 创建一个新的查询对象
112
     * @access public
113
     * @return Query
114
     */
115
    public function newQuery()
116
    {
117
        $query = new static($this->connection);
118
119
        if ($this->model) {
120
            $query->model($this->model);
121
        }
122
123
        if (isset($this->options['table'])) {
124
            $query->table($this->options['table']);
125
        } else {
126
            $query->name($this->name);
127
        }
128
129
        $query->setDb($this->db);
130
131
        return $query;
132
    }
133
134
    /**
135
     * 利用__call方法实现一些特殊的Model方法
136
     * @access public
137
     * @param string $method 方法名称
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
138
     * @param array  $args   调用参数
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
139
     * @return mixed
140
     * @throws DbException
141
     * @throws Exception
142
     */
143
    public function __call(string $method, array $args)
144
    {
145
        if (strtolower(substr($method, 0, 5)) == 'getby') {
146
            // 根据某个字段获取记录
147
            $field = App::parseName(substr($method, 5));
148
            return $this->where($field, '=', $args[0])->find();
149
        } elseif (strtolower(substr($method, 0, 10)) == 'getfieldby') {
150
            // 根据某个字段获取记录的某个值
151
            $name = App::parseName(substr($method, 10));
152
            return $this->where($name, '=', $args[0])->value($args[1]);
153
        } elseif (strtolower(substr($method, 0, 7)) == 'whereor') {
154
            $name = App::parseName(substr($method, 7));
155
            array_unshift($args, $name);
156
            return call_user_func_array([$this, 'whereOr'], $args);
157
        } elseif (strtolower(substr($method, 0, 5)) == 'where') {
158
            $name = App::parseName(substr($method, 5));
159
            array_unshift($args, $name);
160
            return call_user_func_array([$this, 'where'], $args);
161
        } elseif ($this->model && method_exists($this->model, 'scope' . $method)) {
162
            // 动态调用命名范围
163
            $method = 'scope' . $method;
164
            array_unshift($args, $this);
165
166
            call_user_func_array([$this->model, $method], $args);
167
            return $this;
168
        } else {
169
            throw new Exception('method not exist:' . static::class . '->' . $method);
170
        }
171
    }
172
173
    /**
174
     * 获取当前的数据库Connection对象
175
     * @access public
176
     * @return Connection
177
     */
178
    public function getConnection()
179
    {
180
        return $this->connection;
181
    }
182
183
    /**
184
     * 设置当前的数据库Connection对象
185
     * @access public
186
     * @param Connection $connection 数据库连接对象
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
187
     * @return $this
188
     */
189
    public function setConnection($connection)
190
    {
191
        $this->connection = $connection;
192
193
        return $this;
194
    }
195
196
    /**
197
     * 设置Db对象
198
     * @access public
199
     * @param Db $db
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
200
     * @return $this
201
     */
202
    public function setDb(Db $db)
203
    {
204
        $this->db = $db;
205
        $this->connection->setDb($db);
206
        return $this;
207
    }
208
209
    /**
210
     * 获取Db对象
211
     * @access public
212
     * @return Db
213
     */
214
    public function getDb()
215
    {
216
        return $this->db;
217
    }
218
219
    /**
220
     * 指定模型
221
     * @access public
222
     * @param Model $model 模型对象实例
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
223
     * @return $this
224
     */
225
    public function model(Model $model)
226
    {
227
        $this->model = $model;
228
        return $this;
229
    }
230
231
    /**
232
     * 获取当前的模型对象
233
     * @access public
234
     * @return Model|null
235
     */
236
    public function getModel()
237
    {
238
        return $this->model ? $this->model->setQuery($this) : null;
239
    }
240
241
    /**
242
     * 指定当前数据表名(不含前缀)
243
     * @access public
244
     * @param string $name 不含前缀的数据表名字
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
245
     * @return $this
246
     */
247
    public function name(string $name)
248
    {
249
        $this->name = $name;
250
        return $this;
251
    }
252
253
    /**
254
     * 获取当前的数据表名称
255
     * @access public
256
     * @return string
257
     */
258
    public function getName(): string
259
    {
260
        return $this->name ?: $this->model->getName();
261
    }
262
263
    /**
264
     * 获取数据库的配置参数
265
     * @access public
266
     * @param string $name 参数名称
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
267
     * @return mixed
268
     */
269
    public function getConfig(string $name = '')
270
    {
271
        return $this->connection->getConfig($name);
272
    }
273
274
    /**
275
     * 得到当前或者指定名称的数据表
276
     * @access public
277
     * @param string $name 不含前缀的数据表名字
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
278
     * @return mixed
279
     */
280
    public function getTable(string $name = '')
281
    {
282
        if (empty($name) && isset($this->options['table'])) {
283
            return $this->options['table'];
284
        }
285
286
        $name = $name ?: $this->name;
287
288
        return $this->prefix . App::parseName($name);
289
    }
290
291
    /**
292
     * 获取数据表字段信息
293
     * @access public
294
     * @param string $tableName 数据表名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
295
     * @return array
296
     */
297
    public function getTableFields($tableName = ''): array
298
    {
299
        if ('' == $tableName) {
300
            $tableName = $this->getTable();
301
        }
302
303
        return $this->connection->getTableFields($tableName);
304
    }
305
306
    /**
307
     * 设置字段类型信息
308
     * @access public
309
     * @param array $type 字段类型信息
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
310
     * @return $this
311
     */
312
    public function setFieldType(array $type)
313
    {
314
        $this->options['field_type'] = $type;
315
        return $this;
316
    }
317
318
    /**
319
     * 获取字段类型信息
320
     * @access public
321
     * @return array
322
     */
323
    public function getFieldsType(): array
324
    {
325
        if (!empty($this->options['field_type'])) {
326
            return $this->options['field_type'];
327
        }
328
329
        return $this->connection->getFieldsType($this->getTable());
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->connection...Type($this->getTable()) could return the type string which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
330
    }
331
332
    /**
333
     * 获取字段类型信息
334
     * @access public
335
     * @param string $field 字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
336
     * @return string|null
337
     */
338
    public function getFieldType(string $field)
339
    {
340
        $fieldType = $this->getFieldsType();
341
342
        return $fieldType[$field] ?? null;
343
    }
344
345
    /**
346
     * 获取字段类型信息
347
     * @access public
348
     * @return array
349
     */
350
    public function getFieldsBindType(): array
351
    {
352
        $fieldType = $this->getFieldsType();
353
354
        return array_map([$this->connection, 'getFieldBindType'], $fieldType);
355
    }
356
357
    /**
358
     * 获取字段类型信息
359
     * @access public
360
     * @param string $field 字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
361
     * @return int
362
     */
363
    public function getFieldBindType(string $field): int
364
    {
365
        $fieldType = $this->getFieldType($field);
366
367
        return $this->connection->getFieldBindType($fieldType ?: '');
368
    }
369
370
    /**
371
     * 执行查询 返回数据集
372
     * @access public
373
     * @param string $sql  sql指令
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
374
     * @param array  $bind 参数绑定
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
375
     * @return array
376
     * @throws BindParamException
377
     * @throws PDOException
378
     */
379
    public function query(string $sql, array $bind = []): array
380
    {
381
        return $this->connection->query($this, $sql, $bind, true);
382
    }
383
384
    /**
385
     * 执行语句
386
     * @access public
387
     * @param string $sql  sql指令
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
388
     * @param array  $bind 参数绑定
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
389
     * @return int
390
     * @throws BindParamException
391
     * @throws PDOException
392
     */
393
    public function execute(string $sql, array $bind = []): int
394
    {
395
        return $this->connection->execute($this, $sql, $bind, true);
396
    }
397
398
    /**
399
     * 监听SQL执行
400
     * @access public
401
     * @param callable $callback 回调方法
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
402
     * @return void
403
     */
404
    public function listen(callable $callback): void
405
    {
406
        $this->connection->listen($callback);
407
    }
408
409
    /**
410
     * 获取最近插入的ID
411
     * @access public
412
     * @param string $sequence 自增序列名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
413
     * @return string
414
     */
415
    public function getLastInsID(string $sequence = null): string
416
    {
417
        return $this->connection->getLastInsID($sequence);
418
    }
419
420
    /**
421
     * 获取返回或者影响的记录数
422
     * @access public
423
     * @return integer
424
     */
425
    public function getNumRows(): int
426
    {
427
        return $this->connection->getNumRows();
428
    }
429
430
    /**
431
     * 获取最近一次查询的sql语句
432
     * @access public
433
     * @return string
434
     */
435
    public function getLastSql(): string
436
    {
437
        return $this->connection->getLastSql();
438
    }
439
440
    /**
441
     * 执行数据库事务
442
     * @access public
443
     * @param callable $callback 数据操作方法回调
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
444
     * @return mixed
445
     */
446
    public function transaction(callable $callback)
447
    {
448
        return $this->connection->transaction($callback);
449
    }
450
451
    /**
452
     * 启动事务
453
     * @access public
454
     * @return void
455
     */
456
    public function startTrans(): void
457
    {
458
        $this->connection->startTrans();
459
    }
460
461
    /**
462
     * 用于非自动提交状态下面的查询提交
463
     * @access public
464
     * @return void
465
     * @throws PDOException
466
     */
467
    public function commit(): void
468
    {
469
        $this->connection->commit();
470
    }
471
472
    /**
473
     * 事务回滚
474
     * @access public
475
     * @return void
476
     * @throws PDOException
477
     */
478
    public function rollback(): void
479
    {
480
        $this->connection->rollback();
481
    }
482
483
    /**
484
     * 批处理执行SQL语句
485
     * 批处理的指令都认为是execute操作
486
     * @access public
487
     * @param array $sql SQL批处理指令
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
488
     * @return bool
489
     */
490
    public function batchQuery(array $sql = []): bool
491
    {
492
        return $this->connection->batchQuery($this, $sql);
493
    }
494
495
    /**
496
     * 得到某个字段的值
497
     * @access public
498
     * @param string $field   字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
499
     * @param mixed  $default 默认值
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
500
     * @return mixed
501
     */
502
    public function value(string $field, $default = null)
503
    {
504
        return $this->connection->value($this, $field, $default);
505
    }
506
507
    /**
508
     * 得到某个列的数组
509
     * @access public
510
     * @param string $field 字段名 多个字段用逗号分隔
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
511
     * @param string $key   索引
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
512
     * @return array
513
     */
514
    public function column(string $field, string $key = ''): array
515
    {
516
        return $this->connection->column($this, $field, $key);
517
    }
518
519
    /**
520
     * 聚合查询
521
     * @access protected
522
     * @param string     $aggregate 聚合方法
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
523
     * @param string|Raw $field     字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
524
     * @param bool       $force     强制转为数字类型
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
525
     * @return mixed
526
     */
527
    protected function aggregate(string $aggregate, $field, bool $force = false)
528
    {
529
        return $this->connection->aggregate($this, $aggregate, $field, $force);
530
    }
531
532
    /**
533
     * COUNT查询
534
     * @access public
535
     * @param string|Raw $field 字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
536
     * @return int
537
     */
538
    public function count(string $field = '*'): int
539
    {
540
        if (!empty($this->options['group'])) {
541
            // 支持GROUP
542
            $options = $this->getOptions();
543
            $subSql  = $this->options($options)->field('count(' . $field . ') AS think_count')->bind($this->bind)->buildSql();
544
545
            $query = $this->newQuery()->table([$subSql => '_group_count_']);
546
547
            $count = $query->aggregate('COUNT', '*');
548
        } else {
549
            $count = $this->aggregate('COUNT', $field);
550
        }
551
552
        return (int) $count;
553
    }
554
555
    /**
556
     * SUM查询
557
     * @access public
558
     * @param string|Raw $field 字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
559
     * @return float
560
     */
561
    public function sum($field): float
562
    {
563
        return $this->aggregate('SUM', $field, true);
564
    }
565
566
    /**
567
     * MIN查询
568
     * @access public
569
     * @param string|Raw $field 字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
570
     * @param bool       $force 强制转为数字类型
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
571
     * @return mixed
572
     */
573
    public function min($field, bool $force = true)
574
    {
575
        return $this->aggregate('MIN', $field, $force);
576
    }
577
578
    /**
579
     * MAX查询
580
     * @access public
581
     * @param string|Raw $field 字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
582
     * @param bool       $force 强制转为数字类型
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
583
     * @return mixed
584
     */
585
    public function max($field, bool $force = true)
586
    {
587
        return $this->aggregate('MAX', $field, $force);
588
    }
589
590
    /**
591
     * AVG查询
592
     * @access public
593
     * @param string|Raw $field 字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
594
     * @return float
595
     */
596
    public function avg($field): float
597
    {
598
        return $this->aggregate('AVG', $field, true);
599
    }
600
601
    /**
602
     * 查询SQL组装 join
603
     * @access public
604
     * @param mixed  $join      关联的表名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
605
     * @param mixed  $condition 条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
606
     * @param string $type      JOIN类型
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
607
     * @param array  $bind      参数绑定
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
608
     * @return $this
609
     */
610
    public function join($join, string $condition = null, string $type = 'INNER', array $bind = [])
611
    {
612
        $table = $this->getJoinTable($join);
613
614
        if (!empty($bind) && $condition) {
615
            $this->bindParams($condition, $bind);
616
        }
617
618
        $this->options['join'][] = [$table, strtoupper($type), $condition];
619
620
        return $this;
621
    }
622
623
    /**
624
     * LEFT JOIN
625
     * @access public
626
     * @param mixed $join      关联的表名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
627
     * @param mixed $condition 条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
628
     * @param array $bind      参数绑定
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
629
     * @return $this
630
     */
631
    public function leftJoin($join, string $condition = null, array $bind = [])
632
    {
633
        return $this->join($join, $condition, 'LEFT', $bind);
634
    }
635
636
    /**
637
     * RIGHT JOIN
638
     * @access public
639
     * @param mixed $join      关联的表名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
640
     * @param mixed $condition 条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
641
     * @param array $bind      参数绑定
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
642
     * @return $this
643
     */
644
    public function rightJoin($join, string $condition = null, array $bind = [])
645
    {
646
        return $this->join($join, $condition, 'RIGHT', $bind);
647
    }
648
649
    /**
650
     * FULL JOIN
651
     * @access public
652
     * @param mixed $join      关联的表名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
653
     * @param mixed $condition 条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
654
     * @param array $bind      参数绑定
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
655
     * @return $this
656
     */
657
    public function fullJoin($join, string $condition = null, array $bind = [])
658
    {
659
        return $this->join($join, $condition, 'FULL');
660
    }
661
662
    /**
663
     * 获取Join表名及别名 支持
664
     * ['prefix_table或者子查询'=>'alias'] 'table alias'
665
     * @access protected
666
     * @param array|string|Raw $join  JION表名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
667
     * @param string           $alias 别名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
668
     * @return string|array
669
     */
670
    protected function getJoinTable($join, &$alias = null)
671
    {
672
        if (is_array($join)) {
673
            $table = $join;
674
            $alias = array_shift($join);
675
            return $table;
676
        } elseif ($join instanceof Raw) {
677
            return $join;
678
        }
679
680
        $join = trim($join);
681
682
        if (false !== strpos($join, '(')) {
683
            // 使用子查询
684
            $table = $join;
685
        } else {
686
            // 使用别名
687
            if (strpos($join, ' ')) {
688
                // 使用别名
689
                list($table, $alias) = explode(' ', $join);
690
            } else {
691
                $table = $join;
692
                if (false === strpos($join, '.')) {
693
                    $alias = $join;
694
                }
695
            }
696
697
            if ($this->prefix && false === strpos($table, '.') && 0 !== strpos($table, $this->prefix)) {
698
                $table = $this->getTable($table);
699
            }
700
        }
701
702
        if (!empty($alias) && $table != $alias) {
703
            $table = [$table => $alias];
704
        }
705
706
        return $table;
707
    }
708
709
    /**
710
     * 查询SQL组装 union
711
     * @access public
712
     * @param mixed   $union UNION
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
713
     * @param boolean $all   是否适用UNION ALL
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
714
     * @return $this
715
     */
716
    public function union($union, bool $all = false)
717
    {
718
        $this->options['union']['type'] = $all ? 'UNION ALL' : 'UNION';
719
720
        if (is_array($union)) {
721
            $this->options['union'] = array_merge($this->options['union'], $union);
722
        } else {
723
            $this->options['union'][] = $union;
724
        }
725
726
        return $this;
727
    }
728
729
    /**
730
     * 查询SQL组装 union all
731
     * @access public
732
     * @param mixed $union UNION数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
733
     * @return $this
734
     */
735
    public function unionAll($union)
736
    {
737
        return $this->union($union, true);
738
    }
739
740
    /**
741
     * 指定查询字段 支持字段排除和指定数据表
742
     * @access public
743
     * @param mixed   $field     字段信息
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
744
     * @param boolean $except    是否排除
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
745
     * @param string  $tableName 数据表名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
746
     * @param string  $prefix    字段前缀
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
747
     * @param string  $alias     别名前缀
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
748
     * @return $this
749
     */
750
    public function field($field, bool $except = false, string $tableName = '', string $prefix = '', string $alias = '')
751
    {
752
        if (empty($field)) {
753
            return $this;
754
        } elseif ($field instanceof Raw) {
755
            $this->options['field'][] = $field;
756
            return $this;
757
        }
758
759
        if (is_string($field)) {
760
            if (preg_match('/[\<\'\"\(]/', $field)) {
761
                return $this->fieldRaw($field);
762
            }
763
764
            $field = array_map('trim', explode(',', $field));
765
        }
766
767
        if (true === $field) {
768
            // 获取全部字段
769
            $fields = $this->getTableFields($tableName);
770
            $field  = $fields ?: ['*'];
0 ignored issues
show
introduced by
$fields is an empty array, thus is always false.
Loading history...
771
        } elseif ($except) {
772
            // 字段排除
773
            $fields = $this->getTableFields($tableName);
774
            $field  = $fields ? array_diff($fields, $field) : $field;
0 ignored issues
show
introduced by
$fields is an empty array, thus is always false.
Loading history...
775
        }
776
777
        if ($tableName) {
778
            // 添加统一的前缀
779
            $prefix = $prefix ?: $tableName;
780
            foreach ($field as $key => &$val) {
781
                if (is_numeric($key) && $alias) {
782
                    $field[$prefix . '.' . $val] = $alias . $val;
783
                    unset($field[$key]);
784
                } elseif (is_numeric($key)) {
785
                    $val = $prefix . '.' . $val;
786
                }
787
            }
788
        }
789
790
        if (isset($this->options['field'])) {
791
            $field = array_merge((array) $this->options['field'], $field);
792
        }
793
794
        $this->options['field'] = array_unique($field);
795
796
        return $this;
797
    }
798
799
    /**
800
     * 表达式方式指定查询字段
801
     * @access public
802
     * @param string $field 字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
803
     * @return $this
804
     */
805
    public function fieldRaw(string $field)
806
    {
807
        $this->options['field'][] = new Raw($field);
808
809
        return $this;
810
    }
811
812
    /**
813
     * 设置数据
814
     * @access public
815
     * @param array $data 数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
816
     * @return $this
817
     */
818
    public function data(array $data)
819
    {
820
        $this->options['data'] = $data;
821
822
        return $this;
823
    }
824
825
    /**
826
     * 字段值增长
827
     * @access public
828
     * @param string  $field    字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
829
     * @param integer $step     增长值
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
830
     * @param integer $lazyTime 延时时间(s)
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
831
     * @param string  $op       INC/DEC
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
832
     * @return $this
833
     */
834
    public function inc(string $field, int $step = 1, int $lazyTime = 0, string $op = 'INC')
835
    {
836
        if ($lazyTime > 0) {
837
            // 延迟写入
838
            $condition = $this->options['where'] ?? [];
839
840
            $guid = md5($this->getTable() . '_' . $field . '_' . serialize($condition));
841
            $step = $this->connection->lazyWrite($op, $guid, $step, $lazyTime);
842
843
            if (false === $step) {
844
                return $this;
845
            }
846
847
            $op = 'INC';
848
        }
849
850
        $this->options['data'][$field] = [$op, $step];
851
852
        return $this;
853
    }
854
855
    /**
856
     * 字段值减少
857
     * @access public
858
     * @param string  $field    字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
859
     * @param integer $step     增长值
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
860
     * @param integer $lazyTime 延时时间(s)
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
861
     * @return $this
862
     */
863
    public function dec(string $field, int $step = 1, int $lazyTime = 0)
864
    {
865
        return $this->inc($field, $step, $lazyTime, 'DEC');
866
    }
867
868
    /**
869
     * 使用表达式设置数据
870
     * @access public
871
     * @param string $field 字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
872
     * @param string $value 字段值
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
873
     * @return $this
874
     */
875
    public function exp(string $field, string $value)
876
    {
877
        $this->options['data'][$field] = new Raw($value);
878
        return $this;
879
    }
880
881
    /**
882
     * 指定JOIN查询字段
883
     * @access public
884
     * @param string|array $join  数据表
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
885
     * @param string|array $field 查询字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
886
     * @param string       $on    JOIN条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
887
     * @param string       $type  JOIN类型
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
888
     * @param array        $bind  参数绑定
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
889
     * @return $this
890
     */
891
    public function view($join, $field = true, $on = null, string $type = 'INNER', array $bind = [])
892
    {
893
        $this->options['view'] = true;
894
895
        $fields = [];
896
        $table  = $this->getJoinTable($join, $alias);
897
898
        if (true === $field) {
899
            $fields = $alias . '.*';
900
        } else {
901
            if (is_string($field)) {
902
                $field = explode(',', $field);
903
            }
904
905
            foreach ($field as $key => $val) {
906
                if (is_numeric($key)) {
907
                    $fields[] = $alias . '.' . $val;
908
909
                    $this->options['map'][$val] = $alias . '.' . $val;
910
                } else {
911
                    if (preg_match('/[,=\.\'\"\(\s]/', $key)) {
912
                        $name = $key;
913
                    } else {
914
                        $name = $alias . '.' . $key;
915
                    }
916
917
                    $fields[] = $name . ' AS ' . $val;
918
919
                    $this->options['map'][$val] = $name;
920
                }
921
            }
922
        }
923
924
        $this->field($fields);
925
926
        if ($on) {
927
            $this->join($table, $on, $type, $bind);
928
        } else {
929
            $this->table($table);
930
        }
931
932
        return $this;
933
    }
934
935
    /**
936
     * 指定AND查询条件
937
     * @access public
938
     * @param mixed $field     查询字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
939
     * @param mixed $op        查询表达式
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
940
     * @param mixed $condition 查询条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
941
     * @return $this
942
     */
943
    public function where($field, $op = null, $condition = null)
944
    {
945
        if ($field instanceof $this) {
946
            $this->options['where'] = $field->getOptions('where');
947
            return $this;
948
        }
949
950
        $param = func_get_args();
951
        array_shift($param);
952
        return $this->parseWhereExp('AND', $field, $op, $condition, $param);
953
    }
954
955
    /**
956
     * 指定OR查询条件
957
     * @access public
958
     * @param mixed $field     查询字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
959
     * @param mixed $op        查询表达式
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
960
     * @param mixed $condition 查询条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
961
     * @return $this
962
     */
963
    public function whereOr($field, $op = null, $condition = null)
964
    {
965
        $param = func_get_args();
966
        array_shift($param);
967
        return $this->parseWhereExp('OR', $field, $op, $condition, $param);
968
    }
969
970
    /**
971
     * 指定XOR查询条件
972
     * @access public
973
     * @param mixed $field     查询字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
974
     * @param mixed $op        查询表达式
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
975
     * @param mixed $condition 查询条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
976
     * @return $this
977
     */
978
    public function whereXor($field, $op = null, $condition = null)
979
    {
980
        $param = func_get_args();
981
        array_shift($param);
982
        return $this->parseWhereExp('XOR', $field, $op, $condition, $param);
983
    }
984
985
    /**
986
     * 指定Null查询条件
987
     * @access public
988
     * @param mixed  $field 查询字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
989
     * @param string $logic 查询逻辑 and or xor
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
990
     * @return $this
991
     */
992
    public function whereNull(string $field, string $logic = 'AND')
993
    {
994
        return $this->parseWhereExp($logic, $field, 'NULL', null, [], true);
995
    }
996
997
    /**
998
     * 指定NotNull查询条件
999
     * @access public
1000
     * @param mixed  $field 查询字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1001
     * @param string $logic 查询逻辑 and or xor
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1002
     * @return $this
1003
     */
1004
    public function whereNotNull(string $field, string $logic = 'AND')
1005
    {
1006
        return $this->parseWhereExp($logic, $field, 'NOTNULL', null, [], true);
1007
    }
1008
1009
    /**
1010
     * 指定Exists查询条件
1011
     * @access public
1012
     * @param mixed  $condition 查询条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1013
     * @param string $logic     查询逻辑 and or xor
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1014
     * @return $this
1015
     */
1016
    public function whereExists($condition, string $logic = 'AND')
1017
    {
1018
        if (is_string($condition)) {
1019
            $condition = new Raw($condition);
1020
        }
1021
1022
        $this->options['where'][strtoupper($logic)][] = ['', 'EXISTS', $condition];
1023
        return $this;
1024
    }
1025
1026
    /**
1027
     * 指定NotExists查询条件
1028
     * @access public
1029
     * @param mixed  $condition 查询条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1030
     * @param string $logic     查询逻辑 and or xor
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1031
     * @return $this
1032
     */
1033
    public function whereNotExists($condition, string $logic = 'AND')
1034
    {
1035
        if (is_string($condition)) {
1036
            $condition = new Raw($condition);
1037
        }
1038
1039
        $this->options['where'][strtoupper($logic)][] = ['', 'NOT EXISTS', $condition];
1040
        return $this;
1041
    }
1042
1043
    /**
1044
     * 指定In查询条件
1045
     * @access public
1046
     * @param mixed  $field     查询字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1047
     * @param mixed  $condition 查询条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1048
     * @param string $logic     查询逻辑 and or xor
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1049
     * @return $this
1050
     */
1051
    public function whereIn(string $field, $condition, string $logic = 'AND')
1052
    {
1053
        return $this->parseWhereExp($logic, $field, 'IN', $condition, [], true);
1054
    }
1055
1056
    /**
1057
     * 指定NotIn查询条件
1058
     * @access public
1059
     * @param mixed  $field     查询字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1060
     * @param mixed  $condition 查询条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1061
     * @param string $logic     查询逻辑 and or xor
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1062
     * @return $this
1063
     */
1064
    public function whereNotIn(string $field, $condition, string $logic = 'AND')
1065
    {
1066
        return $this->parseWhereExp($logic, $field, 'NOT IN', $condition, [], true);
1067
    }
1068
1069
    /**
1070
     * 指定Like查询条件
1071
     * @access public
1072
     * @param mixed  $field     查询字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1073
     * @param mixed  $condition 查询条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1074
     * @param string $logic     查询逻辑 and or xor
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1075
     * @return $this
1076
     */
1077
    public function whereLike(string $field, $condition, string $logic = 'AND')
1078
    {
1079
        return $this->parseWhereExp($logic, $field, 'LIKE', $condition, [], true);
1080
    }
1081
1082
    /**
1083
     * 指定NotLike查询条件
1084
     * @access public
1085
     * @param mixed  $field     查询字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1086
     * @param mixed  $condition 查询条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1087
     * @param string $logic     查询逻辑 and or xor
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1088
     * @return $this
1089
     */
1090
    public function whereNotLike(string $field, $condition, string $logic = 'AND')
1091
    {
1092
        return $this->parseWhereExp($logic, $field, 'NOT LIKE', $condition, [], true);
1093
    }
1094
1095
    /**
1096
     * 指定Between查询条件
1097
     * @access public
1098
     * @param mixed  $field     查询字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1099
     * @param mixed  $condition 查询条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1100
     * @param string $logic     查询逻辑 and or xor
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1101
     * @return $this
1102
     */
1103
    public function whereBetween(string $field, $condition, string $logic = 'AND')
1104
    {
1105
        return $this->parseWhereExp($logic, $field, 'BETWEEN', $condition, [], true);
1106
    }
1107
1108
    /**
1109
     * 指定NotBetween查询条件
1110
     * @access public
1111
     * @param mixed  $field     查询字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1112
     * @param mixed  $condition 查询条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1113
     * @param string $logic     查询逻辑 and or xor
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1114
     * @return $this
1115
     */
1116
    public function whereNotBetween(string $field, $condition, string $logic = 'AND')
1117
    {
1118
        return $this->parseWhereExp($logic, $field, 'NOT BETWEEN', $condition, [], true);
1119
    }
1120
1121
    /**
1122
     * 指定FIND_IN_SET查询条件
1123
     * @access public
1124
     * @param mixed  $field     查询字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1125
     * @param mixed  $condition 查询条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1126
     * @param string $logic     查询逻辑 and or xor
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1127
     * @return $this
1128
     */
1129
    public function whereFindInSet(string $field, $condition, string $logic = 'AND')
1130
    {
1131
        return $this->parseWhereExp($logic, $field, 'FIND IN SET', $condition, [], true);
1132
    }
1133
1134
    /**
1135
     * 比较两个字段
1136
     * @access public
1137
     * @param string $field1   查询字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1138
     * @param string $operator 比较操作符
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1139
     * @param string $field2   比较字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1140
     * @param string $logic    查询逻辑 and or xor
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1141
     * @return $this
1142
     */
1143
    public function whereColumn(string $field1, string $operator, string $field2 = null, string $logic = 'AND')
1144
    {
1145
        if (is_null($field2)) {
1146
            $field2   = $operator;
1147
            $operator = '=';
1148
        }
1149
1150
        return $this->parseWhereExp($logic, $field1, 'COLUMN', [$operator, $field2], [], true);
1151
    }
1152
1153
    /**
1154
     * 设置软删除字段及条件
1155
     * @access public
1156
     * @param string $field     查询字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1157
     * @param mixed  $condition 查询条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1158
     * @return $this
1159
     */
1160
    public function useSoftDelete(string $field, $condition = null)
1161
    {
1162
        if ($field) {
1163
            $this->options['soft_delete'] = [$field, $condition];
1164
        }
1165
1166
        return $this;
1167
    }
1168
1169
    /**
1170
     * 指定Exp查询条件
1171
     * @access public
1172
     * @param mixed  $field 查询字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1173
     * @param string $where 查询条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1174
     * @param array  $bind  参数绑定
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1175
     * @param string $logic 查询逻辑 and or xor
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1176
     * @return $this
1177
     */
1178
    public function whereExp(string $field, string $where, array $bind = [], string $logic = 'AND')
1179
    {
1180
        if (!empty($bind)) {
1181
            $this->bindParams($where, $bind);
1182
        }
1183
1184
        $this->options['where'][$logic][] = [$field, 'EXP', new Raw($where)];
1185
1186
        return $this;
1187
    }
1188
1189
    /**
1190
     * 指定字段Raw查询
1191
     * @access public
1192
     * @param string $field     查询字段表达式
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1193
     * @param mixed  $op        查询表达式
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1194
     * @param string $condition 查询条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1195
     * @param string $logic     查询逻辑 and or xor
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1196
     * @return $this
1197
     */
1198
    public function whereFieldRaw(string $field, $op, $condition = null, string $logic = 'AND')
1199
    {
1200
        if (is_null($condition)) {
1201
            $condition = $op;
1202
            $op        = '=';
1203
        }
1204
1205
        $this->options['where'][$logic][] = [new Raw($field), $op, $condition];
1206
        return $this;
1207
    }
1208
1209
    /**
1210
     * 指定表达式查询条件
1211
     * @access public
1212
     * @param string $where 查询条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1213
     * @param array  $bind  参数绑定
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1214
     * @param string $logic 查询逻辑 and or xor
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1215
     * @return $this
1216
     */
1217
    public function whereRaw(string $where, array $bind = [], string $logic = 'AND')
1218
    {
1219
        if (!empty($bind)) {
1220
            $this->bindParams($where, $bind);
1221
        }
1222
1223
        $this->options['where'][$logic][] = new Raw($where);
1224
1225
        return $this;
1226
    }
1227
1228
    /**
1229
     * 指定表达式查询条件 OR
1230
     * @access public
1231
     * @param string $where 查询条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1232
     * @param array  $bind  参数绑定
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1233
     * @return $this
1234
     */
1235
    public function whereOrRaw(string $where, array $bind = [])
1236
    {
1237
        return $this->whereRaw($where, $bind, 'OR');
1238
    }
1239
1240
    /**
1241
     * 分析查询表达式
1242
     * @access protected
1243
     * @param string $logic     查询逻辑 and or xor
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1244
     * @param mixed  $field     查询字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1245
     * @param mixed  $op        查询表达式
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1246
     * @param mixed  $condition 查询条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1247
     * @param array  $param     查询参数
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1248
     * @param bool   $strict    严格模式
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1249
     * @return $this
1250
     */
1251
    protected function parseWhereExp(string $logic, $field, $op, $condition, array $param = [], bool $strict = false)
1252
    {
1253
        $logic = strtoupper($logic);
1254
1255
        if (is_string($field) && !empty($this->options['via']) && false === strpos($field, '.')) {
1256
            $field = $this->options['via'] . '.' . $field;
1257
        }
1258
1259
        if ($field instanceof Raw) {
1260
            return $this->whereRaw($field, is_array($op) ? $op : [], $logic);
1261
        } elseif ($strict) {
1262
            // 使用严格模式查询
1263
            if ('=' == $op) {
1264
                $where = $this->whereEq($field, $condition);
1265
            } else {
1266
                $where = [$field, $op, $condition, $logic];
1267
            }
1268
        } elseif (is_array($field)) {
1269
            // 解析数组批量查询
1270
            return $this->parseArrayWhereItems($field, $logic);
1271
        } elseif ($field instanceof Closure) {
1272
            $where = $field;
1273
        } elseif (is_string($field)) {
1274
            if (preg_match('/[,=\<\'\"\(\s]/', $field)) {
1275
                return $this->whereRaw($field, is_array($op) ? $op : [], $logic);
1276
            } elseif (is_string($op) && strtolower($op) == 'exp') {
1277
                $bind = isset($param[2]) && is_array($param[2]) ? $param[2] : [];
1278
                return $this->whereExp($field, $condition, $bind, $logic);
1279
            }
1280
1281
            $where = $this->parseWhereItem($logic, $field, $op, $condition, $param);
1282
        }
1283
1284
        if (!empty($where)) {
1285
            $this->options['where'][$logic][] = $where;
1286
        }
1287
1288
        return $this;
1289
    }
1290
1291
    /**
1292
     * 分析查询表达式
1293
     * @access protected
1294
     * @param string $logic     查询逻辑 and or xor
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1295
     * @param mixed  $field     查询字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1296
     * @param mixed  $op        查询表达式
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1297
     * @param mixed  $condition 查询条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1298
     * @param array  $param     查询参数
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1299
     * @return array
1300
     */
1301
    protected function parseWhereItem(string $logic, $field, $op, $condition, array $param = []): array
1302
    {
1303
        if (is_array($op)) {
1304
            // 同一字段多条件查询
1305
            array_unshift($param, $field);
1306
            $where = $param;
1307
        } elseif ($field && is_null($condition)) {
1308
            if (is_string($op) && in_array(strtoupper($op), ['NULL', 'NOTNULL', 'NOT NULL'], true)) {
1309
                // null查询
1310
                $where = [$field, $op, ''];
1311
            } elseif ('=' === $op || is_null($op)) {
1312
                $where = [$field, 'NULL', ''];
1313
            } elseif ('<>' === $op) {
1314
                $where = [$field, 'NOTNULL', ''];
1315
            } else {
1316
                // 字段相等查询
1317
                $where = $this->whereEq($field, $op);
1318
            }
1319
        } elseif (in_array(strtoupper($op), ['EXISTS', 'NOT EXISTS', 'NOTEXISTS'], true)) {
1320
            $where = [$field, $op, is_string($condition) ? new Raw($condition) : $condition];
1321
        } else {
1322
            $where = $field ? [$field, $op, $condition, $param[2] ?? null] : [];
1323
        }
1324
1325
        return $where;
1326
    }
1327
1328
    /**
1329
     * 相等查询的主键处理
1330
     * @access protected
1331
     * @param string $field 字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1332
     * @param mixed  $value 字段值
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1333
     * @return array
1334
     */
1335
    protected function whereEq(string $field, $value): array
1336
    {
1337
        $where = [$field, '=', $value];
1338
        if ($this->getPk() == $field) {
1339
            $this->options['key'] = $value;
1340
        }
1341
1342
        return $where;
1343
    }
1344
1345
    /**
1346
     * 数组批量查询
1347
     * @access protected
1348
     * @param array  $field 批量查询
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1349
     * @param string $logic 查询逻辑 and or xor
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1350
     * @return $this
1351
     */
1352
    protected function parseArrayWhereItems(array $field, string $logic)
1353
    {
1354
        if (key($field) !== 0) {
1355
            $where = [];
1356
            foreach ($field as $key => $val) {
1357
                if ($val instanceof Raw) {
1358
                    $where[] = [$key, 'exp', $val];
1359
                } else {
1360
                    $where[] = is_null($val) ? [$key, 'NULL', ''] : [$key, is_array($val) ? 'IN' : '=', $val];
1361
                }
1362
            }
1363
        } else {
1364
            // 数组批量查询
1365
            $where = $field;
1366
        }
1367
1368
        if (!empty($where)) {
1369
            $this->options['where'][$logic] = isset($this->options['where'][$logic]) ? array_merge($this->options['where'][$logic], $where) : $where;
1370
        }
1371
1372
        return $this;
1373
    }
1374
1375
    /**
1376
     * 去除某个查询条件
1377
     * @access public
1378
     * @param string $field 查询字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1379
     * @param string $logic 查询逻辑 and or xor
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1380
     * @return $this
1381
     */
1382
    public function removeWhereField(string $field, string $logic = 'AND')
1383
    {
1384
        $logic = strtoupper($logic);
1385
1386
        if (isset($this->options['where'][$logic])) {
1387
            foreach ($this->options['where'][$logic] as $key => $val) {
1388
                if (is_array($val) && $val[0] == $field) {
1389
                    unset($this->options['where'][$logic][$key]);
1390
                }
1391
            }
1392
        }
1393
1394
        return $this;
1395
    }
1396
1397
    /**
1398
     * 去除查询参数
1399
     * @access public
1400
     * @param string $option 参数名 留空去除所有参数
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1401
     * @return $this
1402
     */
1403
    public function removeOption(string $option = '')
1404
    {
1405
        if ('' === $option) {
1406
            $this->options = [];
1407
            $this->bind    = [];
1408
        } elseif (isset($this->options[$option])) {
1409
            unset($this->options[$option]);
1410
        }
1411
1412
        return $this;
1413
    }
1414
1415
    /**
1416
     * 条件查询
1417
     * @access public
1418
     * @param mixed         $condition 满足条件(支持闭包)
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1419
     * @param Closure|array $query     满足条件后执行的查询表达式(闭包或数组)
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1420
     * @param Closure|array $otherwise 不满足条件后执行
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1421
     * @return $this
1422
     */
1423
    public function when($condition, $query, $otherwise = null)
1424
    {
1425
        if ($condition instanceof Closure) {
1426
            $condition = $condition($this);
1427
        }
1428
1429
        if ($condition) {
1430
            if ($query instanceof Closure) {
1431
                $query($this, $condition);
1432
            } elseif (is_array($query)) {
0 ignored issues
show
introduced by
The condition is_array($query) is always true.
Loading history...
1433
                $this->where($query);
1434
            }
1435
        } elseif ($otherwise) {
1436
            if ($otherwise instanceof Closure) {
1437
                $otherwise($this, $condition);
1438
            } elseif (is_array($otherwise)) {
0 ignored issues
show
introduced by
The condition is_array($otherwise) is always true.
Loading history...
1439
                $this->where($otherwise);
1440
            }
1441
        }
1442
1443
        return $this;
1444
    }
1445
1446
    /**
1447
     * 指定查询数量
1448
     * @access public
1449
     * @param int $offset 起始位置
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1450
     * @param int $length 查询数量
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1451
     * @return $this
1452
     */
1453
    public function limit(int $offset, int $length = null)
1454
    {
1455
        $this->options['limit'] = $offset . ($length ? ',' . $length : '');
1456
1457
        return $this;
1458
    }
1459
1460
    /**
1461
     * 指定分页
1462
     * @access public
1463
     * @param int $page     页数
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1464
     * @param int $listRows 每页数量
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1465
     * @return $this
1466
     */
1467
    public function page(int $page, int $listRows = null)
1468
    {
1469
        $this->options['page'] = [$page, $listRows];
1470
1471
        return $this;
1472
    }
1473
1474
    /**
1475
     * 分页查询
1476
     * @access public
1477
     * @param int|array $listRows 每页数量 数组表示配置参数
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1478
     * @param int|bool  $simple   是否简洁模式或者总记录数
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1479
     * @param array     $config   配置参数
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1480
     * @return Paginator
1481
     * @throws DbException
1482
     */
1483
    public function paginate($listRows = null, $simple = false, $config = [])
1484
    {
1485
        if (is_int($simple)) {
1486
            $total  = $simple;
1487
            $simple = false;
1488
        }
1489
1490
        $defaultConfig = [
1491
            'query'     => [], //url额外参数
1492
            'fragment'  => '', //url锚点
1493
            'var_page'  => 'page', //分页变量
1494
            'list_rows' => 15, //每页数量
1495
        ];
1496
1497
        if (is_array($listRows)) {
1498
            $config   = array_merge($defaultConfig, $listRows);
1499
            $listRows = intval($config['list_rows']);
1500
        } else {
1501
            $config   = array_merge($defaultConfig, $config);
1502
            $listRows = intval($listRows ?: $config['list_rows']);
1503
        }
1504
1505
        $page = isset($config['page']) ? (int) $config['page'] : Paginator::getCurrentPage($config['var_page']);
1506
1507
        $page = $page < 1 ? 1 : $page;
1508
1509
        $config['path'] = $config['path'] ?? Paginator::getCurrentPath();
1510
1511
        if (!isset($total) && !$simple) {
1512
            $options = $this->getOptions();
1513
1514
            unset($this->options['order'], $this->options['limit'], $this->options['page'], $this->options['field']);
1515
1516
            $bind    = $this->bind;
1517
            $total   = $this->count();
1518
            $results = $this->options($options)->bind($bind)->page($page, $listRows)->select();
1519
        } elseif ($simple) {
1520
            $results = $this->limit(($page - 1) * $listRows, $listRows + 1)->select();
1521
            $total   = null;
1522
        } else {
1523
            $results = $this->page($page, $listRows)->select();
1524
        }
1525
1526
        $this->removeOption('limit');
1527
        $this->removeOption('page');
1528
1529
        return Paginator::make($results, $listRows, $page, $total, $simple, $config);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $total does not seem to be defined for all execution paths leading up to this point.
Loading history...
1530
    }
1531
1532
    /**
1533
     * 表达式方式指定当前操作的数据表
1534
     * @access public
1535
     * @param mixed $table 表名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1536
     * @return $this
1537
     */
1538
    public function tableRaw(string $table)
1539
    {
1540
        $this->options['table'] = new Raw($table);
1541
1542
        return $this;
1543
    }
1544
1545
    /**
1546
     * 指定当前操作的数据表
1547
     * @access public
1548
     * @param mixed $table 表名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1549
     * @return $this
1550
     */
1551
    public function table($table)
1552
    {
1553
        if (is_string($table)) {
1554
            if (strpos($table, ')')) {
1555
                // 子查询
1556
            } elseif (false === strpos($table, ',')) {
1557
                if (strpos($table, ' ')) {
1558
                    list($item, $alias) = explode(' ', $table);
1559
                    $table = [];
1560
                    $this->alias([$item => $alias]);
1561
                    $table[$item] = $alias;
1562
                }
1563
            } else {
1564
                $tables = explode(',', $table);
1565
                $table  = [];
1566
1567
                foreach ($tables as $item) {
1568
                    $item = trim($item);
1569
                    if (strpos($item, ' ')) {
1570
                        list($item, $alias) = explode(' ', $item);
1571
                        $this->alias([$item => $alias]);
1572
                        $table[$item] = $alias;
1573
                    } else {
1574
                        $table[] = $item;
1575
                    }
1576
                }
1577
            }
1578
        } elseif (is_array($table)) {
1579
            $tables = $table;
1580
            $table  = [];
1581
1582
            foreach ($tables as $key => $val) {
1583
                if (is_numeric($key)) {
1584
                    $table[] = $val;
1585
                } else {
1586
                    $this->alias([$key => $val]);
1587
                    $table[$key] = $val;
1588
                }
1589
            }
1590
        }
1591
1592
        $this->options['table'] = $table;
1593
1594
        return $this;
1595
    }
1596
1597
    /**
1598
     * USING支持 用于多表删除
1599
     * @access public
1600
     * @param mixed $using USING
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1601
     * @return $this
1602
     */
1603
    public function using($using)
1604
    {
1605
        $this->options['using'] = $using;
1606
        return $this;
1607
    }
1608
1609
    /**
1610
     * 存储过程调用
1611
     * @access public
1612
     * @param bool $procedure 是否为存储过程查询
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1613
     * @return $this
1614
     */
1615
    public function procedure($procedure = true)
1616
    {
1617
        $this->options['procedure'] = $procedure;
1618
        return $this;
1619
    }
1620
1621
    /**
1622
     * 是否允许返回空数据(或空模型)
1623
     * @access public
1624
     * @param bool $allowEmpty 是否允许为空
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1625
     * @return $this
1626
     */
1627
    public function allowEmpty(bool $allowEmpty = true)
1628
    {
1629
        $this->options['allow_empty'] = $allowEmpty;
1630
        return $this;
1631
    }
1632
1633
    /**
1634
     * 指定排序 order('id','desc') 或者 order(['id'=>'desc','create_time'=>'desc'])
1635
     * @access public
1636
     * @param string|array|Raw $field 排序字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1637
     * @param string           $order 排序
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1638
     * @return $this
1639
     */
1640
    public function order($field, string $order = '')
1641
    {
1642
        if (empty($field)) {
1643
            return $this;
1644
        } elseif ($field instanceof Raw) {
1645
            $this->options['order'][] = $field;
1646
            return $this;
1647
        }
1648
1649
        if (is_string($field)) {
1650
            if (!empty($this->options['via'])) {
1651
                $field = $this->options['via'] . '.' . $field;
1652
            }
1653
            if (strpos($field, ',')) {
1654
                $field = array_map('trim', explode(',', $field));
1655
            } else {
1656
                $field = empty($order) ? $field : [$field => $order];
1657
            }
1658
        } elseif (!empty($this->options['via'])) {
1659
            foreach ($field as $key => $val) {
1660
                if (is_numeric($key)) {
1661
                    $field[$key] = $this->options['via'] . '.' . $val;
1662
                } else {
1663
                    $field[$this->options['via'] . '.' . $key] = $val;
1664
                    unset($field[$key]);
1665
                }
1666
            }
1667
        }
1668
1669
        if (!isset($this->options['order'])) {
1670
            $this->options['order'] = [];
1671
        }
1672
1673
        if (is_array($field)) {
1674
            $this->options['order'] = array_merge($this->options['order'], $field);
1675
        } else {
1676
            $this->options['order'][] = $field;
1677
        }
1678
1679
        return $this;
1680
    }
1681
1682
    /**
1683
     * 表达式方式指定Field排序
1684
     * @access public
1685
     * @param string $field 排序字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1686
     * @param array  $bind  参数绑定
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1687
     * @return $this
1688
     */
1689
    public function orderRaw(string $field, array $bind = [])
1690
    {
1691
        if (!empty($bind)) {
1692
            $this->bindParams($field, $bind);
1693
        }
1694
1695
        $this->options['order'][] = new Raw($field);
1696
1697
        return $this;
1698
    }
1699
1700
    /**
1701
     * 指定Field排序 orderField('id',[1,2,3],'desc')
1702
     * @access public
1703
     * @param string $field  排序字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1704
     * @param array  $values 排序值
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1705
     * @param string $order  排序 desc/asc
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1706
     * @return $this
1707
     */
1708
    public function orderField(string $field, array $values, string $order = '')
1709
    {
1710
        if (!empty($values)) {
1711
            $values['sort'] = $order;
1712
1713
            $this->options['order'][$field] = $values;
1714
        }
1715
1716
        return $this;
1717
    }
1718
1719
    /**
1720
     * 随机排序
1721
     * @access public
1722
     * @return $this
1723
     */
1724
    public function orderRand()
1725
    {
1726
        $this->options['order'][] = '[rand]';
1727
        return $this;
1728
    }
1729
1730
    /**
1731
     * 查询缓存
1732
     * @access public
1733
     * @param mixed             $key    缓存key
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1734
     * @param integer|\DateTime $expire 缓存有效期
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1735
     * @param string            $tag    缓存标签
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1736
     * @return $this
1737
     */
1738
    public function cache($key = true, $expire = null, $tag = null)
1739
    {
1740
        if (false === $key) {
1741
            return $this;
1742
        }
1743
1744
        if ($key instanceof \DateTimeInterface || (is_int($key) && is_null($expire))) {
1745
            $expire = $key;
1746
            $key    = true;
1747
        }
1748
1749
        $this->options['cache'] = [$key, $expire, $tag];
1750
1751
        return $this;
1752
    }
1753
1754
    /**
1755
     * 指定group查询
1756
     * @access public
1757
     * @param string|array $group GROUP
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1758
     * @return $this
1759
     */
1760
    public function group($group)
1761
    {
1762
        $this->options['group'] = $group;
1763
        return $this;
1764
    }
1765
1766
    /**
1767
     * 指定having查询
1768
     * @access public
1769
     * @param string $having having
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1770
     * @return $this
1771
     */
1772
    public function having(string $having)
1773
    {
1774
        $this->options['having'] = $having;
1775
        return $this;
1776
    }
1777
1778
    /**
1779
     * 指定查询lock
1780
     * @access public
1781
     * @param bool|string $lock 是否lock
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1782
     * @return $this
1783
     */
1784
    public function lock($lock = false)
1785
    {
1786
        $this->options['lock'] = $lock;
1787
1788
        if ($lock) {
1789
            $this->options['master'] = true;
1790
        }
1791
1792
        return $this;
1793
    }
1794
1795
    /**
1796
     * 指定distinct查询
1797
     * @access public
1798
     * @param bool $distinct 是否唯一
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1799
     * @return $this
1800
     */
1801
    public function distinct(bool $distinct = true)
1802
    {
1803
        $this->options['distinct'] = $distinct;
1804
        return $this;
1805
    }
1806
1807
    /**
1808
     * 指定数据表别名
1809
     * @access public
1810
     * @param array|string $alias 数据表别名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1811
     * @return $this
1812
     */
1813
    public function alias($alias)
1814
    {
1815
        if (is_array($alias)) {
1816
            $this->options['alias'] = $alias;
1817
        } else {
1818
            $table = $this->getTable();
1819
1820
            $this->options['alias'][$table] = $alias;
1821
        }
1822
1823
        return $this;
1824
    }
1825
1826
    /**
1827
     * 指定强制索引
1828
     * @access public
1829
     * @param string $force 索引名称
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1830
     * @return $this
1831
     */
1832
    public function force(string $force)
1833
    {
1834
        $this->options['force'] = $force;
1835
        return $this;
1836
    }
1837
1838
    /**
1839
     * 查询注释
1840
     * @access public
1841
     * @param string $comment 注释
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1842
     * @return $this
1843
     */
1844
    public function comment(string $comment)
1845
    {
1846
        $this->options['comment'] = $comment;
1847
        return $this;
1848
    }
1849
1850
    /**
1851
     * 获取执行的SQL语句而不进行实际的查询
1852
     * @access public
1853
     * @param bool $fetch 是否返回sql
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1854
     * @return $this|Fetch
1855
     */
1856
    public function fetchSql(bool $fetch = true)
1857
    {
1858
        $this->options['fetch_sql'] = $fetch;
1859
1860
        if ($fetch) {
1861
            return new Fetch($this);
1862
        }
1863
1864
        return $this;
1865
    }
1866
1867
    /**
1868
     * 设置是否返回数据集对象
1869
     * @access public
1870
     * @param bool|string $collection 是否返回数据集对象
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1871
     * @return $this
1872
     */
1873
    public function fetchCollection($collection = true)
1874
    {
1875
        $this->options['collection'] = $collection;
1876
        return $this;
1877
    }
1878
1879
    /**
1880
     * 设置是否返回数组
1881
     * @access public
1882
     * @param bool $asArray 是否返回数组
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1883
     * @return $this
1884
     */
1885
    public function fetchArray(bool $asArray = true)
1886
    {
1887
        $this->options['array'] = $asArray;
1888
        return $this;
1889
    }
1890
1891
    /**
1892
     * 设置从主服务器读取数据
1893
     * @access public
1894
     * @param bool $readMaster 是否从主服务器读取
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1895
     * @return $this
1896
     */
1897
    public function master(bool $readMaster = true)
1898
    {
1899
        $this->options['master'] = $readMaster;
1900
        return $this;
1901
    }
1902
1903
    /**
1904
     * 设置后续从主库读取数据
1905
     * @access public
1906
     * @param bool $all 是否所有表有效
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1907
     * @return $this
1908
     */
1909
    public function readMaster(bool $all = false)
1910
    {
1911
        $table = $all ? '*' : $this->getTable();
1912
1913
        $this->db->readMaster($table);
1914
1915
        return $this;
1916
    }
1917
1918
    /**
1919
     * 设置是否严格检查字段名
1920
     * @access public
1921
     * @param bool $strict 是否严格检查字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1922
     * @return $this
1923
     */
1924
    public function strict(bool $strict = true)
1925
    {
1926
        $this->options['strict'] = $strict;
1927
        return $this;
1928
    }
1929
1930
    /**
1931
     * 设置查询数据不存在是否抛出异常
1932
     * @access public
1933
     * @param bool $fail 数据不存在是否抛出异常
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1934
     * @return $this
1935
     */
1936
    public function failException(bool $fail = true)
1937
    {
1938
        $this->options['fail'] = $fail;
1939
        return $this;
1940
    }
1941
1942
    /**
1943
     * 设置自增序列名
1944
     * @access public
1945
     * @param string $sequence 自增序列名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1946
     * @return $this
1947
     */
1948
    public function sequence(string $sequence = null)
1949
    {
1950
        $this->options['sequence'] = $sequence;
1951
        return $this;
1952
    }
1953
1954
    /**
1955
     * 设置是否REPLACE
1956
     * @access public
1957
     * @param bool $replace 是否使用REPLACE写入数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1958
     * @return $this
1959
     */
1960
    public function replace(bool $replace = true)
1961
    {
1962
        $this->options['replace'] = $replace;
1963
        return $this;
1964
    }
1965
1966
    /**
1967
     * 设置当前查询所在的分区
1968
     * @access public
1969
     * @param string|array $partition 分区名称
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1970
     * @return $this
1971
     */
1972
    public function partition($partition)
1973
    {
1974
        $this->options['partition'] = $partition;
1975
        return $this;
1976
    }
1977
1978
    /**
1979
     * 设置DUPLICATE
1980
     * @access public
1981
     * @param array|string|Raw $duplicate DUPLICATE信息
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1982
     * @return $this
1983
     */
1984
    public function duplicate($duplicate)
1985
    {
1986
        $this->options['duplicate'] = $duplicate;
1987
        return $this;
1988
    }
1989
1990
    /**
1991
     * 设置查询的额外参数
1992
     * @access public
1993
     * @param string $extra 额外信息
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1994
     * @return $this
1995
     */
1996
    public function extra(string $extra)
1997
    {
1998
        $this->options['extra'] = $extra;
1999
        return $this;
2000
    }
2001
2002
    /**
2003
     * 设置需要隐藏的输出属性
2004
     * @access public
2005
     * @param array $hidden 需要隐藏的字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2006
     * @return $this
2007
     */
2008
    public function hidden(array $hidden)
2009
    {
2010
        $this->options['hidden'] = $hidden;
2011
        return $this;
2012
    }
2013
2014
    /**
2015
     * 设置需要输出的属性
2016
     * @access public
2017
     * @param array $visible 需要输出的属性
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2018
     * @return $this
2019
     */
2020
    public function visible(array $visible)
2021
    {
2022
        $this->options['visible'] = $visible;
2023
        return $this;
2024
    }
2025
2026
    /**
2027
     * 设置需要追加输出的属性
2028
     * @access public
2029
     * @param array $append 需要追加的属性
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2030
     * @return $this
2031
     */
2032
    public function append(array $append)
2033
    {
2034
        $this->options['append'] = $append;
2035
        return $this;
2036
    }
2037
2038
    /**
2039
     * 设置JSON字段信息
2040
     * @access public
2041
     * @param array $json  JSON字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2042
     * @param bool  $assoc 是否取出数组
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2043
     * @return $this
2044
     */
2045
    public function json(array $json = [], bool $assoc = false)
2046
    {
2047
        $this->options['json']       = $json;
2048
        $this->options['json_assoc'] = $assoc;
2049
        return $this;
2050
    }
2051
2052
    /**
0 ignored issues
show
Coding Style introduced by
Parameter ...$args should have a doc-comment as per coding-style.
Loading history...
2053
     * 添加查询范围
2054
     * @access public
2055
     * @param array|string|Closure $scope 查询范围定义
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2056
     * @param array                $args  参数
1 ignored issue
show
Coding Style introduced by
Doc comment for parameter $args does not match actual variable name ...$args
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2057
     * @return $this
2058
     */
2059
    public function scope($scope, ...$args)
2060
    {
2061
        // 查询范围的第一个参数始终是当前查询对象
2062
        array_unshift($args, $this);
2063
2064
        if ($scope instanceof Closure) {
2065
            call_user_func_array($scope, $args);
2066
            return $this;
2067
        }
2068
2069
        if (is_string($scope)) {
2070
            $scope = explode(',', $scope);
2071
        }
2072
2073
        if ($this->model) {
2074
            // 检查模型类的查询范围方法
2075
            foreach ($scope as $name) {
2076
                $method = 'scope' . trim($name);
2077
2078
                if (method_exists($this->model, $method)) {
2079
                    call_user_func_array([$this->model, $method], $args);
2080
                }
2081
            }
2082
        }
2083
2084
        return $this;
2085
    }
2086
2087
    /**
2088
     * 指定数据表主键
2089
     * @access public
2090
     * @param string $pk 主键
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2091
     * @return $this
2092
     */
2093
    public function pk(string $pk)
2094
    {
2095
        $this->pk = $pk;
2096
        return $this;
2097
    }
2098
2099
    /**
2100
     * 添加日期或者时间查询规则
2101
     * @access public
2102
     * @param string       $name 时间表达式
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2103
     * @param string|array $rule 时间范围
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2104
     * @return $this
2105
     */
2106
    public function timeRule(string $name, $rule)
2107
    {
2108
        $this->timeRule[$name] = $rule;
2109
        return $this;
2110
    }
2111
2112
    /**
2113
     * 查询日期或者时间
2114
     * @access public
2115
     * @param string       $field 日期字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2116
     * @param string       $op    比较运算符或者表达式
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2117
     * @param string|array $range 比较范围
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2118
     * @param string       $logic AND OR
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2119
     * @return $this
2120
     */
2121
    public function whereTime(string $field, string $op, $range = null, string $logic = 'AND')
2122
    {
2123
        if (is_null($range) && isset($this->timeRule[$op])) {
2124
            $range = $this->timeRule[$op];
2125
            $op    = 'between';
2126
        }
2127
2128
        return $this->parseWhereExp($logic, $field, strtolower($op) . ' time', $range, [], true);
2129
    }
2130
2131
    /**
2132
     * 查询某个时间间隔数据
2133
     * @access protected
2134
     * @param string $field    日期字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2135
     * @param string $start    开始时间
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2136
     * @param string $interval 时间间隔单位
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2137
     * @param string $logic    AND OR
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2138
     * @return $this
2139
     */
2140
    protected function whereTimeInterval(string $field, string $start, string $interval = 'day', string $logic = 'AND')
2141
    {
2142
        $startTime = strtotime($start);
2143
        $endTime   = strtotime('+1 ' . $interval, $startTime);
2144
2145
        return $this->whereTime($field, 'between', [$startTime, $endTime], $logic);
2146
    }
2147
2148
    /**
2149
     * 查询月数据 whereMonth('time_field', '2018-1')
2150
     * @access public
2151
     * @param string $field 日期字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2152
     * @param string $month 月份信息
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2153
     * @param string $logic AND OR
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2154
     * @return $this
2155
     */
2156
    public function whereMonth(string $field, string $month = 'this month', string $logic = 'AND')
2157
    {
2158
        if (in_array($month, ['this month', 'last month'])) {
2159
            $month = date('Y-m', strtotime($month));
2160
        }
2161
2162
        return $this->whereTimeInterval($field, $month, 'month', $logic);
2163
    }
2164
2165
    /**
2166
     * 查询年数据 whereYear('time_field', '2018')
2167
     * @access public
2168
     * @param string $field 日期字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2169
     * @param string $year  年份信息
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2170
     * @param string $logic AND OR
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2171
     * @return $this
2172
     */
2173
    public function whereYear(string $field, string $year = 'this year', string $logic = 'AND')
2174
    {
2175
        if (in_array($year, ['this year', 'last year'])) {
2176
            $year = date('Y', strtotime($year));
2177
        }
2178
2179
        return $this->whereTimeInterval($field, $year . '-1-1', 'year', $logic);
2180
    }
2181
2182
    /**
2183
     * 查询日数据 whereDay('time_field', '2018-1-1')
2184
     * @access public
2185
     * @param string $field 日期字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2186
     * @param string $day   日期信息
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2187
     * @param string $logic AND OR
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2188
     * @return $this
2189
     */
2190
    public function whereDay(string $field, string $day = 'today', string $logic = 'AND')
2191
    {
2192
        if (in_array($day, ['today', 'yesterday'])) {
2193
            $day = date('Y-m-d', strtotime($day));
2194
        }
2195
2196
        return $this->whereTimeInterval($field, $day, 'day', $logic);
2197
    }
2198
2199
    /**
2200
     * 查询日期或者时间范围 whereBetweenTime('time_field', '2018-1-1','2018-1-15')
2201
     * @access public
2202
     * @param string     $field     日期字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2203
     * @param string|int $startTime 开始时间
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2204
     * @param string|int $endTime   结束时间
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2205
     * @param string     $logic     AND OR
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2206
     * @return $this
2207
     */
2208
    public function whereBetweenTime(string $field, $startTime, $endTime, string $logic = 'AND')
2209
    {
2210
        return $this->whereTime($field, 'between', [$startTime, $endTime], $logic);
2211
    }
2212
2213
    /**
2214
     * 查询日期或者时间范围 whereNotBetweenTime('time_field', '2018-1-1','2018-1-15')
2215
     * @access public
2216
     * @param string     $field     日期字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2217
     * @param string|int $startTime 开始时间
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2218
     * @param string|int $endTime   结束时间
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2219
     * @return $this
2220
     */
2221
    public function whereNotBetweenTime(string $field, $startTime, $endTime)
2222
    {
2223
        return $this->whereTime($field, '<', $startTime)
2224
            ->whereTime($field, '>', $endTime);
2225
    }
2226
2227
    /**
2228
     * 查询当前时间在两个时间字段范围 whereBetweenTimeField('start_time', 'end_time')
2229
     * @access public
2230
     * @param string $startField 开始时间字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2231
     * @param string $endField   结束时间字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2232
     * @return $this
2233
     */
2234
    public function whereBetweenTimeField(string $startField, string $endField)
2235
    {
2236
        return $this->whereTime($startField, '<=', time())
2237
            ->whereTime($endField, '>=', time());
2238
    }
2239
2240
    /**
2241
     * 查询当前时间不在两个时间字段范围 whereNotBetweenTimeField('start_time', 'end_time')
2242
     * @access public
2243
     * @param string $startField 开始时间字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2244
     * @param string $endField   结束时间字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2245
     * @return $this
2246
     */
2247
    public function whereNotBetweenTimeField(string $startField, string $endField)
2248
    {
2249
        return $this->whereTime($startField, '>', time())
2250
            ->whereTime($endField, '<', time(), 'OR');
2251
    }
2252
2253
    /**
2254
     * 获取当前数据表的主键
2255
     * @access public
2256
     * @return string|array
2257
     */
2258
    public function getPk()
2259
    {
2260
        if (!empty($this->pk)) {
2261
            $pk = $this->pk;
2262
        } else {
2263
            $this->pk = $pk = $this->connection->getPk($this->getTable());
2264
        }
2265
2266
        return $pk;
2267
    }
2268
2269
    /**
2270
     * 批量参数绑定
2271
     * @access public
2272
     * @param array $value 绑定变量值
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2273
     * @return $this
2274
     */
2275
    public function bind(array $value)
2276
    {
2277
        $this->bind = array_merge($this->bind, $value);
2278
        return $this;
2279
    }
2280
2281
    /**
2282
     * 单个参数绑定
2283
     * @access public
2284
     * @param mixed   $value 绑定变量值
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2285
     * @param integer $type  绑定类型
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2286
     * @param string  $name  绑定标识
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2287
     * @return string
2288
     */
2289
    public function bindValue($value, int $type = null, string $name = null)
2290
    {
2291
        $name = $name ?: 'ThinkBind_' . (count($this->bind) + 1) . '_';
2292
2293
        $this->bind[$name] = [$value, $type ?: PDO::PARAM_STR];
2294
        return $name;
2295
    }
2296
2297
    /**
2298
     * 检测参数是否已经绑定
2299
     * @access public
2300
     * @param string $key 参数名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2301
     * @return bool
2302
     */
2303
    public function isBind($key)
2304
    {
2305
        return isset($this->bind[$key]);
2306
    }
2307
2308
    /**
2309
     * 参数绑定
2310
     * @access public
2311
     * @param string $sql  绑定的sql表达式
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2312
     * @param array  $bind 参数绑定
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2313
     * @return void
2314
     */
2315
    protected function bindParams(string &$sql, array $bind = []): void
2316
    {
2317
        foreach ($bind as $key => $value) {
2318
            if (is_array($value)) {
2319
                $name = $this->bindValue($value[0], $value[1], $value[2] ?? null);
2320
            } else {
2321
                $name = $this->bindValue($value);
2322
            }
2323
2324
            if (is_numeric($key)) {
2325
                $sql = substr_replace($sql, ':' . $name, strpos($sql, '?'), 1);
2326
            } else {
2327
                $sql = str_replace(':' . $key, ':' . $name, $sql);
2328
            }
2329
        }
2330
    }
2331
2332
    /**
2333
     * 查询参数批量赋值
2334
     * @access protected
2335
     * @param array $options 表达式参数
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2336
     * @return $this
2337
     */
2338
    protected function options(array $options)
2339
    {
2340
        $this->options = $options;
2341
        return $this;
2342
    }
2343
2344
    /**
2345
     * 获取当前的查询参数
2346
     * @access public
2347
     * @param string $name 参数名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2348
     * @return mixed
2349
     */
2350
    public function getOptions(string $name = '')
2351
    {
2352
        if ('' === $name) {
2353
            return $this->options;
2354
        }
2355
2356
        return $this->options[$name] ?? null;
2357
    }
2358
2359
    /**
2360
     * 设置当前的查询参数
2361
     * @access public
2362
     * @param string $option 参数名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2363
     * @param mixed  $value  参数值
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2364
     * @return $this
2365
     */
2366
    public function setOption(string $option, $value)
2367
    {
2368
        $this->options[$option] = $value;
2369
        return $this;
2370
    }
2371
2372
    /**
2373
     * 设置关联查询
2374
     * @access public
2375
     * @param array $relation 关联名称
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2376
     * @return $this
2377
     */
2378
    public function relation(array $relation)
2379
    {
2380
        if (!empty($relation)) {
2381
            $this->options['relation'] = $relation;
2382
        }
2383
2384
        return $this;
2385
    }
2386
2387
    /**
2388
     * 设置关联查询JOIN预查询
2389
     * @access public
2390
     * @param array $with 关联方法名称(数组)
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2391
     * @return $this
2392
     */
2393
    public function with(array $with)
2394
    {
2395
        if (!empty($with)) {
2396
            $this->options['with'] = $with;
2397
        }
2398
2399
        return $this;
2400
    }
2401
2402
    /**
2403
     * 关联预载入 JOIN方式
2404
     * @access protected
2405
     * @param array  $with     关联方法名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2406
     * @param string $joinType JOIN方式
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2407
     * @return $this
2408
     */
2409
    public function withJoin(array $with, string $joinType = '')
2410
    {
2411
        if (empty($with)) {
2412
            return $this;
2413
        }
2414
2415
        $first = true;
2416
2417
        /** @var Model $class */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
2418
        $class = $this->model;
2419
        foreach ($with as $key => $relation) {
2420
            $closure = null;
2421
            $field   = true;
2422
2423
            if ($relation instanceof Closure) {
2424
                // 支持闭包查询过滤关联条件
2425
                $closure  = $relation;
2426
                $relation = $key;
2427
            } elseif (is_array($relation)) {
2428
                $field    = $relation;
2429
                $relation = $key;
2430
            } elseif (is_string($relation) && strpos($relation, '.')) {
2431
                $relation = strstr($relation, '.', true);
2432
            }
2433
2434
            /** @var Relation $model */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
2435
            $relation = App::parseName($relation, 1, false);
2436
            $model    = $class->$relation();
2437
2438
            if ($model instanceof OneToOne) {
2439
                $model->eagerly($this, $relation, $field, $joinType, $closure, $first);
2440
                $first = false;
2441
            } else {
2442
                // 不支持其它关联
2443
                unset($with[$key]);
2444
            }
2445
        }
2446
2447
        $this->via();
2448
2449
        $this->options['with_join'] = $with;
2450
2451
        return $this;
2452
    }
2453
2454
    /**
2455
     * 设置数据字段获取器
2456
     * @access public
2457
     * @param string   $name     字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2458
     * @param callable $callback 闭包获取器
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2459
     * @return $this
2460
     */
2461
    public function withAttr(string $name, callable $callback)
2462
    {
2463
        $this->options['with_attr'][$name] = $callback;
2464
2465
        return $this;
2466
    }
2467
2468
    /**
2469
     * 设置数据字段获取器
2470
     * @access public
2471
     * @param array $attrs 字段获取器
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2472
     * @return $this
2473
     */
2474
    public function withAttrs(array $attrs)
2475
    {
2476
        $this->options['with_attr'] = $attrs;
2477
2478
        return $this;
2479
    }
2480
2481
    /**
2482
     * 使用搜索器条件搜索字段
2483
     * @access public
2484
     * @param array  $fields 搜索字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2485
     * @param array  $data   搜索数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2486
     * @param string $prefix 字段前缀标识
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2487
     * @return $this
2488
     */
2489
    public function withSearch(array $fields, array $data = [], string $prefix = '')
2490
    {
2491
        foreach ($fields as $key => $field) {
2492
            if ($field instanceof Closure) {
2493
                $field($this, $data[$key] ?? null, $data, $prefix);
2494
            } elseif ($this->model) {
2495
                // 检测搜索器
2496
                $fieldName = is_numeric($key) ? $field : $key;
2497
                $method    = 'search' . App::parseName($fieldName, 1) . 'Attr';
2498
2499
                if (method_exists($this->model, $method)) {
2500
                    $this->model->$method($this, $data[$field] ?? null, $data, $prefix);
2501
                }
2502
            }
2503
        }
2504
2505
        return $this;
2506
    }
2507
2508
    /**
2509
     * 关联统计
2510
     * @access protected
2511
     * @param array|string $relations 关联方法名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2512
     * @param string       $aggregate 聚合查询方法
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2513
     * @param string       $field     字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2514
     * @param bool         $subQuery  是否使用子查询
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2515
     * @return $this
2516
     */
2517
    protected function withAggregate($relations, string $aggregate = 'count', $field = '*', bool $subQuery = true)
2518
    {
2519
        if (is_string($relations)) {
2520
            $relations = explode(',', $relations);
2521
        }
2522
2523
        if (!$subQuery) {
2524
            $this->options['with_count'][] = [$relations, $aggregate, $field];
2525
        } else {
2526
            if (!isset($this->options['field'])) {
2527
                $this->field('*');
2528
            }
2529
2530
            foreach ($relations as $key => $relation) {
2531
                $closure = $aggregateField = null;
2532
2533
                if ($relation instanceof Closure) {
2534
                    $closure  = $relation;
2535
                    $relation = $key;
2536
                } elseif (!is_int($key)) {
2537
                    $aggregateField = $relation;
2538
                    $relation       = $key;
2539
                }
2540
2541
                $relation = App::parseName($relation, 1, false);
2542
2543
                $count = '(' . $this->model->$relation()->getRelationCountQuery($closure, $aggregate, $field, $aggregateField) . ')';
2544
2545
                if (empty($aggregateField)) {
2546
                    $aggregateField = App::parseName($relation) . '_' . $aggregate;
2547
                }
2548
2549
                $this->field([$count => $aggregateField]);
2550
            }
2551
        }
2552
2553
        return $this;
2554
    }
2555
2556
    /**
2557
     * 关联统计
2558
     * @access public
2559
     * @param string|array $relation 关联方法名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2560
     * @param bool         $subQuery 是否使用子查询
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2561
     * @return $this
2562
     */
2563
    public function withCount($relation, bool $subQuery = true)
2564
    {
2565
        return $this->withAggregate($relation, 'count', '*', $subQuery);
2566
    }
2567
2568
    /**
2569
     * 关联统计Sum
2570
     * @access public
2571
     * @param string|array $relation 关联方法名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2572
     * @param string       $field    字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2573
     * @param bool         $subQuery 是否使用子查询
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2574
     * @return $this
2575
     */
2576
    public function withSum($relation, string $field, bool $subQuery = true)
2577
    {
2578
        return $this->withAggregate($relation, 'sum', $field, $subQuery);
2579
    }
2580
2581
    /**
2582
     * 关联统计Max
2583
     * @access public
2584
     * @param string|array $relation 关联方法名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2585
     * @param string       $field    字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2586
     * @param bool         $subQuery 是否使用子查询
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2587
     * @return $this
2588
     */
2589
    public function withMax($relation, string $field, bool $subQuery = true)
2590
    {
2591
        return $this->withAggregate($relation, 'max', $field, $subQuery);
2592
    }
2593
2594
    /**
2595
     * 关联统计Min
2596
     * @access public
2597
     * @param string|array $relation 关联方法名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2598
     * @param string       $field    字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2599
     * @param bool         $subQuery 是否使用子查询
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2600
     * @return $this
2601
     */
2602
    public function withMin($relation, string $field, bool $subQuery = true)
2603
    {
2604
        return $this->withAggregate($relation, 'min', $field, $subQuery);
2605
    }
2606
2607
    /**
2608
     * 关联统计Avg
2609
     * @access public
2610
     * @param string|array $relation 关联方法名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2611
     * @param string       $field    字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2612
     * @param bool         $subQuery 是否使用子查询
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2613
     * @return $this
2614
     */
2615
    public function withAvg($relation, string $field, bool $subQuery = true)
2616
    {
2617
        return $this->withAggregate($relation, 'avg', $field, $subQuery);
2618
    }
2619
2620
    /**
2621
     * 关联预加载中 获取关联指定字段值
2622
     * example:
2623
     * Model::with(['relation' => function($query){
2624
     *     $query->withField("id,name");
2625
     * }])
2626
     *
2627
     * @access public
2628
     * @param string|array $field 指定获取的字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2629
     * @return $this
2630
     */
2631
    public function withField($field)
2632
    {
2633
        $this->options['with_field'] = $field;
2634
2635
        return $this;
2636
    }
2637
2638
    /**
2639
     * 设置当前字段添加的表别名
2640
     * @access public
2641
     * @param string $via 临时表别名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2642
     * @return $this
2643
     */
2644
    public function via(string $via = '')
2645
    {
2646
        $this->options['via'] = $via;
2647
2648
        return $this;
2649
    }
2650
2651
    /**
2652
     * 保存记录 自动判断insert或者update
2653
     * @access public
2654
     * @param array $data        数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2655
     * @param bool  $forceInsert 是否强制insert
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2656
     * @return integer
2657
     */
2658
    public function save(array $data = [], bool $forceInsert = false)
2659
    {
2660
        if ($forceInsert) {
2661
            return $this->insert($data);
2662
        }
2663
2664
        $this->options['data'] = array_merge($this->options['data'] ?? [], $data);
2665
2666
        if (!empty($this->options['where'])) {
2667
            $isUpdate = true;
2668
        } else {
2669
            $isUpdate = $this->parseUpdateData($this->options['data']);
2670
        }
2671
2672
        return $isUpdate ? $this->update() : $this->insert();
2673
    }
2674
2675
    /**
2676
     * 插入记录
2677
     * @access public
2678
     * @param array   $data         数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2679
     * @param boolean $getLastInsID 返回自增主键
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2680
     * @return integer
2681
     */
2682
    public function insert(array $data = [], bool $getLastInsID = false)
2683
    {
2684
        if (!empty($data)) {
2685
            $this->options['data'] = $data;
2686
        }
2687
2688
        return $this->connection->insert($this, $getLastInsID);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->connection...t($this, $getLastInsID) also could return the type string which is incompatible with the documented return type integer.
Loading history...
2689
    }
2690
2691
    /**
2692
     * 插入记录并获取自增ID
2693
     * @access public
2694
     * @param array $data 数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2695
     * @return integer|string
2696
     */
2697
    public function insertGetId(array $data)
2698
    {
2699
        return $this->insert($data, true);
2700
    }
2701
2702
    /**
2703
     * 批量插入记录
2704
     * @access public
2705
     * @param array   $dataSet 数据集
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2706
     * @param integer $limit   每次写入数据限制
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2707
     * @return integer
2708
     */
2709
    public function insertAll(array $dataSet = [], int $limit = 0): int
2710
    {
2711
        if (empty($dataSet)) {
2712
            $dataSet = $this->options['data'] ?? [];
2713
        }
2714
2715
        if (empty($limit) && !empty($this->options['limit']) && is_numeric($this->options['limit'])) {
2716
            $limit = (int) $this->options['limit'];
2717
        }
2718
2719
        return $this->connection->insertAll($this, $dataSet, $limit);
2720
    }
2721
2722
    /**
2723
     * 通过Select方式插入记录
2724
     * @access public
2725
     * @param array  $fields 要插入的数据表字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2726
     * @param string $table  要插入的数据表名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2727
     * @return integer
2728
     * @throws PDOException
2729
     */
2730
    public function selectInsert(array $fields, string $table): int
2731
    {
2732
        return $this->connection->selectInsert($this, $fields, $table);
2733
    }
2734
2735
    /**
2736
     * 更新记录
2737
     * @access public
2738
     * @param mixed $data 数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2739
     * @return integer
2740
     * @throws Exception
2741
     * @throws PDOException
2742
     */
2743
    public function update(array $data = []): int
2744
    {
2745
        if (!empty($data)) {
2746
            $this->options['data'] = array_merge($this->options['data'] ?? [], $data);
2747
        }
2748
2749
        if (empty($this->options['where'])) {
2750
            $this->parseUpdateData($this->options['data']);
2751
        }
2752
2753
        if (empty($this->options['where']) && $this->model) {
2754
            $this->where($this->model->getWhere());
2755
        }
2756
2757
        if (empty($this->options['where'])) {
2758
            // 如果没有任何更新条件则不执行
2759
            throw new Exception('miss update condition');
2760
        }
2761
2762
        return $this->connection->update($this);
2763
    }
2764
2765
    /**
2766
     * 删除记录
2767
     * @access public
2768
     * @param mixed $data 表达式 true 表示强制删除
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2769
     * @return int
2770
     * @throws Exception
2771
     * @throws PDOException
2772
     */
2773
    public function delete($data = null): int
2774
    {
2775
        if (!is_null($data) && true !== $data) {
2776
            // AR模式分析主键条件
2777
            $this->parsePkWhere($data);
2778
        }
2779
2780
        if (empty($this->options['where']) && $this->model) {
2781
            $this->where($this->model->getWhere());
2782
        }
2783
2784
        if (true !== $data && empty($this->options['where'])) {
2785
            // 如果条件为空 不进行删除操作 除非设置 1=1
2786
            throw new Exception('delete without condition');
2787
        }
2788
2789
        if (!empty($this->options['soft_delete'])) {
2790
            // 软删除
2791
            list($field, $condition) = $this->options['soft_delete'];
2792
            if ($condition) {
2793
                unset($this->options['soft_delete']);
2794
                $this->options['data'] = [$field => $condition];
2795
2796
                return $this->connection->update($this);
2797
            }
2798
        }
2799
2800
        $this->options['data'] = $data;
2801
2802
        return $this->connection->delete($this);
2803
    }
2804
2805
    /**
2806
     * 执行查询但只返回PDOStatement对象
2807
     * @access public
2808
     * @return PDOStatement
2809
     */
2810
    public function getPdo(): PDOStatement
2811
    {
2812
        return $this->connection->pdo($this);
2813
    }
2814
2815
    /**
2816
     * 使用游标查找记录
2817
     * @access public
2818
     * @param mixed $data 数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2819
     * @return \Generator
2820
     */
2821
    public function cursor($data = null)
2822
    {
2823
        if (!is_null($data)) {
2824
            // 主键条件分析
2825
            $this->parsePkWhere($data);
2826
        }
2827
2828
        $this->options['data'] = $data;
2829
2830
        $connection = clone $this->connection;
2831
2832
        return $connection->cursor($this);
2833
    }
2834
2835
    /**
2836
     * 查找记录
2837
     * @access public
2838
     * @param mixed $data 数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2839
     * @return Collection|array|ModelCollection
2840
     * @throws DbException
2841
     * @throws ModelNotFoundException
2842
     * @throws DataNotFoundException
2843
     */
2844
    public function select($data = null)
2845
    {
2846
        if (!is_null($data)) {
2847
            // 主键条件分析
2848
            $this->parsePkWhere($data);
2849
        }
2850
2851
        $resultSet = $this->connection->select($this);
2852
2853
        // 返回结果处理
2854
        if (!empty($this->options['fail']) && count($resultSet) == 0) {
2855
            $this->throwNotFound();
2856
        }
2857
2858
        // 数据列表读取后的处理
2859
        if (!empty($this->model) && empty($this->options['array'])) {
2860
            // 生成模型对象
2861
            $resultSet = $this->resultSetToModelCollection($resultSet);
2862
        } else {
2863
            $this->resultSet($resultSet);
2864
        }
2865
2866
        return $resultSet;
2867
    }
2868
2869
    /**
2870
     * 查询数据转换为模型数据集对象
2871
     * @access protected
2872
     * @param array $resultSet 数据集
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2873
     * @return ModelCollection
2874
     */
2875
    protected function resultSetToModelCollection(array $resultSet): ModelCollection
2876
    {
2877
        if (!empty($this->options['collection']) && is_string($this->options['collection'])) {
2878
            $collection = $this->options['collection'];
2879
        }
2880
2881
        if (empty($resultSet)) {
2882
            return $this->model->toCollection([], $collection ?? null);
2883
        }
2884
2885
        // 检查动态获取器
2886
        if (!empty($this->options['with_attr'])) {
2887
            foreach ($this->options['with_attr'] as $name => $val) {
2888
                if (strpos($name, '.')) {
2889
                    list($relation, $field) = explode('.', $name);
2890
2891
                    $withRelationAttr[$relation][$field] = $val;
2892
                    unset($this->options['with_attr'][$name]);
2893
                }
2894
            }
2895
        }
2896
2897
        $withRelationAttr = $withRelationAttr ?? [];
2898
2899
        foreach ($resultSet as $key => &$result) {
2900
            // 数据转换为模型对象
2901
            $this->resultToModel($result, $this->options, true, $withRelationAttr);
2902
        }
2903
2904
        if (!empty($this->options['with'])) {
2905
            // 预载入
2906
            $result->eagerlyResultSet($resultSet, $this->options['with'], $withRelationAttr);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $result seems to be defined by a foreach iteration on line 2899. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
2907
        }
2908
2909
        if (!empty($this->options['with_join'])) {
2910
            // 预载入
2911
            $result->eagerlyResultSet($resultSet, $this->options['with_join'], $withRelationAttr, true);
2912
        }
2913
2914
        // 模型数据集转换
2915
        return $this->model->toCollection($resultSet, $collection ?? null);
2916
    }
2917
2918
    /**
2919
     * 处理数据集
2920
     * @access public
2921
     * @param array $resultSet 数据集
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2922
     * @return void
2923
     */
2924
    protected function resultSet(array &$resultSet): void
2925
    {
2926
        if (!empty($this->options['json'])) {
2927
            foreach ($resultSet as &$result) {
2928
                $this->jsonResult($result, $this->options['json'], true);
2929
            }
2930
        }
2931
2932
        if (!empty($this->options['with_attr'])) {
2933
            foreach ($resultSet as &$result) {
2934
                $this->getResultAttr($result, $this->options['with_attr']);
2935
            }
2936
        }
2937
2938
        if (!empty($this->options['visible']) || !empty($this->options['hidden'])) {
2939
            foreach ($resultSet as &$result) {
2940
                $this->filterResult($result);
2941
            }
2942
        }
2943
2944
        if (!empty($this->options['collection'])) {
2945
            // 返回Collection对象
2946
            $resultSet = new Collection($resultSet);
2947
        }
2948
    }
2949
2950
    /**
2951
     * 查找单条记录
2952
     * @access public
2953
     * @param mixed $data 查询数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2954
     * @return array|Model|null
2955
     * @throws DbException
2956
     * @throws ModelNotFoundException
2957
     * @throws DataNotFoundException
2958
     */
2959
    public function find($data = null)
2960
    {
2961
        if (!is_null($data)) {
2962
            // AR模式分析主键条件
2963
            $this->parsePkWhere($data);
2964
        }
2965
2966
        $result = $this->connection->find($this);
2967
2968
        // 数据处理
2969
        if (empty($result)) {
2970
            return $this->resultToEmpty();
2971
        }
2972
2973
        if (!empty($this->model) && empty($this->options['array'])) {
2974
            // 返回模型对象
2975
            $this->resultToModel($result, $this->options);
2976
        } else {
2977
            $this->result($result);
2978
        }
2979
2980
        return $result;
2981
    }
2982
2983
    /**
2984
     * 查找单条记录 不存在返回空数据(或者空模型)
2985
     * @access public
2986
     * @param mixed $data 数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
2987
     * @return array|Model
2988
     */
2989
    public function findOrEmpty($data = null)
2990
    {
2991
        return $this->allowEmpty(true)->find($data);
2992
    }
2993
2994
    /**
2995
     * 处理空数据
2996
     * @access protected
2997
     * @return array|Model|null
2998
     * @throws DbException
2999
     * @throws ModelNotFoundException
3000
     * @throws DataNotFoundException
3001
     */
3002
    protected function resultToEmpty()
3003
    {
3004
        if (!empty($this->options['fail'])) {
3005
            $this->throwNotFound();
3006
        } elseif (!empty($this->options['allow_empty'])) {
3007
            return !empty($this->model) && empty($this->options['array']) ? $this->model->newInstance() : [];
3008
        } elseif (!empty($this->options['array'])) {
3009
            return [];
3010
        }
3011
    }
3012
3013
    /**
3014
     * 获取模型的更新条件
3015
     * @access protected
3016
     * @param array $options 查询参数
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3017
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
3018
    protected function getModelUpdateCondition(array $options)
3019
    {
3020
        return $options['where']['AND'] ?? null;
3021
    }
3022
3023
    /**
3024
     * 处理数据
3025
     * @access protected
3026
     * @param array $result 查询数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3027
     * @return void
3028
     */
3029
    protected function result(array &$result): void
3030
    {
3031
        if (!empty($this->options['json'])) {
3032
            $this->jsonResult($result, $this->options['json'], true);
3033
        }
3034
3035
        if (!empty($this->options['with_attr'])) {
3036
            $this->getResultAttr($result, $this->options['with_attr']);
3037
        }
3038
3039
        $this->filterResult($result);
3040
    }
3041
3042
    /**
3043
     * 处理数据的可见和隐藏
3044
     * @access protected
3045
     * @param array $result 查询数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3046
     * @return void
3047
     */
3048
    protected function filterResult(&$result): void
3049
    {
3050
        if (!empty($this->options['visible'])) {
3051
            foreach ($this->options['visible'] as $key) {
3052
                $array[] = $key;
3053
            }
3054
            $result = array_intersect_key($result, array_flip($array));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $array seems to be defined by a foreach iteration on line 3051. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
3055
        } elseif (!empty($this->options['hidden'])) {
3056
            foreach ($this->options['hidden'] as $key) {
3057
                $array[] = $key;
3058
            }
3059
            $result = array_diff_key($result, array_flip($array));
3060
        }
3061
    }
3062
3063
    /**
3064
     * 使用获取器处理数据
3065
     * @access protected
3066
     * @param array $result   查询数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3067
     * @param array $withAttr 字段获取器
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3068
     * @return void
3069
     */
3070
    protected function getResultAttr(array &$result, array $withAttr = []): void
3071
    {
3072
        foreach ($withAttr as $name => $closure) {
3073
            $name = App::parseName($name);
3074
3075
            if (strpos($name, '.')) {
3076
                // 支持JSON字段 获取器定义
3077
                list($key, $field) = explode('.', $name);
3078
3079
                if (isset($result[$key])) {
3080
                    $result[$key][$field] = $closure($result[$key][$field] ?? null, $result[$key]);
3081
                }
3082
            } else {
3083
                $result[$name] = $closure($result[$name] ?? null, $result);
3084
            }
3085
        }
3086
    }
3087
3088
    /**
3089
     * JSON字段数据转换
3090
     * @access protected
3091
     * @param array $result           查询数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3092
     * @param array $json             JSON字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3093
     * @param bool  $assoc            是否转换为数组
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3094
     * @param array $withRelationAttr 关联获取器
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3095
     * @return void
3096
     */
3097
    protected function jsonResult(array &$result, array $json = [], bool $assoc = false, array $withRelationAttr = []): void
3098
    {
3099
        foreach ($json as $name) {
3100
            if (!isset($result[$name])) {
3101
                continue;
3102
            }
3103
3104
            $result[$name] = json_decode($result[$name], $assoc);
3105
3106
            if (!isset($withRelationAttr[$name])) {
3107
                continue;
3108
            }
3109
3110
            foreach ($withRelationAttr[$name] as $key => $closure) {
3111
                $data = get_object_vars($result[$name]);
3112
3113
                $result[$name]->$key = $closure($result[$name]->$key ?? null, $data);
3114
            }
3115
        }
3116
    }
3117
3118
    /**
3119
     * 查询数据转换为模型对象
3120
     * @access protected
3121
     * @param array $result           查询数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3122
     * @param array $options          查询参数
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3123
     * @param bool  $resultSet        是否为数据集查询
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3124
     * @param array $withRelationAttr 关联字段获取器
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3125
     * @return void
3126
     */
3127
    protected function resultToModel(array &$result, array $options = [], bool $resultSet = false, array $withRelationAttr = []): void
3128
    {
3129
        // 动态获取器
3130
        if (!empty($options['with_attr']) && empty($withRelationAttr)) {
3131
            foreach ($options['with_attr'] as $name => $val) {
3132
                if (strpos($name, '.')) {
3133
                    list($relation, $field) = explode('.', $name);
3134
3135
                    $withRelationAttr[$relation][$field] = $val;
3136
                    unset($options['with_attr'][$name]);
3137
                }
3138
            }
3139
        }
3140
3141
        // JSON 数据处理
3142
        if (!empty($options['json'])) {
3143
            $this->jsonResult($result, $options['json'], $options['json_assoc'], $withRelationAttr);
3144
        }
3145
3146
        $result = $this->model->newInstance($result, $resultSet ? null : $this->getModelUpdateCondition($options));
3147
3148
        // 动态获取器
3149
        if (!empty($options['with_attr'])) {
3150
            $result->withAttribute($options['with_attr']);
3151
        }
3152
3153
        // 输出属性控制
3154
        if (!empty($options['visible'])) {
3155
            $result->visible($options['visible']);
3156
        } elseif (!empty($options['hidden'])) {
3157
            $result->hidden($options['hidden']);
3158
        }
3159
3160
        if (!empty($options['append'])) {
3161
            $result->append($options['append']);
3162
        }
3163
3164
        // 关联查询
3165
        if (!empty($options['relation'])) {
3166
            $result->relationQuery($options['relation']);
3167
        }
3168
3169
        // 预载入查询
3170
        if (!$resultSet && !empty($options['with'])) {
3171
            $result->eagerlyResult($result, $options['with'], $withRelationAttr);
3172
        }
3173
3174
        // JOIN预载入查询
3175
        if (!$resultSet && !empty($options['with_join'])) {
3176
            $result->eagerlyResult($result, $options['with_join'], $withRelationAttr, true);
3177
        }
3178
3179
        // 关联统计
3180
        if (!empty($options['with_count'])) {
3181
            foreach ($options['with_count'] as $val) {
3182
                $result->relationCount($result, $val[0], $val[1], $val[2]);
3183
            }
3184
        }
3185
    }
3186
3187
    /**
3188
     * 查询失败 抛出异常
3189
     * @access protected
3190
     * @return void
3191
     * @throws ModelNotFoundException
3192
     * @throws DataNotFoundException
3193
     */
3194
    protected function throwNotFound(): void
3195
    {
3196
        if (!empty($this->model)) {
3197
            $class = get_class($this->model);
3198
            throw new ModelNotFoundException('model data Not Found:' . $class, $class, $this->options);
3199
        }
3200
3201
        $table = $this->getTable();
3202
        throw new DataNotFoundException('table data not Found:' . $table, $table, $this->options);
3203
    }
3204
3205
    /**
3206
     * 查找多条记录 如果不存在则抛出异常
3207
     * @access public
3208
     * @param array|string|Query|Closure $data 数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3209
     * @return array|PDOStatement|string|Model
3210
     * @throws DbException
3211
     * @throws ModelNotFoundException
3212
     * @throws DataNotFoundException
3213
     */
3214
    public function selectOrFail($data = null)
3215
    {
3216
        return $this->failException(true)->select($data);
3217
    }
3218
3219
    /**
3220
     * 查找单条记录 如果不存在则抛出异常
3221
     * @access public
3222
     * @param array|string|Query|Closure $data 数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3223
     * @return array|PDOStatement|string|Model
3224
     * @throws DbException
3225
     * @throws ModelNotFoundException
3226
     * @throws DataNotFoundException
3227
     */
3228
    public function findOrFail($data = null)
3229
    {
3230
        return $this->failException(true)->find($data);
3231
    }
3232
3233
    /**
3234
     * 分批数据返回处理
3235
     * @access public
3236
     * @param integer      $count    每次处理的数据数量
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3237
     * @param callable     $callback 处理回调方法
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3238
     * @param string|array $column   分批处理的字段名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3239
     * @param string       $order    字段排序
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3240
     * @return bool
3241
     * @throws DbException
3242
     */
3243
    public function chunk(int $count, callable $callback, $column = null, string $order = 'asc'): bool
3244
    {
3245
        $options = $this->getOptions();
3246
        $column  = $column ?: $this->getPk();
3247
3248
        if (isset($options['order'])) {
3249
            unset($options['order']);
3250
        }
3251
3252
        $bind = $this->bind;
3253
3254
        if (is_array($column)) {
3255
            $times = 1;
3256
            $query = $this->options($options)->page($times, $count);
3257
        } else {
3258
            $query = $this->options($options)->limit($count);
3259
3260
            if (strpos($column, '.')) {
3261
                list($alias, $key) = explode('.', $column);
3262
            } else {
3263
                $key = $column;
3264
            }
3265
        }
3266
3267
        $resultSet = $query->order($column, $order)->select();
3268
3269
        while (count($resultSet) > 0) {
3270
            if ($resultSet instanceof Collection) {
3271
                $resultSet = $resultSet->all();
3272
            }
3273
3274
            if (false === call_user_func($callback, $resultSet)) {
3275
                return false;
3276
            }
3277
3278
            if (isset($times)) {
3279
                $times++;
3280
                $query = $this->options($options)->page($times, $count);
3281
            } else {
3282
                $end    = end($resultSet);
3283
                $lastId = is_array($end) ? $end[$key] : $end->getData($key);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $key does not seem to be defined for all execution paths leading up to this point.
Loading history...
3284
3285
                $query = $this->options($options)
3286
                    ->limit($count)
3287
                    ->where($column, 'asc' == strtolower($order) ? '>' : '<', $lastId);
3288
            }
3289
3290
            $resultSet = $query->bind($bind)->order($column, $order)->select();
3291
        }
3292
3293
        return true;
3294
    }
3295
3296
    /**
3297
     * 获取绑定的参数 并清空
3298
     * @access public
3299
     * @param bool $clear 是否清空绑定数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3300
     * @return array
3301
     */
3302
    public function getBind(bool $clear = true): array
3303
    {
3304
        $bind = $this->bind;
3305
        if ($clear) {
3306
            $this->bind = [];
3307
        }
3308
3309
        return $bind;
3310
    }
3311
3312
    /**
3313
     * 创建子查询SQL
3314
     * @access public
3315
     * @param bool $sub 是否添加括号
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3316
     * @return string
3317
     * @throws DbException
3318
     */
3319
    public function buildSql(bool $sub = true): string
3320
    {
3321
        return $sub ? '( ' . $this->fetchSql()->select() . ' )' : $this->fetchSql()->select();
3322
    }
3323
3324
    /**
3325
     * 视图查询处理
3326
     * @access protected
3327
     * @param array $options 查询参数
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3328
     * @return void
3329
     */
3330
    protected function parseView(array &$options): void
3331
    {
3332
        foreach (['AND', 'OR'] as $logic) {
3333
            if (isset($options['where'][$logic])) {
3334
                foreach ($options['where'][$logic] as $key => $val) {
3335
                    if (array_key_exists($key, $options['map'])) {
3336
                        array_shift($val);
3337
                        array_unshift($val, $options['map'][$key]);
3338
                        $options['where'][$logic][$options['map'][$key]] = $val;
3339
                        unset($options['where'][$logic][$key]);
3340
                    }
3341
                }
3342
            }
3343
        }
3344
3345
        if (isset($options['order'])) {
3346
            // 视图查询排序处理
3347
            foreach ($options['order'] as $key => $val) {
3348
                if (is_numeric($key) && is_string($val)) {
3349
                    if (strpos($val, ' ')) {
3350
                        list($field, $sort) = explode(' ', $val);
3351
                        if (array_key_exists($field, $options['map'])) {
3352
                            $options['order'][$options['map'][$field]] = $sort;
3353
                            unset($options['order'][$key]);
3354
                        }
3355
                    } elseif (array_key_exists($val, $options['map'])) {
3356
                        $options['order'][$options['map'][$val]] = 'asc';
3357
                        unset($options['order'][$key]);
3358
                    }
3359
                } elseif (array_key_exists($key, $options['map'])) {
3360
                    $options['order'][$options['map'][$key]] = $val;
3361
                    unset($options['order'][$key]);
3362
                }
3363
            }
3364
        }
3365
    }
3366
3367
    /**
3368
     * 分析数据是否存在更新条件
3369
     * @access public
3370
     * @param array $data 数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3371
     * @return bool
3372
     * @throws Exception
3373
     */
3374
    public function parseUpdateData(&$data): bool
3375
    {
3376
        $pk       = $this->getPk();
3377
        $isUpdate = false;
3378
        // 如果存在主键数据 则自动作为更新条件
3379
        if (is_string($pk) && isset($data[$pk])) {
3380
            $this->where($pk, '=', $data[$pk]);
3381
            $this->options['key'] = $data[$pk];
3382
            unset($data[$pk]);
3383
            $isUpdate = true;
3384
        } elseif (is_array($pk)) {
3385
            // 增加复合主键支持
3386
            foreach ($pk as $field) {
3387
                if (isset($data[$field])) {
3388
                    $this->where($field, '=', $data[$field]);
3389
                    $isUpdate = true;
3390
                } else {
3391
                    // 如果缺少复合主键数据则不执行
3392
                    throw new Exception('miss complex primary data');
3393
                }
3394
                unset($data[$field]);
3395
            }
3396
        }
3397
3398
        return $isUpdate;
3399
    }
3400
3401
    /**
3402
     * 把主键值转换为查询条件 支持复合主键
3403
     * @access public
3404
     * @param array|string $data 主键数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
3405
     * @return void
3406
     * @throws Exception
3407
     */
3408
    public function parsePkWhere($data): void
3409
    {
3410
        $pk = $this->getPk();
3411
3412
        if (is_string($pk)) {
3413
            // 获取数据表
3414
            if (empty($this->options['table'])) {
3415
                $this->options['table'] = $this->getTable();
3416
            }
3417
3418
            $table = is_array($this->options['table']) ? key($this->options['table']) : $this->options['table'];
3419
3420
            if (!empty($this->options['alias'][$table])) {
3421
                $alias = $this->options['alias'][$table];
3422
            }
3423
3424
            $key = isset($alias) ? $alias . '.' . $pk : $pk;
3425
            // 根据主键查询
3426
            if (is_array($data)) {
3427
                $this->where($key, 'in', $data);
3428
            } else {
3429
                $this->where($key, '=', $data);
3430
                $this->options['key'] = $data;
3431
            }
3432
        }
3433
    }
3434
3435
    /**
3436
     * 分析表达式(可用于查询或者写入操作)
3437
     * @access public
3438
     * @return array
3439
     */
3440
    public function parseOptions(): array
3441
    {
3442
        $options = $this->getOptions();
3443
3444
        // 获取数据表
3445
        if (empty($options['table'])) {
3446
            $options['table'] = $this->getTable();
3447
        }
3448
3449
        if (!isset($options['where'])) {
3450
            $options['where'] = [];
3451
        } elseif (isset($options['view'])) {
3452
            // 视图查询条件处理
3453
            $this->parseView($options);
3454
        }
3455
3456
        if (!isset($options['field'])) {
3457
            $options['field'] = '*';
3458
        }
3459
3460
        foreach (['data', 'order', 'join', 'union'] as $name) {
3461
            if (!isset($options[$name])) {
3462
                $options[$name] = [];
3463
            }
3464
        }
3465
3466
        if (!isset($options['strict'])) {
3467
            $options['strict'] = $this->connection->getConfig('fields_strict');
3468
        }
3469
3470
        foreach (['master', 'lock', 'fetch_sql', 'array', 'distinct', 'procedure'] as $name) {
3471
            if (!isset($options[$name])) {
3472
                $options[$name] = false;
3473
            }
3474
        }
3475
3476
        if (is_string($options['table']) && $this->db->isReadMaster($options['table'])) {
3477
            $options['master'] = true;
3478
        }
3479
3480
        foreach (['group', 'having', 'limit', 'force', 'comment', 'partition', 'duplicate', 'extra'] as $name) {
3481
            if (!isset($options[$name])) {
3482
                $options[$name] = '';
3483
            }
3484
        }
3485
3486
        if (isset($options['page'])) {
3487
            // 根据页数计算limit
3488
            list($page, $listRows) = $options['page'];
3489
            $page             = $page > 0 ? $page : 1;
3490
            $listRows         = $listRows ? $listRows : (is_numeric($options['limit']) ? $options['limit'] : 20);
3491
            $offset           = $listRows * ($page - 1);
3492
            $options['limit'] = $offset . ',' . $listRows;
3493
        }
3494
3495
        $this->options = $options;
3496
3497
        return $options;
3498
    }
3499
3500
}
3501