Completed
Push — 6.0 ( 709e53...02746e )
by liu
03:17
created

Builder::parseWhereField()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

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