Completed
Push — 6.0 ( 0f7073...d5b9ea )
by liu
03:56
created

Builder::bindParser()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 4
ccs 0
cts 3
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
// +----------------------------------------------------------------------
1 ignored issue
show
Coding Style introduced by
You must use "/**" style comments for a file comment
Loading history...
3
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
6
// +----------------------------------------------------------------------
7
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
8
// +----------------------------------------------------------------------
9
// | Author: liu21st <[email protected]>
10
// +----------------------------------------------------------------------
11
declare (strict_types = 1);
12
13
namespace think\db;
14
15
use Closure;
16
use PDO;
17
use 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' == $query->getFieldType($key))) {
155
                $val = json_encode($val);
156
            }
157
158
            if (false !== strpos($key, '->')) {
159
                list($key, $name) = explode('->', $key, 2);
160
                $item             = $this->parseKey($query, $key);
161
                $result[$item]    = 'json_set(' . $item . ', \'$.' . $name . '\', ' . $this->parseDataBind($query, $key . '->' . $name, $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
        $item = [];
400
401
        foreach (explode('&', $field) as $k) {
402
            $item[] = $this->parseWhereItem($query, $k, $value, $binds);
403
        }
404
405
        return ' ' . $logic . ' ( ' . implode(' AND ', $item) . ' )';
406
    }
407
408
    /**
409
     * 不同字段使用相同查询条件(OR)
410
     * @access protected
411
     * @param  Query  $query 查询对象
412
     * @param  mixed  $value 查询条件
413
     * @param  string $field 查询字段
414
     * @param  string $logic Logic
415
     * @param  array  $binds 参数绑定
416
     * @return string
417
     */
418
    protected function parseFieldsOr(Query $query, $value, string $field, string $logic, array $binds): string
419
    {
420
        $item = [];
421
422
        foreach (explode('|', $field) as $k) {
423
            $item[] = $this->parseWhereItem($query, $k, $value, $binds);
424
        }
425
426
        return ' ' . $logic . ' ( ' . implode(' OR ', $item) . ' )';
427
    }
428
429
    /**
430
     * 闭包查询
431
     * @access protected
432
     * @param  Query   $query 查询对象
433
     * @param  Closure $value 查询条件
434
     * @param  string  $logic Logic
435
     * @return string
436
     */
437
    protected function parseClousreWhere(Query $query, Closure $value, string $logic): string
438
    {
439
        $newQuery = $query->newQuery()->setConnection($this->connection);
440
        $value($newQuery);
441
        $whereClause = $this->buildWhere($query, $newQuery->getOptions('where') ?: []);
442
443
        if (!empty($whereClause)) {
444
            $where = ' ' . $logic . ' ( ' . $whereClause . ' )';
445
        }
446
447
        return $where ?? '';
448
    }
449
450
    /**
451
     * 复合条件查询
452
     * @access protected
453
     * @param  Query  $query 查询对象
454
     * @param  mixed  $value 查询条件
455
     * @param  mixed  $field 查询字段
456
     * @param  string $logic Logic
457
     * @param  array  $binds 参数绑定
458
     * @return string
459
     */
460
    protected function parseMultiWhereField(Query $query, $value, $field, string $logic, array $binds): string
461
    {
462
        array_unshift($value, $field);
463
464
        $where = [];
465
        foreach ($value as $item) {
466
            $where[] = $this->parseWhereItem($query, array_shift($item), $item, $binds);
467
        }
468
469
        return ' ' . $logic . ' ( ' . implode(' AND ', $where) . ' )';
470
    }
471
472
    /**
473
     * where子单元分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
474
     * @access protected
475
     * @param  Query $query 查询对象
476
     * @param  mixed $field 查询字段
477
     * @param  array $val   查询条件
478
     * @param  array $binds 参数绑定
479
     * @return string
480
     */
481
    protected function parseWhereItem(Query $query, $field, array $val, array $binds = []): string
482
    {
483
        // 字段分析
484
        $key = $field ? $this->parseKey($query, $field, true) : '';
485
486
        list($exp, $value) = $val;
487
488
        // 检测操作符
489
        if (!is_string($exp)) {
490
            throw new Exception('where express error:' . var_export($exp, true));
491
        }
492
493
        $exp = strtoupper($exp);
494
        if (isset($this->exp[$exp])) {
495
            $exp = $this->exp[$exp];
496
        }
497
498
        if (is_string($field)) {
499
            $bindType = $binds[$field] ?? PDO::PARAM_STR;
500
        } else {
501
            $bindType = PDO::PARAM_STR;
502
        }
503
504
        if ($value instanceof Raw) {
505
506
        } elseif (is_object($value) && method_exists($value, '__toString')) {
507
            // 对象数据写入
508
            $value = $value->__toString();
509
        }
510
511
        if (is_scalar($value) && !in_array($exp, ['EXP', 'NOT NULL', 'NULL', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN']) && strpos($exp, 'TIME') === false) {
512
            if (is_string($value) && 0 === strpos($value, ':') && $query->isBind(substr($value, 1))) {
513
            } else {
514
                $name  = $query->bindValue($value, $bindType);
515
                $value = ':' . $name;
516
            }
517
        }
518
519
        // 解析查询表达式
520
        foreach ($this->parser as $fun => $parse) {
521
            if (in_array($exp, $parse)) {
522
                return $this->$fun($query, $key, $exp, $value, $field, $bindType, $val[2] ?? 'AND');
523
            }
524
        }
525
526
        throw new Exception('where express error:' . $exp);
527
    }
528
529
    /**
530
     * 模糊查询
531
     * @access protected
532
     * @param  Query   $query   查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 3 found
Loading history...
533
     * @param  string  $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
534
     * @param  string  $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
535
     * @param  array   $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
536
     * @param  string  $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
537
     * @param  integer $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
538
     * @param  string  $logic
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
539
     * @return string
540
     */
541
    protected function parseLike(Query $query, string $key, string $exp, $value, $field, int $bindType, string $logic): string
542
    {
543
        // 模糊匹配
544
        if (is_array($value)) {
0 ignored issues
show
introduced by
The condition is_array($value) is always true.
Loading history...
545
            $array = [];
546
            foreach ($value as $item) {
547
                $name    = $query->bindValue($item, $bindType);
548
                $array[] = $key . ' ' . $exp . ' :' . $name;
549
            }
550
551
            $whereStr = '(' . implode(' ' . strtoupper($logic) . ' ', $array) . ')';
552
        } else {
553
            $whereStr = $key . ' ' . $exp . ' ' . $value;
554
        }
555
556
        return $whereStr;
557
    }
558
559
    /**
560
     * 表达式查询
561
     * @access protected
562
     * @param  Query   $query   查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 3 found
Loading history...
563
     * @param  string  $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
564
     * @param  string  $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
565
     * @param  array   $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
566
     * @param  string  $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
567
     * @param  integer $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
568
     * @return string
569
     */
570
    protected function parseExp(Query $query, string $key, string $exp, Raw $value, string $field, int $bindType): string
571
    {
572
        // 表达式查询
573
        return '( ' . $key . ' ' . $value->getValue() . ' )';
574
    }
575
576
    /**
577
     * 表达式查询
578
     * @access protected
579
     * @param  Query   $query   查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 3 found
Loading history...
580
     * @param  string  $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
581
     * @param  string  $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
582
     * @param  array   $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
583
     * @param  string  $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
584
     * @param  integer $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
585
     * @return string
586
     */
587
    protected function parseColumn(Query $query, string $key, $exp, array $value, string $field, int $bindType): string
588
    {
589
        // 字段比较查询
590
        list($op, $field) = $value;
591
592
        if (!in_array(trim($op), ['=', '<>', '>', '>=', '<', '<='])) {
593
            throw new Exception('where express error:' . var_export($value, true));
594
        }
595
596
        return '( ' . $key . ' ' . $op . ' ' . $this->parseKey($query, $field, true) . ' )';
597
    }
598
599
    /**
600
     * Null查询
601
     * @access protected
602
     * @param  Query   $query   查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 3 found
Loading history...
603
     * @param  string  $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
604
     * @param  string  $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
605
     * @param  mixed   $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
606
     * @param  string  $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
607
     * @param  integer $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
608
     * @return string
609
     */
610
    protected function parseNull(Query $query, string $key, string $exp, $value, $field, int $bindType): string
611
    {
612
        // NULL 查询
613
        return $key . ' IS ' . $exp;
614
    }
615
616
    /**
617
     * 范围查询
618
     * @access protected
619
     * @param  Query   $query   查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 3 found
Loading history...
620
     * @param  string  $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
621
     * @param  string  $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
622
     * @param  mixed   $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
623
     * @param  string  $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
624
     * @param  integer $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
625
     * @return string
626
     */
627
    protected function parseBetween(Query $query, string $key, string $exp, $value, $field, int $bindType): string
628
    {
629
        // BETWEEN 查询
630
        $data = is_array($value) ? $value : explode(',', $value);
631
632
        $min = $query->bindValue($data[0], $bindType);
633
        $max = $query->bindValue($data[1], $bindType);
634
635
        return $key . ' ' . $exp . ' :' . $min . ' AND :' . $max . ' ';
636
    }
637
638
    /**
639
     * Exists查询
640
     * @access protected
641
     * @param  Query   $query   查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 3 found
Loading history...
642
     * @param  string  $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
643
     * @param  string  $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
644
     * @param  mixed   $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
645
     * @param  string  $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
646
     * @param  integer $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
647
     * @return string
648
     */
649
    protected function parseExists(Query $query, string $key, string $exp, $value, string $field, int $bindType): string
650
    {
651
        // EXISTS 查询
652
        if ($value instanceof \Closure) {
653
            $value = $this->parseClosure($query, $value, false);
654
        } elseif ($value instanceof Raw) {
655
            $value = $value->getValue();
656
        } else {
657
            throw new Exception('where express error:' . $value);
658
        }
659
660
        return $exp . ' ( ' . $value . ' )';
661
    }
662
663
    /**
664
     * 时间比较查询
665
     * @access protected
666
     * @param  Query   $query  查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 2 found
Loading history...
667
     * @param  string  $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
668
     * @param  string  $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
669
     * @param  mixed   $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
670
     * @param  string  $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
671
     * @param  integer $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
672
     * @return string
673
     */
674
    protected function parseTime(Query $query, string $key, string $exp, $value, $field, int $bindType): string
675
    {
676
        return $key . ' ' . substr($exp, 0, 2) . ' ' . $this->parseDateTime($query, $value, $field, $bindType);
677
    }
678
679
    /**
680
     * 大小比较查询
681
     * @access protected
682
     * @param  Query   $query   查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 3 found
Loading history...
683
     * @param  string  $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
684
     * @param  string  $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
685
     * @param  mixed   $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
686
     * @param  string  $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
687
     * @param  integer $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
688
     * @return string
689
     */
690
    protected function parseCompare(Query $query, string $key, string $exp, $value, $field, int $bindType): string
691
    {
692
        if (is_array($value)) {
693
            throw new Exception('where express error:' . $exp . var_export($value, true));
694
        }
695
696
        // 比较运算
697
        if ($value instanceof \Closure) {
698
            $value = $this->parseClosure($query, $value);
699
        }
700
701
        if ('=' == $exp && is_null($value)) {
702
            return $key . ' IS NULL';
703
        }
704
705
        return $key . ' ' . $exp . ' ' . $value;
706
    }
707
708
    /**
709
     * 时间范围查询
710
     * @access protected
711
     * @param  Query   $query     查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 5 found
Loading history...
712
     * @param  string  $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
713
     * @param  string  $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
714
     * @param  mixed   $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
715
     * @param  string  $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
716
     * @param  integer $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
717
     * @return string
718
     */
719
    protected function parseBetweenTime(Query $query, string $key, string $exp, $value, $field, int $bindType): string
720
    {
721
        if (is_string($value)) {
722
            $value = explode(',', $value);
723
        }
724
725
        return $key . ' ' . substr($exp, 0, -4)
726
        . $this->parseDateTime($query, $value[0], $field, $bindType)
727
        . ' AND '
728
        . $this->parseDateTime($query, $value[1], $field, $bindType);
729
730
    }
731
732
    /**
733
     * IN查询
734
     * @access protected
735
     * @param  Query   $query   查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 3 found
Loading history...
736
     * @param  string  $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
737
     * @param  string  $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
738
     * @param  mixed   $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
739
     * @param  string  $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
740
     * @param  integer $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
741
     * @return string
742
     */
743
    protected function parseIn(Query $query, string $key, string $exp, $value, $field, int $bindType): string
744
    {
745
        // IN 查询
746
        if ($value instanceof \Closure) {
747
            $value = $this->parseClosure($query, $value, false);
748
        } elseif ($value instanceof Raw) {
749
            $value = $value->getValue();
750
        } else {
751
            $value = array_unique(is_array($value) ? $value : explode(',', $value));
752
            $array = [];
753
754
            foreach ($value as $v) {
755
                $name    = $query->bindValue($v, $bindType);
756
                $array[] = ':' . $name;
757
            }
758
759
            if (count($array) == 1) {
760
                return $key . ' = ' . $array[0];
761
            } else {
762
                $zone  = implode(',', $array);
763
                $value = empty($zone) ? "''" : $zone;
764
            }
765
        }
766
767
        return $key . ' ' . $exp . ' (' . $value . ')';
768
    }
769
770
    /**
771
     * 闭包子查询
772
     * @access protected
773
     * @param  Query    $query 查询对象
774
     * @param  \Closure $call
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
775
     * @param  bool     $show
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
776
     * @return string
777
     */
778
    protected function parseClosure(Query $query, \Closure $call, bool $show = true): string
779
    {
780
        $newQuery = $query->newQuery()->setConnection($this->connection);
781
        $call($newQuery);
782
783
        return $newQuery->buildSql($show);
784
    }
785
786
    /**
787
     * 日期时间条件解析
788
     * @access protected
789
     * @param  Query   $query 查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 1 found
Loading history...
790
     * @param  mixed   $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
791
     * @param  string  $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
792
     * @param  integer $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
793
     * @return string
794
     */
795
    protected function parseDateTime(Query $query, $value, string $key, int $bindType): string
796
    {
797
        $options = $query->getOptions();
798
799
        // 获取时间字段类型
800
        if (strpos($key, '.')) {
801
            list($table, $key) = explode('.', $key);
802
803
            if (isset($options['alias']) && $pos = array_search($table, $options['alias'])) {
804
                $table = $pos;
0 ignored issues
show
Unused Code introduced by
The assignment to $table is dead and can be removed.
Loading history...
805
            }
806
        } else {
807
            $table = $options['table'];
808
        }
809
810
        $type = $query->getFieldType($key);
811
812
        if ($type) {
813
            if (is_string($value)) {
814
                $value = strtotime($value) ?: $value;
815
            }
816
817
            if (is_int($value)) {
818
                if (preg_match('/(datetime|timestamp)/is', $type)) {
819
                    // 日期及时间戳类型
820
                    $value = date('Y-m-d H:i:s', $value);
821
                } elseif (preg_match('/(date)/is', $type)) {
822
                    // 日期及时间戳类型
823
                    $value = date('Y-m-d', $value);
824
                }
825
            }
826
        }
827
828
        $name = $query->bindValue($value, $bindType);
829
830
        return ':' . $name;
831
    }
832
833
    /**
834
     * limit分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
835
     * @access protected
836
     * @param  Query $query 查询对象
837
     * @param  mixed $limit
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
838
     * @return string
839
     */
840
    protected function parseLimit(Query $query, string $limit): string
841
    {
842
        return (!empty($limit) && false === strpos($limit, '(')) ? ' LIMIT ' . $limit . ' ' : '';
843
    }
844
845
    /**
846
     * join分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
847
     * @access protected
848
     * @param  Query $query 查询对象
849
     * @param  array $join
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
850
     * @return string
851
     */
852
    protected function parseJoin(Query $query, array $join): string
853
    {
854
        $joinStr = '';
855
856
        foreach ($join as $item) {
857
            list($table, $type, $on) = $item;
858
859
            if (strpos($on, '=')) {
860
                list($val1, $val2) = explode('=', $on, 2);
861
862
                $condition = $this->parseKey($query, $val1) . '=' . $this->parseKey($query, $val2);
863
            } else {
864
                $condition = $on;
865
            }
866
867
            $table = $this->parseTable($query, $table);
868
869
            $joinStr .= ' ' . $type . ' JOIN ' . $table . ' ON ' . $condition;
870
        }
871
872
        return $joinStr;
873
    }
874
875
    /**
876
     * order分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
877
     * @access protected
878
     * @param  Query $query 查询对象
879
     * @param  array $order
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
880
     * @return string
881
     */
882
    protected function parseOrder(Query $query, array $order): string
883
    {
884
        $array = [];
885
        foreach ($order as $key => $val) {
886
            if ($val instanceof Raw) {
887
                $array[] = $val->getValue();
888
            } elseif (is_array($val) && preg_match('/^[\w\.]+$/', $key)) {
889
                $array[] = $this->parseOrderField($query, $key, $val);
890
            } elseif ('[rand]' == $val) {
891
                $array[] = $this->parseRand($query);
892
            } elseif (is_string($val)) {
893
                if (is_numeric($key)) {
894
                    list($key, $sort) = explode(' ', strpos($val, ' ') ? $val : $val . ' ');
895
                } else {
896
                    $sort = $val;
897
                }
898
899
                if (preg_match('/^[\w\.]+$/', $key)) {
900
                    $sort    = strtoupper($sort);
901
                    $sort    = in_array($sort, ['ASC', 'DESC'], true) ? ' ' . $sort : '';
902
                    $array[] = $this->parseKey($query, $key, true) . $sort;
903
                } else {
904
                    throw new Exception('order express error:' . $key);
905
                }
906
            }
907
        }
908
909
        return empty($array) ? '' : ' ORDER BY ' . implode(',', $array);
910
    }
911
912
    /**
913
     * 随机排序
914
     * @access protected
915
     * @param  Query $query 查询对象
916
     * @return string
917
     */
918
    protected function parseRand(Query $query): string
919
    {
920
        return '';
921
    }
922
923
    /**
924
     * orderField分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
925
     * @access protected
926
     * @param  Query  $query 查询对象
927
     * @param  string $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
928
     * @param  array  $val
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
929
     * @return string
930
     */
931
    protected function parseOrderField(Query $query, string $key, array $val): string
932
    {
933
        if (isset($val['sort'])) {
934
            $sort = $val['sort'];
935
            unset($val['sort']);
936
        } else {
937
            $sort = '';
938
        }
939
940
        $sort = strtoupper($sort);
941
        $sort = in_array($sort, ['ASC', 'DESC'], true) ? ' ' . $sort : '';
942
        $bind = $query->getFieldsBindType();
943
944
        foreach ($val as $item) {
945
            $val[] = $this->parseDataBind($query, $key, $item, $bind);
946
        }
947
948
        return 'field(' . $this->parseKey($query, $key, true) . ',' . implode(',', $val) . ')' . $sort;
949
    }
950
951
    /**
952
     * group分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
953
     * @access protected
954
     * @param  Query $query 查询对象
955
     * @param  mixed $group
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
956
     * @return string
957
     */
958
    protected function parseGroup(Query $query, $group): string
959
    {
960
        if (empty($group)) {
961
            return '';
962
        }
963
964
        if (is_string($group)) {
965
            $group = explode(',', $group);
966
        }
967
968
        $val = [];
969
        foreach ($group as $key) {
970
            $val[] = $this->parseKey($query, $key);
971
        }
972
973
        return ' GROUP BY ' . implode(',', $val);
974
    }
975
976
    /**
977
     * having分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
978
     * @access protected
979
     * @param  Query  $query  查询对象
980
     * @param  string $having
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
981
     * @return string
982
     */
983
    protected function parseHaving(Query $query, string $having): string
984
    {
985
        return !empty($having) ? ' HAVING ' . $having : '';
986
    }
987
988
    /**
989
     * comment分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
990
     * @access protected
991
     * @param  Query  $query  查询对象
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 2 found
Loading history...
992
     * @param  string $comment
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
993
     * @return string
994
     */
995
    protected function parseComment(Query $query, string $comment): string
996
    {
997
        if (false !== strpos($comment, '*/')) {
998
            $comment = strstr($comment, '*/', true);
999
        }
1000
1001
        return !empty($comment) ? ' /* ' . $comment . ' */' : '';
1002
    }
1003
1004
    /**
1005
     * distinct分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
1006
     * @access protected
1007
     * @param  Query $query  查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 2 found
Loading history...
1008
     * @param  mixed $distinct
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1009
     * @return string
1010
     */
1011
    protected function parseDistinct(Query $query, bool $distinct): string
1012
    {
1013
        return !empty($distinct) ? ' DISTINCT ' : '';
1014
    }
1015
1016
    /**
1017
     * union分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
1018
     * @access protected
1019
     * @param  Query $query 查询对象
1020
     * @param  array $union
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1021
     * @return string
1022
     */
1023
    protected function parseUnion(Query $query, array $union): string
1024
    {
1025
        if (empty($union)) {
1026
            return '';
1027
        }
1028
1029
        $type = $union['type'];
1030
        unset($union['type']);
1031
1032
        foreach ($union as $u) {
1033
            if ($u instanceof \Closure) {
1034
                $sql[] = $type . ' ' . $this->parseClosure($query, $u);
1035
            } elseif (is_string($u)) {
1036
                $sql[] = $type . ' ( ' . $u . ' )';
1037
            }
1038
        }
1039
1040
        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 1032. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
1041
    }
1042
1043
    /**
1044
     * index分析,可在操作链中指定需要强制使用的索引
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
1045
     * @access protected
1046
     * @param  Query $query 查询对象
1047
     * @param  mixed $index
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1048
     * @return string
1049
     */
1050
    protected function parseForce(Query $query, $index): string
1051
    {
1052
        if (empty($index)) {
1053
            return '';
1054
        }
1055
1056
        if (is_array($index)) {
1057
            $index = join(',', $index);
1058
        }
1059
1060
        return sprintf(" FORCE INDEX ( %s ) ", $index);
1061
    }
1062
1063
    /**
1064
     * 设置锁机制
1065
     * @access protected
1066
     * @param  Query       $query 查询对象
1067
     * @param  bool|string $lock
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1068
     * @return string
1069
     */
1070
    protected function parseLock(Query $query, $lock = false): string
1071
    {
1072
        if (is_bool($lock)) {
1073
            return $lock ? ' FOR UPDATE ' : '';
1074
        }
1075
1076
        if (is_string($lock) && !empty($lock)) {
1077
            return ' ' . trim($lock) . ' ';
1078
        } else {
1079
            return '';
1080
        }
1081
    }
1082
1083
    /**
1084
     * 生成查询SQL
1085
     * @access public
1086
     * @param  Query $query 查询对象
1087
     * @param  bool  $one   是否仅获取一个记录
1088
     * @return string
1089
     */
1090
    public function select(Query $query, bool $one = false): string
1091
    {
1092
        $options = $query->getOptions();
1093
1094
        return str_replace(
1095
            ['%TABLE%', '%DISTINCT%', '%EXTRA%', '%FIELD%', '%JOIN%', '%WHERE%', '%GROUP%', '%HAVING%', '%ORDER%', '%LIMIT%', '%UNION%', '%LOCK%', '%COMMENT%', '%FORCE%'],
1096
            [
1097
                $this->parseTable($query, $options['table']),
1098
                $this->parseDistinct($query, $options['distinct']),
1099
                $this->parseExtra($query, $options['extra']),
1100
                $this->parseField($query, $options['field']),
1101
                $this->parseJoin($query, $options['join']),
1102
                $this->parseWhere($query, $options['where']),
1103
                $this->parseGroup($query, $options['group']),
1104
                $this->parseHaving($query, $options['having']),
1105
                $this->parseOrder($query, $options['order']),
1106
                $this->parseLimit($query, $one ? '1' : $options['limit']),
1107
                $this->parseUnion($query, $options['union']),
1108
                $this->parseLock($query, $options['lock']),
1109
                $this->parseComment($query, $options['comment']),
1110
                $this->parseForce($query, $options['force']),
1111
            ],
1112
            $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...
1113
    }
1114
1115
    /**
1116
     * 生成Insert SQL
1117
     * @access public
1118
     * @param  Query $query 查询对象
1119
     * @return string
1120
     */
1121
    public function insert(Query $query): string
1122
    {
1123
        $options = $query->getOptions();
1124
1125
        // 分析并处理数据
1126
        $data = $this->parseData($query, $options['data']);
1127
        if (empty($data)) {
1128
            return '';
1129
        }
1130
1131
        $fields = array_keys($data);
1132
        $values = array_values($data);
1133
1134
        return str_replace(
1135
            ['%INSERT%', '%TABLE%', '%EXTRA%', '%FIELD%', '%DATA%', '%COMMENT%'],
1136
            [
1137
                !empty($options['replace']) ? 'REPLACE' : 'INSERT',
1138
                $this->parseTable($query, $options['table']),
1139
                $this->parseExtra($query, $options['extra']),
1140
                implode(' , ', $fields),
1141
                implode(' , ', $values),
1142
                $this->parseComment($query, $options['comment']),
1143
            ],
1144
            $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...
1145
    }
1146
1147
    /**
1148
     * 生成insertall SQL
1149
     * @access public
1150
     * @param  Query $query   查询对象
1151
     * @param  array $dataSet 数据集
1152
     * @return string
1153
     */
1154
    public function insertAll(Query $query, array $dataSet): string
1155
    {
1156
        $options = $query->getOptions();
1157
1158
        // 获取绑定信息
1159
        $bind = $query->getFieldsBindType();
1160
1161
        // 获取合法的字段
1162
        if ('*' == $options['field']) {
1163
            $allowFields = array_keys($bind);
1164
        } else {
1165
            $allowFields = $options['field'];
1166
        }
1167
1168
        $fields = [];
1169
        $values = [];
1170
1171
        foreach ($dataSet as $k => $data) {
1172
            $data = $this->parseData($query, $data, $allowFields, $bind);
1173
1174
            $values[] = 'SELECT ' . implode(',', array_values($data));
1175
1176
            if (!isset($insertFields)) {
1177
                $insertFields = array_keys($data);
1178
            }
1179
        }
1180
1181
        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 1171. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
1182
            $fields[] = $this->parseKey($query, $field);
1183
        }
1184
1185
        return str_replace(
1186
            ['%INSERT%', '%TABLE%', '%EXTRA%', '%FIELD%', '%DATA%', '%COMMENT%'],
1187
            [
1188
                !empty($options['replace']) ? 'REPLACE' : 'INSERT',
1189
                $this->parseTable($query, $options['table']),
1190
                $this->parseExtra($query, $options['extra']),
1191
                implode(' , ', $fields),
1192
                implode(' UNION ALL ', $values),
1193
                $this->parseComment($query, $options['comment']),
1194
            ],
1195
            $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...
1196
    }
1197
1198
    /**
1199
     * 生成slect insert SQL
1200
     * @access public
1201
     * @param  Query  $query  查询对象
1202
     * @param  array  $fields 数据
1203
     * @param  string $table  数据表
1204
     * @return string
1205
     */
1206
    public function selectInsert(Query $query, array $fields, string $table): string
1207
    {
1208
        foreach ($fields as &$field) {
1209
            $field = $this->parseKey($query, $field, true);
1210
        }
1211
1212
        return 'INSERT INTO ' . $this->parseTable($query, $table) . ' (' . implode(',', $fields) . ') ' . $this->select($query);
1213
    }
1214
1215
    /**
1216
     * 生成update SQL
1217
     * @access public
1218
     * @param  Query $query 查询对象
1219
     * @return string
1220
     */
1221
    public function update(Query $query): string
1222
    {
1223
        $options = $query->getOptions();
1224
1225
        $data = $this->parseData($query, $options['data']);
1226
1227
        if (empty($data)) {
1228
            return '';
1229
        }
1230
1231
        $set = [];
1232
        foreach ($data as $key => $val) {
1233
            $set[] = $key . ' = ' . $val;
1234
        }
1235
1236
        return str_replace(
1237
            ['%TABLE%', '%EXTRA%', '%SET%', '%JOIN%', '%WHERE%', '%ORDER%', '%LIMIT%', '%LOCK%', '%COMMENT%'],
1238
            [
1239
                $this->parseTable($query, $options['table']),
1240
                $this->parseExtra($query, $options['extra']),
1241
                implode(' , ', $set),
1242
                $this->parseJoin($query, $options['join']),
1243
                $this->parseWhere($query, $options['where']),
1244
                $this->parseOrder($query, $options['order']),
1245
                $this->parseLimit($query, $options['limit']),
1246
                $this->parseLock($query, $options['lock']),
1247
                $this->parseComment($query, $options['comment']),
1248
            ],
1249
            $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...
1250
    }
1251
1252
    /**
1253
     * 生成delete SQL
1254
     * @access public
1255
     * @param  Query $query 查询对象
1256
     * @return string
1257
     */
1258
    public function delete(Query $query): string
1259
    {
1260
        $options = $query->getOptions();
1261
1262
        return str_replace(
1263
            ['%TABLE%', '%EXTRA%', '%USING%', '%JOIN%', '%WHERE%', '%ORDER%', '%LIMIT%', '%LOCK%', '%COMMENT%'],
1264
            [
1265
                $this->parseTable($query, $options['table']),
1266
                $this->parseExtra($query, $options['extra']),
1267
                !empty($options['using']) ? ' USING ' . $this->parseTable($query, $options['using']) . ' ' : '',
1268
                $this->parseJoin($query, $options['join']),
1269
                $this->parseWhere($query, $options['where']),
1270
                $this->parseOrder($query, $options['order']),
1271
                $this->parseLimit($query, $options['limit']),
1272
                $this->parseLock($query, $options['lock']),
1273
                $this->parseComment($query, $options['comment']),
1274
            ],
1275
            $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...
1276
    }
1277
}
1278