Completed
Push — 6.0 ( f2a394...d72635 )
by liu
04:14
created

Fetch::column()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 26
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
cc 5
eloc 13
nc 8
nop 2
dl 0
loc 26
ccs 0
cts 13
cp 0
crap 30
rs 9.5222
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 think\App;
16
use think\Exception;
17
18
/**
19
 * SQL获取类
20
 */
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...
21
class Fetch
22
{
23
    /**
24
     * 查询对象
25
     * @var Query
26
     */
27
    protected $query;
28
29
    /**
30
     * Connection对象
31
     * @var Connection
32
     */
33
    protected $connection;
34
35
    /**
36
     * Builder对象
37
     * @var Builder
38
     */
39
    protected $builder;
40
41
    /**
42
     * 创建一个查询SQL获取对象
43
     *
44
     * @param  Query    $query      查询对象
1 ignored issue
show
Coding Style introduced by
Expected 1 spaces after parameter name; 6 found
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 1 spaces but found 2
Loading history...
45
     */
46
    public function __construct(Query $query)
47
    {
48
        $this->query      = $query;
49
        $this->connection = $query->getConnection();
50
        $this->builder    = $this->connection->getBuilder();
51
    }
52
53
    /**
54
     * 聚合查询
55
     * @access protected
56
     * @param  string $aggregate    聚合方法
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
57
     * @param  string $field        字段名
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter name; 8 found
Loading history...
58
     * @return string
59
     */
60
    protected function aggregate(string $aggregate, string $field): string
61
    {
62
        $this->query->parseOptions();
63
64
        $field = $aggregate . '(' . $this->builder->parseKey($this->query, $field) . ') AS tp_' . strtolower($aggregate);
65
66
        return $this->value($field, 0, false);
67
    }
68
69
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $one should have a doc-comment as per coding-style.
Loading history...
70
     * 得到某个字段的值
71
     * @access public
72
     * @param  string $field   字段名
73
     * @param  mixed  $default 默认值
74
     * @return string
75
     */
76
    public function value(string $field, $default = null, bool $one = true): string
77
    {
78
        $options = $this->query->parseOptions();
79
80
        if (isset($options['field'])) {
81
            $this->query->removeOption('field');
82
        }
83
84
        $this->query->setOption('field', (array) $field);
85
86
        // 生成查询SQL
87
        $sql = $this->builder->select($this->query, $one);
88
89
        if (isset($options['field'])) {
90
            $this->query->setOption('field', $options['field']);
91
        } else {
92
            $this->query->removeOption('field');
93
        }
94
95
        return $this->fetch($sql);
96
    }
97
98
    /**
99
     * 得到某个列的数组
100
     * @access public
101
     * @param  string $field 字段名 多个字段用逗号分隔
102
     * @param  string $key   索引
103
     * @return string
104
     */
105
    public function column(string $field, string $key = ''): string
106
    {
107
        $options = $this->query->parseOptions();
108
109
        if (isset($options['field'])) {
110
            $this->query->removeOption('field');
111
        }
112
113
        if ($key && '*' != $field) {
114
            $field = $key . ',' . $field;
115
        }
116
117
        $field = array_map('trim', explode(',', $field));
118
119
        $this->query->setOption('field', $field);
120
121
        // 生成查询SQL
122
        $sql = $this->builder->select($this->query);
123
124
        if (isset($options['field'])) {
125
            $this->query->setOption('field', $options['field']);
126
        } else {
127
            $this->query->removeOption('field');
128
        }
129
130
        return $this->fetch($sql);
131
    }
132
133
    /**
134
     * 插入记录
135
     * @access public
136
     * @param  array $data 数据
137
     * @return string
138
     */
139
    public function insert(array $data = []): string
140
    {
141
        $options = $this->query->parseOptions();
0 ignored issues
show
Unused Code introduced by
The assignment to $options is dead and can be removed.
Loading history...
142
143
        if (!empty($data)) {
144
            $this->query->setOption('data', $data);
145
        }
146
147
        $sql = $this->builder->insert($this->query);
148
149
        return $this->fetch($sql);
150
    }
151
152
    /**
153
     * 插入记录并获取自增ID
154
     * @access public
155
     * @param  array $data 数据
156
     * @return string
157
     */
158
    public function insertGetId(array $data = []): string
159
    {
160
        return $this->insert($data);
161
    }
162
163
    /**
164
     * 保存数据 自动判断insert或者update
165
     * @access public
166
     * @param  array $data        数据
167
     * @param  bool  $forceInsert 是否强制insert
168
     * @return string
169
     */
170
    public function save(array $data = [], bool $forceInsert = false): string
171
    {
172
        if ($forceInsert) {
173
            return $this->insert($data);
174
        }
175
176
        $data = array_merge($this->query->getOptions('data') ?: [], $data);
177
178
        $this->query->setOption('data', $data);
179
180
        if ($this->query->getOptions('where')) {
181
            $isUpdate = true;
182
        } else {
183
            $isUpdate = $this->query->parseUpdateData($data);
184
        }
185
186
        return $isUpdate ? $this->update() : $this->insert();
187
    }
188
189
    /**
190
     * 批量插入记录
191
     * @access public
192
     * @param  array     $dataSet 数据集
193
     * @param  integer   $limit   每次写入数据限制
194
     * @return string
195
     */
196
    public function insertAll(array $dataSet = [], int $limit = null): string
197
    {
198
        $options = $this->query->parseOptions();
199
200
        if (empty($dataSet)) {
201
            $dataSet = $options['data'];
202
        }
203
204
        if (empty($limit) && !empty($options['limit'])) {
205
            $limit = $options['limit'];
206
        }
207
208
        if ($limit) {
209
            $array    = array_chunk($dataSet, $limit, true);
210
            $fetchSql = [];
211
            foreach ($array as $item) {
212
                $sql  = $this->builder->insertAll($this->query, $item);
213
                $bind = $this->query->getBind();
214
215
                $fetchSql[] = $this->connection->getRealSql($sql, $bind);
216
            }
217
218
            return implode(';', $fetchSql);
219
        }
220
221
        $sql = $this->builder->insertAll($this->query, $dataSet);
222
223
        return $this->fetch($sql);
224
    }
225
226
    /**
227
     * 通过Select方式插入记录
228
     * @access public
229
     * @param  array    $fields 要插入的数据表字段名
230
     * @param  string   $table  要插入的数据表名
231
     * @return string
232
     */
233
    public function selectInsert(array $fields, string $table): string
234
    {
235
        $this->query->parseOptions();
236
        $sql = $this->builder->selectInsert($this->query, $fields, $table);
237
238
        return $this->fetch($sql);
239
    }
240
241
    /**
242
     * 更新记录
243
     * @access public
244
     * @param  mixed $data 数据
245
     * @return string
246
     */
247
    public function update(array $data = []): string
248
    {
249
        $options = $this->query->parseOptions();
250
251
        $data = !empty($data) ? $data : $options['data'];
252
253
        $pk = $this->query->getPk();
254
255
        if (empty($options['where'])) {
256
            // 如果存在主键数据 则自动作为更新条件
257
            if (is_string($pk) && isset($data[$pk])) {
258
                $this->query->where($pk, '=', $data[$pk]);
259
                unset($data[$pk]);
260
            } elseif (is_array($pk)) {
261
                // 增加复合主键支持
262
                foreach ($pk as $field) {
263
                    if (isset($data[$field])) {
264
                        $this->query->where($field, '=', $data[$field]);
265
                    } else {
266
                        // 如果缺少复合主键数据则不执行
267
                        throw new Exception('miss complex primary data');
268
                    }
269
                    unset($data[$field]);
270
                }
271
            }
272
273
            if (empty($this->query->getOptions('where'))) {
274
                // 如果没有任何更新条件则不执行
275
                throw new Exception('miss update condition');
276
            }
277
        }
278
279
        // 更新数据
280
        $this->query->setOption('data', $data);
281
282
        // 生成UPDATE SQL语句
283
        $sql = $this->builder->update($this->query);
284
285
        return $this->fetch($sql);
286
    }
287
288
    /**
289
     * 删除记录
290
     * @access public
291
     * @param  mixed $data 表达式 true 表示强制删除
292
     * @return string
293
     */
294
    public function delete($data = null): string
295
    {
296
        $options = $this->query->parseOptions();
297
298
        if (!is_null($data) && true !== $data) {
299
            // AR模式分析主键条件
300
            $this->query->parsePkWhere($data);
301
        }
302
303
        if (!empty($options['soft_delete'])) {
304
            // 软删除
305
            list($field, $condition) = $options['soft_delete'];
306
            if ($condition) {
307
                $this->query->setOption('soft_delete', null);
308
                $this->query->setOption('data', [$field => $condition]);
309
                // 生成删除SQL语句
310
                $sql = $this->builder->delete($this->query);
311
                return $this->fetch($sql);
312
            }
313
        }
314
315
        // 生成删除SQL语句
316
        $sql = $this->builder->delete($this->query);
317
318
        return $this->fetch($sql);
319
    }
320
321
    /**
322
     * 查找记录 返回SQL
323
     * @access public
324
     * @param  mixed $data
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
325
     * @return string
326
     */
327
    public function select($data = null): string
328
    {
329
        $this->query->parseOptions();
330
331
        if (!is_null($data)) {
332
            // 主键条件分析
333
            $this->query->parsePkWhere($data);
334
        }
335
336
        // 生成查询SQL
337
        $sql = $this->builder->select($this->query);
338
339
        return $this->fetch($sql);
340
    }
341
342
    /**
343
     * 查找单条记录 返回SQL语句
344
     * @access public
345
     * @param  mixed $data
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
346
     * @return string
347
     */
348
    public function find($data = null): string
349
    {
350
        $this->query->parseOptions();
351
352
        if (!is_null($data)) {
353
            // AR模式分析主键条件
354
            $this->query->parsePkWhere($data);
355
        }
356
357
        // 生成查询SQL
358
        $sql = $this->builder->select($this->query, true);
359
360
        // 获取实际执行的SQL语句
361
        return $this->fetch($sql);
362
    }
363
364
    /**
365
     * 查找多条记录 如果不存在则抛出异常
366
     * @access public
367
     * @param  mixed $data
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
368
     * @return string
369
     */
370
    public function selectOrFail($data = null): string
371
    {
372
        return $this->select($data);
373
    }
374
375
    /**
376
     * 查找单条记录 如果不存在则抛出异常
377
     * @access public
378
     * @param  mixed $data
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
379
     * @return string
380
     */
381
    public function findOrFail($data = null): string
382
    {
383
        return $this->find($data);
384
    }
385
386
    /**
387
     * 查找单条记录 不存在返回空数据(或者空模型)
388
     * @access public
389
     * @param  mixed $data 数据
390
     * @return string
391
     */
392
    public function findOrEmpty($data = null)
393
    {
394
        return $this->find($data);
395
    }
396
397
    /**
398
     * 获取实际的SQL语句
399
     * @access public
400
     * @param  string $sql
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
401
     * @return string
402
     */
403
    public function fetch(string $sql): string
404
    {
405
        $bind = $this->query->getBind();
406
407
        return $this->connection->getRealSql($sql, $bind);
408
    }
409
410
    /**
411
     * COUNT查询
412
     * @access public
413
     * @param  string $field 字段名
414
     * @return string
415
     */
416
    public function count(string $field = '*'): string
417
    {
418
        $options = $this->query->parseOptions();
419
420
        if (!empty($options['group'])) {
421
            // 支持GROUP
422
            $bind   = $this->query->getBind();
423
            $subSql = $this->query->options($options)->field('count(' . $field . ') AS think_count')->bind($bind)->buildSql();
424
425
            $query = $this->query->newQuery()->table([$subSql => '_group_count_']);
426
427
            return $query->fetchsql()->aggregate('COUNT', '*');
428
        } else {
429
            return $this->aggregate('COUNT', $field);
430
        }
431
    }
432
433
    /**
434
     * SUM查询
435
     * @access public
436
     * @param  string $field 字段名
437
     * @return string
438
     */
439
    public function sum(string $field): string
440
    {
441
        return $this->aggregate('SUM', $field);
442
    }
443
444
    /**
445
     * MIN查询
446
     * @access public
447
     * @param  string $field    字段名
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
448
     * @return string
449
     */
450
    public function min(string $field): string
451
    {
452
        return $this->aggregate('MIN', $field);
453
    }
454
455
    /**
456
     * MAX查询
457
     * @access public
458
     * @param  string $field    字段名
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
459
     * @return string
460
     */
461
    public function max(string $field): string
462
    {
463
        return $this->aggregate('MAX', $field);
464
    }
465
466
    /**
467
     * AVG查询
468
     * @access public
469
     * @param  string $field 字段名
470
     * @return string
471
     */
472
    public function avg(string $field): string
473
    {
474
        return $this->aggregate('AVG', $field);
475
    }
476
477
    public function __call($method, $args)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __call()
Loading history...
478
    {
479
        if (strtolower(substr($method, 0, 5)) == 'getby') {
480
            // 根据某个字段获取记录
481
            $field = App::parseName(substr($method, 5));
482
            return $this->where($field, '=', $args[0])->find();
0 ignored issues
show
Bug introduced by
The method where() does not exist on think\db\Fetch. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

482
            return $this->/** @scrutinizer ignore-call */ where($field, '=', $args[0])->find();
Loading history...
483
        } elseif (strtolower(substr($method, 0, 10)) == 'getfieldby') {
484
            // 根据某个字段获取记录的某个值
485
            $name = App::parseName(substr($method, 10));
486
            return $this->where($name, '=', $args[0])->value($args[1]);
487
        }
488
489
        $result = call_user_func_array([$this->query, $method], $args);
490
        return $result === $this->query ? $this : $result;
491
    }
492
}
493