Passed
Pull Request — 6.0 (#1846)
by
unknown
04:11
created

Query::getFields()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

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

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

3340
                $end    = end(/** @scrutinizer ignore-type */ $resultSet);
Loading history...
3341
                $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...
3342
3343
                $query = $this->options($options)
3344
                    ->limit($count)
3345
                    ->where($column, 'asc' == strtolower($order) ? '>' : '<', $lastId);
3346
            }
3347
3348
            $resultSet = $query->bind($bind)->order($column, $order)->select();
3349
        }
3350
3351
        return true;
3352
    }
3353
3354
    /**
3355
     * 获取绑定的参数 并清空
3356
     * @access public
3357
     * @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...
3358
     * @return array
3359
     */
3360
    public function getBind(bool $clear = true): array
3361
    {
3362
        $bind = $this->bind;
3363
        if ($clear) {
3364
            $this->bind = [];
3365
        }
3366
3367
        return $bind;
3368
    }
3369
3370
    /**
3371
     * 创建子查询SQL
3372
     * @access public
3373
     * @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...
3374
     * @return string
3375
     * @throws DbException
3376
     */
3377
    public function buildSql(bool $sub = true): string
3378
    {
3379
        return $sub ? '( ' . $this->fetchSql()->select() . ' )' : $this->fetchSql()->select();
3380
    }
3381
3382
    /**
3383
     * 视图查询处理
3384
     * @access protected
3385
     * @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...
3386
     * @return void
3387
     */
3388
    protected function parseView(array &$options): void
3389
    {
3390
        foreach (['AND', 'OR'] as $logic) {
3391
            if (isset($options['where'][$logic])) {
3392
                foreach ($options['where'][$logic] as $key => $val) {
3393
                    if (array_key_exists($key, $options['map'])) {
3394
                        array_shift($val);
3395
                        array_unshift($val, $options['map'][$key]);
3396
                        $options['where'][$logic][$options['map'][$key]] = $val;
3397
                        unset($options['where'][$logic][$key]);
3398
                    }
3399
                }
3400
            }
3401
        }
3402
3403
        if (isset($options['order'])) {
3404
            // 视图查询排序处理
3405
            foreach ($options['order'] as $key => $val) {
3406
                if (is_numeric($key) && is_string($val)) {
3407
                    if (strpos($val, ' ')) {
3408
                        list($field, $sort) = explode(' ', $val);
3409
                        if (array_key_exists($field, $options['map'])) {
3410
                            $options['order'][$options['map'][$field]] = $sort;
3411
                            unset($options['order'][$key]);
3412
                        }
3413
                    } elseif (array_key_exists($val, $options['map'])) {
3414
                        $options['order'][$options['map'][$val]] = 'asc';
3415
                        unset($options['order'][$key]);
3416
                    }
3417
                } elseif (array_key_exists($key, $options['map'])) {
3418
                    $options['order'][$options['map'][$key]] = $val;
3419
                    unset($options['order'][$key]);
3420
                }
3421
            }
3422
        }
3423
    }
3424
3425
    /**
3426
     * 分析数据是否存在更新条件
3427
     * @access public
3428
     * @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...
3429
     * @return bool
3430
     * @throws Exception
3431
     */
3432
    public function parseUpdateData(&$data): bool
3433
    {
3434
        $pk       = $this->getPk();
3435
        $isUpdate = false;
3436
        // 如果存在主键数据 则自动作为更新条件
3437
        if (is_string($pk) && isset($data[$pk])) {
3438
            $this->where($pk, '=', $data[$pk]);
3439
            $this->options['key'] = $data[$pk];
3440
            unset($data[$pk]);
3441
            $isUpdate = true;
3442
        } elseif (is_array($pk)) {
3443
            foreach ($pk as $field) {
3444
                if (isset($data[$field])) {
3445
                    $this->where($field, '=', $data[$field]);
3446
                    $isUpdate = true;
3447
                } else {
3448
                    // 如果缺少复合主键数据则不执行
3449
                    throw new Exception('miss complex primary data');
3450
                }
3451
                unset($data[$field]);
3452
            }
3453
        }
3454
3455
        return $isUpdate;
3456
    }
3457
3458
    /**
3459
     * 把主键值转换为查询条件 支持复合主键
3460
     * @access public
3461
     * @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...
3462
     * @return void
3463
     * @throws Exception
3464
     */
3465
    public function parsePkWhere($data): void
3466
    {
3467
        $pk = $this->getPk();
3468
3469
        if (is_string($pk)) {
3470
            // 获取数据表
3471
            if (empty($this->options['table'])) {
3472
                $this->options['table'] = $this->getTable();
3473
            }
3474
3475
            $table = is_array($this->options['table']) ? key($this->options['table']) : $this->options['table'];
3476
3477
            if (!empty($this->options['alias'][$table])) {
3478
                $alias = $this->options['alias'][$table];
3479
            }
3480
3481
            $key = isset($alias) ? $alias . '.' . $pk : $pk;
3482
            // 根据主键查询
3483
            if (is_array($data)) {
3484
                $this->where($key, 'in', $data);
3485
            } else {
3486
                $this->where($key, '=', $data);
3487
                $this->options['key'] = $data;
3488
            }
3489
        }
3490
    }
3491
3492
    /**
3493
     * 分析表达式(可用于查询或者写入操作)
3494
     * @access public
3495
     * @return array
3496
     */
3497
    public function parseOptions(): array
3498
    {
3499
        $options = $this->getOptions();
3500
3501
        // 获取数据表
3502
        if (empty($options['table'])) {
3503
            $options['table'] = $this->getTable();
3504
        }
3505
3506
        if (!isset($options['where'])) {
3507
            $options['where'] = [];
3508
        } elseif (isset($options['view'])) {
3509
            // 视图查询条件处理
3510
            $this->parseView($options);
3511
        }
3512
3513
        if (!isset($options['field'])) {
3514
            $options['field'] = '*';
3515
        }
3516
3517
        foreach (['data', 'order', 'join', 'union'] as $name) {
3518
            if (!isset($options[$name])) {
3519
                $options[$name] = [];
3520
            }
3521
        }
3522
3523
        if (!isset($options['strict'])) {
3524
            $options['strict'] = $this->connection->getConfig('fields_strict');
3525
        }
3526
3527
        foreach (['master', 'lock', 'fetch_sql', 'array', 'distinct', 'procedure'] as $name) {
3528
            if (!isset($options[$name])) {
3529
                $options[$name] = false;
3530
            }
3531
        }
3532
3533
        foreach (['group', 'having', 'limit', 'force', 'comment', 'partition', 'duplicate', 'extra'] as $name) {
3534
            if (!isset($options[$name])) {
3535
                $options[$name] = '';
3536
            }
3537
        }
3538
3539
        if (isset($options['page'])) {
3540
            // 根据页数计算limit
3541
            list($page, $listRows) = $options['page'];
3542
            $page                  = $page > 0 ? $page : 1;
3543
            $listRows              = $listRows ?: (is_numeric($options['limit']) ? $options['limit'] : 20);
3544
            $offset                = $listRows * ($page - 1);
3545
            $options['limit']      = $offset . ',' . $listRows;
3546
        }
3547
3548
        $this->options = $options;
3549
3550
        return $options;
3551
    }
3552
3553
    public function __debugInfo()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __debugInfo()
Loading history...
3554
    {
3555
        return [
3556
            'name'    => $this->name,
3557
            'pk'      => $this->pk,
3558
            'prefix'  => $this->prefix,
3559
            'bind'    => $this->bind,
3560
            'options' => $this->options,
3561
        ];
3562
    }
3563
}
3564