Completed
Push — 6.0 ( dc873c...6e7412 )
by liu
04:59
created

Query::model()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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