Completed
Push — 6.0 ( f9d161...156ecf )
by liu
02:56
created

Query::withoutField()   A

Complexity

Conditions 5
Paths 9

Size

Total Lines 21
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

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