Completed
Push — 6.0 ( 96489f...74e33c )
by liu
02:46
created

Query::tableRaw()   A

Complexity

Conditions 1
Paths 1

Size

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