Passed
Push — 5.2 ( 45acc4...549dc7 )
by liu
02:28
created

Builder::buildWhere()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 8
nc 6
nop 2
dl 0
loc 17
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 PDO;
16
use think\Exception;
17
18
abstract class Builder
1 ignored issue
show
Coding Style introduced by
Missing class doc comment
Loading history...
19
{
20
    /**
21
     * Connection对象
22
     * @var Connection
23
     */
24
    protected $connection;
25
26
    /**
27
     * 查询表达式映射
28
     * @var array
29
     */
30
    protected $exp = ['NOTLIKE' => 'NOT LIKE', 'NOTIN' => 'NOT IN', 'NOTBETWEEN' => 'NOT BETWEEN', 'NOTEXISTS' => 'NOT EXISTS', 'NOTNULL' => 'NOT NULL', 'NOTBETWEEN TIME' => 'NOT BETWEEN TIME'];
31
32
    /**
33
     * 查询表达式解析
34
     * @var array
35
     */
36
    protected $parser = [
37
        'parseCompare'     => ['=', '<>', '>', '>=', '<', '<='],
38
        'parseLike'        => ['LIKE', 'NOT LIKE'],
39
        'parseBetween'     => ['NOT BETWEEN', 'BETWEEN'],
40
        'parseIn'          => ['NOT IN', 'IN'],
41
        'parseExp'         => ['EXP'],
42
        'parseNull'        => ['NOT NULL', 'NULL'],
43
        'parseBetweenTime' => ['BETWEEN TIME', 'NOT BETWEEN TIME'],
44
        'parseTime'        => ['< TIME', '> TIME', '<= TIME', '>= TIME'],
45
        'parseExists'      => ['NOT EXISTS', 'EXISTS'],
46
        'parseColumn'      => ['COLUMN'],
47
    ];
48
49
    /**
50
     * SELECT SQL表达式
51
     * @var string
52
     */
53
    protected $selectSql = 'SELECT%DISTINCT%%EXTRA% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%UNION%%ORDER%%LIMIT% %LOCK%%COMMENT%';
54
55
    /**
56
     * INSERT SQL表达式
57
     * @var string
58
     */
59
    protected $insertSql = '%INSERT%%EXTRA% INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%';
60
61
    /**
62
     * INSERT ALL SQL表达式
63
     * @var string
64
     */
65
    protected $insertAllSql = '%INSERT%%EXTRA% INTO %TABLE% (%FIELD%) %DATA% %COMMENT%';
66
67
    /**
68
     * UPDATE SQL表达式
69
     * @var string
70
     */
71
    protected $updateSql = 'UPDATE%EXTRA% %TABLE% SET %SET%%JOIN%%WHERE%%ORDER%%LIMIT% %LOCK%%COMMENT%';
72
73
    /**
74
     * DELETE SQL表达式
75
     * @var string
76
     */
77
    protected $deleteSql = 'DELETE%EXTRA% FROM %TABLE%%USING%%JOIN%%WHERE%%ORDER%%LIMIT% %LOCK%%COMMENT%';
78
79
    /**
80
     * 架构函数
81
     * @access public
82
     * @param  Connection    $connection 数据库连接对象实例
83
     */
84
    public function __construct(Connection $connection)
85
    {
86
        $this->connection = $connection;
87
    }
88
89
    /**
90
     * 获取当前的连接对象实例
91
     * @access public
92
     * @return Connection
93
     */
94
    public function getConnection(): Connection
95
    {
96
        return $this->connection;
97
    }
98
99
    /**
100
     * 注册查询表达式解析
101
     * @access public
102
     * @param  string    $name   解析方法
103
     * @param  array     $parser 匹配表达式数据
104
     * @return $this
105
     */
106
    public function bindParser(string $name, array $parser)
107
    {
108
        $this->parser[$name] = $parser;
109
        return $this;
110
    }
111
112
    /**
113
     * 数据分析
114
     * @access protected
115
     * @param  Query     $query     查询对象
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 5 found
Loading history...
116
     * @param  array     $data      数据
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 6 found
Loading history...
117
     * @param  array     $fields    字段信息
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
118
     * @param  array     $bind      参数绑定
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 6 found
Loading history...
119
     * @return array
120
     */
121
    protected function parseData(Query $query, array $data = [], array $fields = [], array $bind = []): array
122
    {
123
        if (empty($data)) {
124
            return [];
125
        }
126
127
        $options = $query->getOptions();
128
129
        // 获取绑定信息
130
        if (empty($bind)) {
131
            $bind = $query->getFieldsBindType();
132
        }
133
134
        if (empty($fields)) {
135
            if ('*' == $options['field']) {
136
                $fields = array_keys($bind);
137
            } else {
138
                $fields = $options['field'];
139
            }
140
        }
141
142
        $result = [];
143
144
        foreach ($data as $key => $val) {
145
            $item = $this->parseKey($query, $key, true);
146
147
            if ($val instanceof Raw) {
148
                $result[$item] = $val->getValue();
149
                continue;
150
            } elseif (!is_scalar($val) && (in_array($key, (array) $query->getOptions('json')) || 'json' == $this->connection->getFieldsType($options['table'], $key))) {
151
                $val = json_encode($val);
152
            }
153
154
            if (false !== strpos($key, '->')) {
155
                list($key, $name) = explode('->', $key);
156
                $item             = $this->parseKey($query, $key);
157
                $result[$item]    = 'json_set(' . $item . ', \'$.' . $name . '\', ' . $this->parseDataBind($query, $key, $val, $bind) . ')';
158
            } elseif (false === strpos($key, '.') && !in_array($key, $fields, true)) {
159
                if ($options['strict']) {
160
                    throw new Exception('fields not exists:[' . $key . ']');
161
                }
162
            } elseif (is_null($val)) {
163
                $result[$item] = 'NULL';
164
            } elseif (is_array($val) && !empty($val)) {
165
                switch (strtoupper($val[0])) {
166
                    case 'INC':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 16 spaces, found 20
Loading history...
167
                        $result[$item] = $item . ' + ' . floatval($val[1]);
168
                        break;
169
                    case 'DEC':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 16 spaces, found 20
Loading history...
170
                        $result[$item] = $item . ' - ' . floatval($val[1]);
171
                        break;
172
                }
173
            } elseif (is_scalar($val)) {
174
                // 过滤非标量数据
175
                $result[$item] = $this->parseDataBind($query, $key, $val, $bind);
176
            }
177
        }
178
179
        return $result;
180
    }
181
182
    /**
183
     * 数据绑定处理
184
     * @access protected
185
     * @param  Query     $query     查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 5 found
Loading history...
186
     * @param  string    $key       字段名
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 7 found
Loading history...
187
     * @param  mixed     $data      数据
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 6 found
Loading history...
188
     * @param  array     $bind      绑定数据
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 6 found
Loading history...
189
     * @return string
190
     */
191
    protected function parseDataBind(Query $query, string $key, $data, array $bind = []): string
192
    {
193
        if ($data instanceof Raw) {
194
            return $data->getValue();
195
        }
196
197
        $name = $query->bindValue($data, $bind[$key] ?? PDO::PARAM_STR);
198
199
        return ':' . $name;
200
    }
201
202
    /**
203
     * 字段名分析
204
     * @access public
205
     * @param  Query  $query    查询对象
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 4 found
Loading history...
206
     * @param  mixed  $key      字段名
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 6 found
Loading history...
207
     * @param  bool   $strict   严格检测
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 3 found
Loading history...
208
     * @return string
209
     */
210
    public function parseKey(Query $query, $key, bool $strict = false): string
211
    {
212
        return $key;
213
    }
214
215
    /**
216
     * 查询额外参数分析
217
     * @access protected
218
     * @param  Query  $query    查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
219
     * @param  string $extra    额外参数
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
220
     * @return string
221
     */
222
    protected function parseExtra(Query $query, string $extra): string
223
    {
224
        return preg_match('/^[\w]+$/i', $extra) ? ' ' . strtoupper($extra) : '';
225
    }
226
227
    /**
228
     * field分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
229
     * @access protected
230
     * @param  Query     $query     查询对象
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 5 found
Loading history...
231
     * @param  mixed     $fields    字段名
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
232
     * @return string
233
     */
234
    protected function parseField(Query $query, $fields): string
235
    {
236
        if (is_array($fields)) {
237
            // 支持 'field1'=>'field2' 这样的字段别名定义
238
            $array = [];
239
240
            foreach ($fields as $key => $field) {
241
                if ($field instanceof Raw) {
242
                    $array[] = $field->getValue();
243
                } elseif (!is_numeric($key)) {
244
                    $array[] = $this->parseKey($query, $key) . ' AS ' . $this->parseKey($query, $field, true);
245
                } else {
246
                    $array[] = $this->parseKey($query, $field);
247
                }
248
            }
249
250
            $fieldsStr = implode(',', $array);
251
        } else {
252
            $fieldsStr = '*';
253
        }
254
255
        return $fieldsStr;
256
    }
257
258
    /**
259
     * table分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
260
     * @access protected
261
     * @param  Query     $query     查询对象
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 5 found
Loading history...
262
     * @param  mixed     $tables    表名
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
263
     * @return string
264
     */
265
    protected function parseTable(Query $query, $tables): string
266
    {
267
        $item    = [];
268
        $options = $query->getOptions();
269
270
        foreach ((array) $tables as $key => $table) {
271
            if ($table instanceof Raw) {
272
                $item[] = $table->getValue();
273
            } elseif (!is_numeric($key)) {
274
                $item[] = $this->parseKey($query, $key) . ' ' . $this->parseKey($query, $table);
275
            } elseif (isset($options['alias'][$table])) {
276
                $item[] = $this->parseKey($query, $table) . ' ' . $this->parseKey($query, $options['alias'][$table]);
277
            } else {
278
                $item[] = $this->parseKey($query, $table);
279
            }
280
        }
281
282
        return implode(',', $item);
283
    }
284
285
    /**
286
     * where分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
287
     * @access protected
288
     * @param  Query     $query   查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 3 found
Loading history...
289
     * @param  mixed     $where   查询条件
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 3 found
Loading history...
290
     * @return string
291
     */
292
    protected function parseWhere(Query $query, array $where): string
293
    {
294
        $options  = $query->getOptions();
295
        $whereStr = $this->buildWhere($query, $where);
296
297
        if (!empty($options['soft_delete'])) {
298
            // 附加软删除条件
299
            list($field, $condition) = $options['soft_delete'];
300
301
            $binds    = $query->getFieldsBindType();
302
            $whereStr = $whereStr ? '( ' . $whereStr . ' ) AND ' : '';
303
            $whereStr = $whereStr . $this->parseWhereItem($query, $field, $condition, '', $binds);
304
        }
305
306
        return empty($whereStr) ? '' : ' WHERE ' . $whereStr;
307
    }
308
309
    /**
310
     * 生成查询条件SQL
311
     * @access public
312
     * @param  Query     $query     查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 5 found
Loading history...
313
     * @param  mixed     $where     查询条件
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 5 found
Loading history...
314
     * @return string
315
     */
316
    public function buildWhere(Query $query, array $where): string
317
    {
318
        if (empty($where)) {
319
            $where = [];
320
        }
321
322
        $whereStr = '';
323
324
        $binds = $query->getFieldsBindType();
325
326
        foreach ($where as $logic => $val) {
327
            $str = $this->parseWhereLogic($query, $logic, $val, $binds);
328
329
            $whereStr .= empty($whereStr) ? substr(implode(' ', $str), strlen($logic) + 1) : implode(' ', $str);
330
        }
331
332
        return $whereStr;
333
    }
334
335
    protected function parseWhereLogic(Query $query, string $logic, $val, array $binds = [])
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
336
    {
337
        $str = [];
338
        foreach ($val as $value) {
339
            if ($value instanceof Raw) {
340
                $str[] = ' ' . $logic . ' ( ' . $value->getValue() . ' )';
341
                continue;
342
            }
343
344
            if (is_array($value)) {
345
                if (key($value) !== 0) {
346
                    throw new Exception('where express error:' . var_export($value, true));
347
                }
348
                $field = array_shift($value);
349
            } elseif (!($value instanceof \Closure)) {
350
                throw new Exception('where express error:' . var_export($value, true));
351
            }
352
353
            if ($value instanceof \Closure) {
354
                // 使用闭包查询
355
                $newQuery = $query->newQuery()->setConnection($this->connection);
356
                $value($newQuery);
357
                $whereClause = $this->buildWhere($query, $newQuery->getOptions('where') ?: []);
358
359
                if (!empty($whereClause)) {
360
                    $str[] = ' ' . $logic . ' ( ' . $whereClause . ' )';
361
                }
362
            } elseif (is_array($field)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $field does not seem to be defined for all execution paths leading up to this point.
Loading history...
363
                array_unshift($value, $field);
364
                $str2 = [];
365
                foreach ($value as $item) {
366
                    $str2[] = $this->parseWhereItem($query, array_shift($item), $item, $logic, $binds);
367
                }
368
369
                $str[] = ' ' . $logic . ' ( ' . implode(' AND ', $str2) . ' )';
370
            } elseif ($field instanceof Raw) {
371
                $str[] = ' ' . $logic . ' ' . $this->parseWhereItem($query, $field, $value, $logic, $binds);
372
            } elseif (strpos($field, '|')) {
373
                // 不同字段使用相同查询条件(OR)
374
                $array = explode('|', $field);
375
                $item  = [];
376
377
                foreach ($array as $k) {
378
                    $item[] = $this->parseWhereItem($query, $k, $value, '', $binds);
379
                }
380
381
                $str[] = ' ' . $logic . ' ( ' . implode(' OR ', $item) . ' )';
382
            } elseif (strpos($field, '&')) {
383
                // 不同字段使用相同查询条件(AND)
384
                $array = explode('&', $field);
385
                $item  = [];
386
387
                foreach ($array as $k) {
388
                    $item[] = $this->parseWhereItem($query, $k, $value, '', $binds);
389
                }
390
391
                $str[] = ' ' . $logic . ' ( ' . implode(' AND ', $item) . ' )';
392
            } else {
393
                // 对字段使用表达式查询
394
                $field = is_string($field) ? $field : '';
395
                $str[] = ' ' . $logic . ' ' . $this->parseWhereItem($query, $field, $value, $logic, $binds);
396
            }
397
        }
398
399
        return $str;
400
    }
401
402
    // where子单元分析
403
    protected function parseWhereItem(Query $query, $field, $val, $rule = '', array $binds = []): string
0 ignored issues
show
Coding Style introduced by
You must use "/**" style comments for a function comment
Loading history...
404
    {
405
        // 字段分析
406
        $key = $field ? $this->parseKey($query, $field, true) : '';
407
408
        // 查询规则和条件
409
        if (!is_array($val)) {
410
            $val = is_null($val) ? ['NULL', ''] : ['=', $val];
411
        }
412
413
        list($exp, $value) = $val;
414
415
        // 对一个字段使用多个查询条件
416
        if (is_array($exp)) {
417
            $item = array_pop($val);
418
419
            // 传入 or 或者 and
420
            if (is_string($item) && in_array($item, ['AND', 'and', 'OR', 'or'])) {
421
                $rule = $item;
422
            } else {
423
                array_push($val, $item);
424
            }
425
            $str = [];
426
            foreach ($val as $k => $item) {
427
                $str[] = $this->parseWhereItem($query, $field, $item, $rule, $binds);
428
            }
429
430
            return '( ' . implode(' ' . $rule . ' ', $str) . ' )';
431
        }
432
433
        // 检测操作符
434
        $exp = strtoupper($exp);
435
        if (isset($this->exp[$exp])) {
436
            $exp = $this->exp[$exp];
437
        }
438
439
        if (is_string($field)) {
440
            $bindType = $binds[$field] ?? PDO::PARAM_STR;
441
        } else {
442
            $bindType = PDO::PARAM_STR;
443
        }
444
445
        if ($value instanceof Expression) {
446
            return $value->parse($query, $key, $exp, $field, $bindType);
447
        }
448
449
        if ($value instanceof Raw) {
450
451
        } elseif (is_object($value) && method_exists($value, '__toString')) {
452
            // 对象数据写入
453
            $value = $value->__toString();
454
        }
455
456
        if (is_scalar($value) && !in_array($exp, ['EXP', 'NOT NULL', 'NULL', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN']) && strpos($exp, 'TIME') === false) {
457
            if (is_string($value) && 0 === strpos($value, ':') && $query->isBind(substr($value, 1))) {
458
            } else {
459
                $name  = $query->bindValue($value, $bindType);
460
                $value = ':' . $name;
461
            }
462
        }
463
464
        // 解析查询表达式
465
        foreach ($this->parser as $fun => $parse) {
466
            if (in_array($exp, $parse)) {
467
                $whereStr = $this->$fun($query, $key, $exp, $value, $field, $bindType, $val[2] ?? 'AND');
468
                break;
469
            }
470
        }
471
472
        if (!isset($whereStr)) {
473
            throw new Exception('where express error:' . $exp);
474
        }
475
476
        return $whereStr;
477
    }
478
479
    /**
480
     * 模糊查询
481
     * @access protected
482
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
483
     * @param  string    $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
484
     * @param  string    $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
485
     * @param  mixed     $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
486
     * @param  string    $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
487
     * @param  integer   $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
488
     * @param  string    $logic
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
489
     * @return string
490
     */
491
    protected function parseLike(Query $query, string $key, string $exp, $value, $field, int $bindType, string $logic): string
492
    {
493
        // 模糊匹配
494
        if (is_array($value)) {
495
            $array = [];
496
            foreach ($value as $item) {
497
                $name    = $query->bindValue($item, $bindType);
498
                $array[] = $key . ' ' . $exp . ' :' . $name;
499
            }
500
501
            $whereStr = '(' . implode(' ' . strtoupper($logic) . ' ', $array) . ')';
502
        } else {
503
            $whereStr = $key . ' ' . $exp . ' ' . $value;
504
        }
505
506
        return $whereStr;
507
    }
508
509
    /**
510
     * 表达式查询
511
     * @access protected
512
     * @param  Query        $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
513
     * @param  string       $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
514
     * @param  string       $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
515
     * @param  Raw          $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
516
     * @param  string       $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
517
     * @param  integer      $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
518
     * @return string
519
     */
520
    protected function parseExp(Query $query, string $key, string $exp, Raw $value, string $field, int $bindType): string
521
    {
522
        // 表达式查询
523
        return '( ' . $key . ' ' . $value->getValue() . ' )';
524
    }
525
526
    /**
527
     * 表达式查询
528
     * @access protected
529
     * @param  Query        $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
530
     * @param  string       $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
531
     * @param  string       $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
532
     * @param  array        $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
533
     * @param  string       $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
534
     * @param  integer      $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
535
     * @return string
536
     */
537
    protected function parseColumn(Query $query, string $key, $exp, array $value, string $field, int $bindType): string
538
    {
539
        // 字段比较查询
540
        list($op, $field) = $value;
541
542
        if (!in_array(trim($op), ['=', '<>', '>', '>=', '<', '<='])) {
543
            throw new Exception('where express error:' . var_export($value, true));
544
        }
545
546
        return '( ' . $key . ' ' . $op . ' ' . $this->parseKey($query, $field, true) . ' )';
547
    }
548
549
    /**
550
     * Null查询
551
     * @access protected
552
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
553
     * @param  string    $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
554
     * @param  string    $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
555
     * @param  mixed     $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
556
     * @param  string    $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
557
     * @param  integer   $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
558
     * @return string
559
     */
560
    protected function parseNull(Query $query, string $key, string $exp, $value, $field, int $bindType): string
561
    {
562
        // NULL 查询
563
        return $key . ' IS ' . $exp;
564
    }
565
566
    /**
567
     * 范围查询
568
     * @access protected
569
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
570
     * @param  string    $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
571
     * @param  string    $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
572
     * @param  mixed     $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
573
     * @param  string    $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
574
     * @param  integer   $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
575
     * @return string
576
     */
577
    protected function parseBetween(Query $query, string $key, string $exp, $value, $field, int $bindType): string
578
    {
579
        // BETWEEN 查询
580
        $data = is_array($value) ? $value : explode(',', $value);
581
582
        $min = $query->bindValue($data[0], $bindType);
583
        $max = $query->bindValue($data[1], $bindType);
584
585
        return $key . ' ' . $exp . ' :' . $min . ' AND :' . $max . ' ';
586
    }
587
588
    /**
589
     * Exists查询
590
     * @access protected
591
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
592
     * @param  string    $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
593
     * @param  string    $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
594
     * @param  mixed     $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
595
     * @param  string    $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
596
     * @param  integer   $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
597
     * @return string
598
     */
599
    protected function parseExists(Query $query, string $key, string $exp, $value, string $field, int $bindType): string
600
    {
601
        // EXISTS 查询
602
        if ($value instanceof \Closure) {
603
            $value = $this->parseClosure($query, $value, false);
604
        } elseif ($value instanceof Raw) {
605
            $value = $value->getValue();
606
        } else {
607
            throw new Exception('where express error:' . $value);
608
        }
609
610
        return $exp . ' (' . $value . ')';
611
    }
612
613
    /**
614
     * 时间比较查询
615
     * @access protected
616
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
617
     * @param  string    $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
618
     * @param  string    $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
619
     * @param  mixed     $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
620
     * @param  string    $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
621
     * @param  integer   $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
622
     * @return string
623
     */
624
    protected function parseTime(Query $query, string $key, string $exp, $value, $field, int $bindType): string
625
    {
626
        return $key . ' ' . substr($exp, 0, 2) . ' ' . $this->parseDateTime($query, $value, $field, $bindType);
627
    }
628
629
    /**
630
     * 大小比较查询
631
     * @access protected
632
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
633
     * @param  string    $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
634
     * @param  string    $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
635
     * @param  mixed     $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
636
     * @param  string    $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
637
     * @param  integer   $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
638
     * @return string
639
     */
640
    protected function parseCompare(Query $query, string $key, string $exp, $value, $field, int $bindType): string
641
    {
642
        if (is_array($value)) {
643
            throw new Exception('where express error:' . $exp . var_export($value, true));
644
        }
645
646
        // 比较运算
647
        if ($value instanceof \Closure) {
648
            $value = $this->parseClosure($query, $value);
649
        }
650
651
        return $key . ' ' . $exp . ' ' . $value;
652
    }
653
654
    /**
655
     * 时间范围查询
656
     * @access protected
657
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
658
     * @param  string    $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
659
     * @param  string    $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
660
     * @param  mixed     $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
661
     * @param  string    $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
662
     * @param  integer   $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
663
     * @return string
664
     */
665
    protected function parseBetweenTime(Query $query, string $key, string $exp, $value, $field, int $bindType): string
666
    {
667
        if (is_string($value)) {
668
            $value = explode(',', $value);
669
        }
670
671
        return $key . ' ' . substr($exp, 0, -4)
672
        . $this->parseDateTime($query, $value[0], $field, $bindType)
673
        . ' AND '
674
        . $this->parseDateTime($query, $value[1], $field, $bindType);
675
676
    }
677
678
    /**
679
     * IN查询
680
     * @access protected
681
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
682
     * @param  string    $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
683
     * @param  string    $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
684
     * @param  mixed     $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
685
     * @param  string    $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
686
     * @param  integer   $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
687
     * @return string
688
     */
689
    protected function parseIn(Query $query, string $key, string $exp, $value, $field, int $bindType): string
690
    {
691
        // IN 查询
692
        if ($value instanceof \Closure) {
693
            $value = $this->parseClosure($query, $value, false);
694
        } elseif ($value instanceof Raw) {
695
            $value = $value->getValue();
696
        } else {
697
            $value = array_unique(is_array($value) ? $value : explode(',', $value));
698
            $array = [];
699
700
            foreach ($value as $v) {
701
                $name    = $query->bindValue($v, $bindType);
702
                $array[] = ':' . $name;
703
            }
704
705
            $zone  = implode(',', $array);
706
            $value = empty($zone) ? "''" : $zone;
707
        }
708
709
        return $key . ' ' . $exp . ' (' . $value . ')';
710
    }
711
712
    /**
713
     * 闭包子查询
714
     * @access protected
715
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
716
     * @param  \Closure  $call
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
717
     * @param  bool      $show
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
718
     * @return string
719
     */
720
    protected function parseClosure(Query $query, \Closure $call, bool $show = true): string
721
    {
722
        $newQuery = $query->newQuery()->setConnection($this->connection);
723
        $call($newQuery);
724
725
        return $newQuery->buildSql($show);
726
    }
727
728
    /**
729
     * 日期时间条件解析
730
     * @access protected
731
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
732
     * @param  mixed     $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
733
     * @param  string    $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
734
     * @param  integer   $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
735
     * @return string
736
     */
737
    protected function parseDateTime(Query $query, $value, string $key, int $bindType): string
738
    {
739
        $options = $query->getOptions();
740
741
        // 获取时间字段类型
742
        if (strpos($key, '.')) {
743
            list($table, $key) = explode('.', $key);
744
745
            if (isset($options['alias']) && $pos = array_search($table, $options['alias'])) {
746
                $table = $pos;
747
            }
748
        } else {
749
            $table = $options['table'];
750
        }
751
752
        $type = $this->connection->getTableInfo($table, 'type');
753
754
        if (isset($type[$key])) {
755
            $info = $type[$key];
756
            if (is_string($value)) {
757
                $value = strtotime($value) ?: $value;
758
            }
759
760
            if (is_int($value)) {
761
                if (preg_match('/(datetime|timestamp)/is', $info)) {
762
                    // 日期及时间戳类型
763
                    $value = date('Y-m-d H:i:s', $value);
764
                } elseif (preg_match('/(date)/is', $info)) {
765
                    // 日期及时间戳类型
766
                    $value = date('Y-m-d', $value);
767
                }
768
            }
769
        }
770
771
        $name = $query->bindValue($value, $bindType);
772
773
        return ':' . $name;
774
    }
775
776
    /**
777
     * limit分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
778
     * @access protected
779
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
780
     * @param  mixed     $limit
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
781
     * @return string
782
     */
783
    protected function parseLimit(Query $query, string $limit): string
784
    {
785
        return (!empty($limit) && false === strpos($limit, '(')) ? ' LIMIT ' . $limit . ' ' : '';
786
    }
787
788
    /**
789
     * join分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
790
     * @access protected
791
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
792
     * @param  array     $join
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
793
     * @return string
794
     */
795
    protected function parseJoin(Query $query, array $join): string
796
    {
797
        $joinStr = '';
798
799
        foreach ($join as $item) {
800
            list($table, $type, $on) = $item;
801
802
            if (strpos($on, '=')) {
803
                list($val1, $val2) = explode('=', $on, 2);
804
805
                $condition = $this->parseKey($query, $val1) . '=' . $this->parseKey($query, $val2);
806
            } else {
807
                $condition = $on;
808
            }
809
810
            $table = $this->parseTable($query, $table);
811
812
            $joinStr .= ' ' . $type . ' JOIN ' . $table . ' ON ' . $condition;
813
        }
814
815
        return $joinStr;
816
    }
817
818
    /**
819
     * order分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
820
     * @access protected
821
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
822
     * @param  array     $order
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
823
     * @return string
824
     */
825
    protected function parseOrder(Query $query, array $order): string
826
    {
827
        $array = [];
828
        foreach ($order as $key => $val) {
829
            if ($val instanceof Raw) {
830
                $array[] = $val->getValue();
831
            } elseif (is_array($val) && preg_match('/^[\w\.]+$/', $key)) {
832
                $array[] = $this->parseOrderField($query, $key, $val);
833
            } elseif ('[rand]' == $val) {
834
                $array[] = $this->parseRand($query);
835
            } elseif (is_string($val)) {
836
                if (is_numeric($key)) {
837
                    list($key, $sort) = explode(' ', strpos($val, ' ') ? $val : $val . ' ');
838
                } else {
839
                    $sort = $val;
840
                }
841
842
                if (preg_match('/^[\w\.]+$/', $key)) {
843
                    $sort    = strtoupper($sort);
844
                    $sort    = in_array($sort, ['ASC', 'DESC'], true) ? ' ' . $sort : '';
845
                    $array[] = $this->parseKey($query, $key, true) . $sort;
846
                } else {
847
                    throw new Exception('order express error:' . $key);
848
                }
849
            }
850
        }
851
852
        return empty($array) ? '' : ' ORDER BY ' . implode(',', $array);
853
    }
854
855
    /**
856
     * 随机排序
857
     * @access protected
858
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
859
     * @return string
860
     */
861
    protected function parseRand(Query $query): string
862
    {
863
        return '';
864
    }
865
866
    /**
867
     * orderField分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
868
     * @access protected
869
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
870
     * @param  string    $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
871
     * @param  array     $val
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
872
     * @return string
873
     */
874
    protected function parseOrderField(Query $query, string $key, array $val): string
875
    {
876
        if (isset($val['sort'])) {
877
            $sort = $val['sort'];
878
            unset($val['sort']);
879
        } else {
880
            $sort = '';
881
        }
882
883
        $sort = strtoupper($sort);
884
        $sort = in_array($sort, ['ASC', 'DESC'], true) ? ' ' . $sort : '';
885
        $bind = $query->getFieldsBindType();
886
887
        foreach ($val as $item) {
888
            $val[] = $this->parseDataBind($query, $key, $item, $bind);
889
        }
890
891
        return 'field(' . $this->parseKey($query, $key, true) . ',' . implode(',', $val) . ')' . $sort;
892
    }
893
894
    /**
895
     * group分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
896
     * @access protected
897
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
898
     * @param  mixed     $group
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
899
     * @return string
900
     */
901
    protected function parseGroup(Query $query, $group): string
902
    {
903
        if (empty($group)) {
904
            return '';
905
        }
906
907
        if (is_string($group)) {
908
            $group = explode(',', $group);
909
        }
910
911
        $val = [];
912
        foreach ($group as $key) {
913
            $val[] = $this->parseKey($query, $key);
914
        }
915
916
        return ' GROUP BY ' . implode(',', $val);
917
    }
918
919
    /**
920
     * having分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
921
     * @access protected
922
     * @param  Query  $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 8 found
Loading history...
923
     * @param  string $having
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
924
     * @return string
925
     */
926
    protected function parseHaving(Query $query, string $having): string
927
    {
928
        return !empty($having) ? ' HAVING ' . $having : '';
929
    }
930
931
    /**
932
     * comment分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
933
     * @access protected
934
     * @param  Query  $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 8 found
Loading history...
935
     * @param  string $comment
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
936
     * @return string
937
     */
938
    protected function parseComment(Query $query, string $comment): string
939
    {
940
        if (false !== strpos($comment, '*/')) {
941
            $comment = strstr($comment, '*/', true);
942
        }
943
944
        return !empty($comment) ? ' /* ' . $comment . ' */' : '';
945
    }
946
947
    /**
948
     * distinct分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
949
     * @access protected
950
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
951
     * @param  mixed     $distinct
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
952
     * @return string
953
     */
954
    protected function parseDistinct(Query $query, bool $distinct): string
955
    {
956
        return !empty($distinct) ? ' DISTINCT ' : '';
957
    }
958
959
    /**
960
     * union分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
961
     * @access protected
962
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
963
     * @param  array     $union
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
964
     * @return string
965
     */
966
    protected function parseUnion(Query $query, array $union): string
967
    {
968
        if (empty($union)) {
969
            return '';
970
        }
971
972
        $type = $union['type'];
973
        unset($union['type']);
974
975
        foreach ($union as $u) {
976
            if ($u instanceof \Closure) {
977
                $sql[] = $type . ' ' . $this->parseClosure($query, $u);
978
            } elseif (is_string($u)) {
979
                $sql[] = $type . ' ( ' . $u . ' )';
980
            }
981
        }
982
983
        return ' ' . implode(' ', $sql);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $sql seems to be defined by a foreach iteration on line 975. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
984
    }
985
986
    /**
987
     * index分析,可在操作链中指定需要强制使用的索引
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
988
     * @access protected
989
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
990
     * @param  mixed     $index
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
991
     * @return string
992
     */
993
    protected function parseForce(Query $query, $index): string
994
    {
995
        if (empty($index)) {
996
            return '';
997
        }
998
999
        if (is_array($index)) {
1000
            $index = join(',', $index);
1001
        }
1002
1003
        return sprintf(" FORCE INDEX ( %s ) ", $index);
1004
    }
1005
1006
    /**
1007
     * 设置锁机制
1008
     * @access protected
1009
     * @param  Query         $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
1010
     * @param  bool|string   $lock
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1011
     * @return string
1012
     */
1013
    protected function parseLock(Query $query, $lock = false): string
1014
    {
1015
        if (is_bool($lock)) {
1016
            return $lock ? ' FOR UPDATE ' : '';
1017
        }
1018
1019
        if (is_string($lock) && !empty($lock)) {
1020
            return ' ' . trim($lock) . ' ';
1021
        } else {
1022
            return '';
1023
        }
1024
    }
1025
1026
    /**
1027
     * 生成查询SQL
1028
     * @access public
1029
     * @param  Query  $query  查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1030
     * @param  bool   $one    是否仅获取一个记录
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 4 found
Loading history...
1031
     * @return string
1032
     */
1033
    public function select(Query $query, bool $one = false): string
1034
    {
1035
        $options = $query->getOptions();
1036
1037
        return str_replace(
1038
            ['%TABLE%', '%DISTINCT%', '%EXTRA%', '%FIELD%', '%JOIN%', '%WHERE%', '%GROUP%', '%HAVING%', '%ORDER%', '%LIMIT%', '%UNION%', '%LOCK%', '%COMMENT%', '%FORCE%'],
1039
            [
1040
                $this->parseTable($query, $options['table']),
1041
                $this->parseDistinct($query, $options['distinct']),
1042
                $this->parseExtra($query, $options['extra']),
1043
                $this->parseField($query, $options['field']),
1044
                $this->parseJoin($query, $options['join']),
1045
                $this->parseWhere($query, $options['where']),
1046
                $this->parseGroup($query, $options['group']),
1047
                $this->parseHaving($query, $options['having']),
1048
                $this->parseOrder($query, $options['order']),
1049
                $this->parseLimit($query, $one ? '1' : $options['limit']),
1050
                $this->parseUnion($query, $options['union']),
1051
                $this->parseLock($query, $options['lock']),
1052
                $this->parseComment($query, $options['comment']),
1053
                $this->parseForce($query, $options['force']),
1054
            ],
1055
            $this->selectSql);
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 8 spaces, but found 12.
Loading history...
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
1056
    }
1057
1058
    /**
1059
     * 生成Insert SQL
1060
     * @access public
1061
     * @param  Query     $query   查询对象
1062
     * @param  bool      $replace 是否replace
1063
     * @return string
1064
     */
1065
    public function insert(Query $query, bool $replace = false): string
1066
    {
1067
        $options = $query->getOptions();
1068
1069
        // 分析并处理数据
1070
        $data = $this->parseData($query, $options['data']);
1071
        if (empty($data)) {
1072
            return '';
1073
        }
1074
1075
        $fields = array_keys($data);
1076
        $values = array_values($data);
1077
1078
        return str_replace(
1079
            ['%INSERT%', '%TABLE%', '%EXTRA%', '%FIELD%', '%DATA%', '%COMMENT%'],
1080
            [
1081
                $replace ? 'REPLACE' : 'INSERT',
1082
                $this->parseTable($query, $options['table']),
1083
                $this->parseExtra($query, $options['extra']),
1084
                implode(' , ', $fields),
1085
                implode(' , ', $values),
1086
                $this->parseComment($query, $options['comment']),
1087
            ],
1088
            $this->insertSql);
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 8 spaces, but found 12.
Loading history...
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
1089
    }
1090
1091
    /**
1092
     * 生成insertall SQL
1093
     * @access public
1094
     * @param  Query     $query   查询对象
1095
     * @param  array     $dataSet 数据集
1096
     * @param  bool      $replace 是否replace
1097
     * @return string
1098
     */
1099
    public function insertAll(Query $query, array $dataSet, bool $replace = false): string
1100
    {
1101
        $options = $query->getOptions();
1102
1103
        // 获取合法的字段
1104
        if ('*' == $options['field']) {
1105
            $allowFields = $this->connection->getTableFields($options['table']);
1106
        } else {
1107
            $allowFields = $options['field'];
1108
        }
1109
1110
        // 获取绑定信息
1111
        $bind   = $query->getFieldsBindType();
1112
        $fields = [];
1113
        $values = [];
1114
1115
        foreach ($dataSet as $k => $data) {
1116
            $data = $this->parseData($query, $data, $allowFields, $bind);
1117
1118
            $values[] = 'SELECT ' . implode(',', array_values($data));
1119
1120
            if (!isset($insertFields)) {
1121
                $insertFields = array_keys($data);
1122
            }
1123
        }
1124
1125
        foreach ($insertFields as $field) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $insertFields seems to be defined by a foreach iteration on line 1115. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
1126
            $fields[] = $this->parseKey($query, $field);
1127
        }
1128
1129
        return str_replace(
1130
            ['%INSERT%', '%TABLE%', '%EXTRA%', '%FIELD%', '%DATA%', '%COMMENT%'],
1131
            [
1132
                $replace ? 'REPLACE' : 'INSERT',
1133
                $this->parseTable($query, $options['table']),
1134
                $this->parseExtra($query, $options['extra']),
1135
                implode(' , ', $fields),
1136
                implode(' UNION ALL ', $values),
1137
                $this->parseComment($query, $options['comment']),
1138
            ],
1139
            $this->insertAllSql);
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 8 spaces, but found 12.
Loading history...
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
1140
    }
1141
1142
    /**
1143
     * 生成slect insert SQL
1144
     * @access public
1145
     * @param  Query     $query  查询对象
1146
     * @param  array     $fields 数据
1147
     * @param  string    $table  数据表
1148
     * @return string
1149
     */
1150
    public function selectInsert(Query $query, array $fields, string $table): string
1151
    {
1152
        foreach ($fields as &$field) {
1153
            $field = $this->parseKey($query, $field, true);
1154
        }
1155
1156
        return 'INSERT INTO ' . $this->parseTable($query, $table) . ' (' . implode(',', $fields) . ') ' . $this->select($query);
1157
    }
1158
1159
    /**
1160
     * 生成update SQL
1161
     * @access public
1162
     * @param  Query     $query  查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1163
     * @return string
1164
     */
1165
    public function update(Query $query): string
1166
    {
1167
        $options = $query->getOptions();
1168
1169
        $data = $this->parseData($query, $options['data']);
1170
1171
        if (empty($data)) {
1172
            return '';
1173
        }
1174
1175
        $set = [];
1176
        foreach ($data as $key => $val) {
1177
            $set[] = $key . ' = ' . $val;
1178
        }
1179
1180
        return str_replace(
1181
            ['%TABLE%', '%EXTRA%', '%SET%', '%JOIN%', '%WHERE%', '%ORDER%', '%LIMIT%', '%LOCK%', '%COMMENT%'],
1182
            [
1183
                $this->parseTable($query, $options['table']),
1184
                $this->parseExtra($query, $options['extra']),
1185
                implode(' , ', $set),
1186
                $this->parseJoin($query, $options['join']),
1187
                $this->parseWhere($query, $options['where']),
1188
                $this->parseOrder($query, $options['order']),
1189
                $this->parseLimit($query, $options['limit']),
1190
                $this->parseLock($query, $options['lock']),
1191
                $this->parseComment($query, $options['comment']),
1192
            ],
1193
            $this->updateSql);
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 8 spaces, but found 12.
Loading history...
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
1194
    }
1195
1196
    /**
1197
     * 生成delete SQL
1198
     * @access public
1199
     * @param  Query  $query  查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1200
     * @return string
1201
     */
1202
    public function delete(Query $query): string
1203
    {
1204
        $options = $query->getOptions();
1205
1206
        return str_replace(
1207
            ['%TABLE%', '%EXTRA%', '%USING%', '%JOIN%', '%WHERE%', '%ORDER%', '%LIMIT%', '%LOCK%', '%COMMENT%'],
1208
            [
1209
                $this->parseTable($query, $options['table']),
1210
                $this->parseExtra($query, $options['extra']),
1211
                !empty($options['using']) ? ' USING ' . $this->parseTable($query, $options['using']) . ' ' : '',
1212
                $this->parseJoin($query, $options['join']),
1213
                $this->parseWhere($query, $options['where']),
1214
                $this->parseOrder($query, $options['order']),
1215
                $this->parseLimit($query, $options['limit']),
1216
                $this->parseLock($query, $options['lock']),
1217
                $this->parseComment($query, $options['comment']),
1218
            ],
1219
            $this->deleteSql);
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 8 spaces, but found 12.
Loading history...
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
1220
    }
1221
}
1222