Completed
Push — 6.0 ( 1a5a40...59914a )
by liu
03:56
created

Builder::parseClousre()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 2
nop 3
dl 0
loc 11
ccs 0
cts 7
cp 0
crap 12
rs 10
c 0
b 0
f 0
1
<?php
2
// +----------------------------------------------------------------------
1 ignored issue
show
Coding Style introduced by
You must use "/**" style comments for a file comment
Loading history...
3
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
6
// +----------------------------------------------------------------------
7
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
8
// +----------------------------------------------------------------------
9
// | Author: liu21st <[email protected]>
10
// +----------------------------------------------------------------------
11
declare (strict_types = 1);
12
13
namespace think\db;
14
15
use PDO;
16
use think\Exception;
17
18
/**
19
 * Db Builder
20
 */
5 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @author tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
21
abstract class Builder
22
{
23
    /**
24
     * Connection对象
25
     * @var Connection
26
     */
27
    protected $connection;
28
29
    /**
30
     * 查询表达式映射
31
     * @var array
32
     */
33
    protected $exp = ['NOTLIKE' => 'NOT LIKE', 'NOTIN' => 'NOT IN', 'NOTBETWEEN' => 'NOT BETWEEN', 'NOTEXISTS' => 'NOT EXISTS', 'NOTNULL' => 'NOT NULL', 'NOTBETWEEN TIME' => 'NOT BETWEEN TIME'];
34
35
    /**
36
     * 查询表达式解析
37
     * @var array
38
     */
39
    protected $parser = [
40
        'parseCompare'     => ['=', '<>', '>', '>=', '<', '<='],
41
        'parseLike'        => ['LIKE', 'NOT LIKE'],
42
        'parseBetween'     => ['NOT BETWEEN', 'BETWEEN'],
43
        'parseIn'          => ['NOT IN', 'IN'],
44
        'parseExp'         => ['EXP'],
45
        'parseNull'        => ['NOT NULL', 'NULL'],
46
        'parseBetweenTime' => ['BETWEEN TIME', 'NOT BETWEEN TIME'],
47
        'parseTime'        => ['< TIME', '> TIME', '<= TIME', '>= TIME'],
48
        'parseExists'      => ['NOT EXISTS', 'EXISTS'],
49
        'parseColumn'      => ['COLUMN'],
50
    ];
51
52
    /**
53
     * SELECT SQL表达式
54
     * @var string
55
     */
56
    protected $selectSql = 'SELECT%DISTINCT%%EXTRA% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%UNION%%ORDER%%LIMIT% %LOCK%%COMMENT%';
57
58
    /**
59
     * INSERT SQL表达式
60
     * @var string
61
     */
62
    protected $insertSql = '%INSERT%%EXTRA% INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%';
63
64
    /**
65
     * INSERT ALL SQL表达式
66
     * @var string
67
     */
68
    protected $insertAllSql = '%INSERT%%EXTRA% INTO %TABLE% (%FIELD%) %DATA% %COMMENT%';
69
70
    /**
71
     * UPDATE SQL表达式
72
     * @var string
73
     */
74
    protected $updateSql = 'UPDATE%EXTRA% %TABLE% SET %SET%%JOIN%%WHERE%%ORDER%%LIMIT% %LOCK%%COMMENT%';
75
76
    /**
77
     * DELETE SQL表达式
78
     * @var string
79
     */
80
    protected $deleteSql = 'DELETE%EXTRA% FROM %TABLE%%USING%%JOIN%%WHERE%%ORDER%%LIMIT% %LOCK%%COMMENT%';
81
82
    /**
83
     * 架构函数
84
     * @access public
85
     * @param  Connection    $connection 数据库连接对象实例
86
     */
87
    public function __construct(Connection $connection)
88
    {
89
        $this->connection = $connection;
90
    }
91
92
    /**
93
     * 获取当前的连接对象实例
94
     * @access public
95
     * @return Connection
96
     */
97
    public function getConnection(): Connection
98
    {
99
        return $this->connection;
100
    }
101
102
    /**
103
     * 注册查询表达式解析
104
     * @access public
105
     * @param  string    $name   解析方法
106
     * @param  array     $parser 匹配表达式数据
107
     * @return $this
108
     */
109
    public function bindParser(string $name, array $parser)
110
    {
111
        $this->parser[$name] = $parser;
112
        return $this;
113
    }
114
115
    /**
116
     * 数据分析
117
     * @access protected
118
     * @param  Query     $query     查询对象
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 5 found
Loading history...
119
     * @param  array     $data      数据
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 6 found
Loading history...
120
     * @param  array     $fields    字段信息
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
121
     * @param  array     $bind      参数绑定
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 6 found
Loading history...
122
     * @return array
123
     */
124
    protected function parseData(Query $query, array $data = [], array $fields = [], array $bind = []): array
125
    {
126
        if (empty($data)) {
127
            return [];
128
        }
129
130
        $options = $query->getOptions();
131
132
        // 获取绑定信息
133
        if (empty($bind)) {
134
            $bind = $query->getFieldsBindType();
135
        }
136
137
        if (empty($fields)) {
138
            if ('*' == $options['field']) {
139
                $fields = array_keys($bind);
140
            } else {
141
                $fields = $options['field'];
142
            }
143
        }
144
145
        $result = [];
146
147
        foreach ($data as $key => $val) {
148
            $item = $this->parseKey($query, $key, true);
149
150
            if ($val instanceof Raw) {
151
                $result[$item] = $val->getValue();
152
                continue;
153
            } elseif (!is_scalar($val) && (in_array($key, (array) $query->getOptions('json')) || 'json' == $this->connection->getFieldsType($options['table'], $key))) {
154
                $val = json_encode($val);
155
            }
156
157
            if (false !== strpos($key, '->')) {
158
                list($key, $name) = explode('->', $key);
159
                $item             = $this->parseKey($query, $key);
160
                $result[$item]    = 'json_set(' . $item . ', \'$.' . $name . '\', ' . $this->parseDataBind($query, $key, $val, $bind) . ')';
161
            } elseif (false === strpos($key, '.') && !in_array($key, $fields, true)) {
162
                if ($options['strict']) {
163
                    throw new Exception('fields not exists:[' . $key . ']');
164
                }
165
            } elseif (is_null($val)) {
166
                $result[$item] = 'NULL';
167
            } elseif (is_array($val) && !empty($val)) {
168
                switch (strtoupper($val[0])) {
169
                    case 'INC':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 16 spaces, found 20
Loading history...
170
                        $result[$item] = $item . ' + ' . floatval($val[1]);
171
                        break;
172
                    case 'DEC':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 16 spaces, found 20
Loading history...
173
                        $result[$item] = $item . ' - ' . floatval($val[1]);
174
                        break;
175
                }
176
            } elseif (is_scalar($val)) {
177
                // 过滤非标量数据
178
                $result[$item] = $this->parseDataBind($query, $key, $val, $bind);
179
            }
180
        }
181
182
        return $result;
183
    }
184
185
    /**
186
     * 数据绑定处理
187
     * @access protected
188
     * @param  Query     $query     查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 5 found
Loading history...
189
     * @param  string    $key       字段名
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 7 found
Loading history...
190
     * @param  mixed     $data      数据
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 6 found
Loading history...
191
     * @param  array     $bind      绑定数据
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 6 found
Loading history...
192
     * @return string
193
     */
194
    protected function parseDataBind(Query $query, string $key, $data, array $bind = []): string
195
    {
196
        if ($data instanceof Raw) {
197
            return $data->getValue();
198
        }
199
200
        $name = $query->bindValue($data, $bind[$key] ?? PDO::PARAM_STR);
201
202
        return ':' . $name;
203
    }
204
205
    /**
206
     * 字段名分析
207
     * @access public
208
     * @param  Query  $query    查询对象
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 4 found
Loading history...
209
     * @param  mixed  $key      字段名
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 6 found
Loading history...
210
     * @param  bool   $strict   严格检测
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 3 found
Loading history...
211
     * @return string
212
     */
213
    public function parseKey(Query $query, $key, bool $strict = false): string
214
    {
215
        return $key;
216
    }
217
218
    /**
219
     * 查询额外参数分析
220
     * @access protected
221
     * @param  Query  $query    查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
222
     * @param  string $extra    额外参数
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
223
     * @return string
224
     */
225
    protected function parseExtra(Query $query, string $extra): string
226
    {
227
        return preg_match('/^[\w]+$/i', $extra) ? ' ' . strtoupper($extra) : '';
228
    }
229
230
    /**
231
     * field分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
232
     * @access protected
233
     * @param  Query     $query     查询对象
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 5 found
Loading history...
234
     * @param  mixed     $fields    字段名
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
235
     * @return string
236
     */
237
    protected function parseField(Query $query, $fields): string
238
    {
239
        if (is_array($fields)) {
240
            // 支持 'field1'=>'field2' 这样的字段别名定义
241
            $array = [];
242
243
            foreach ($fields as $key => $field) {
244
                if ($field instanceof Raw) {
245
                    $array[] = $field->getValue();
246
                } elseif (!is_numeric($key)) {
247
                    $array[] = $this->parseKey($query, $key) . ' AS ' . $this->parseKey($query, $field, true);
248
                } else {
249
                    $array[] = $this->parseKey($query, $field);
250
                }
251
            }
252
253
            $fieldsStr = implode(',', $array);
254
        } else {
255
            $fieldsStr = '*';
256
        }
257
258
        return $fieldsStr;
259
    }
260
261
    /**
262
     * table分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
263
     * @access protected
264
     * @param  Query     $query     查询对象
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 5 found
Loading history...
265
     * @param  mixed     $tables    表名
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
266
     * @return string
267
     */
268
    protected function parseTable(Query $query, $tables): string
269
    {
270
        $item    = [];
271
        $options = $query->getOptions();
272
273
        foreach ((array) $tables as $key => $table) {
274
            if ($table instanceof Raw) {
275
                $item[] = $table->getValue();
276
            } elseif (!is_numeric($key)) {
277
                $item[] = $this->parseKey($query, $key) . ' ' . $this->parseKey($query, $table);
278
            } elseif (isset($options['alias'][$table])) {
279
                $item[] = $this->parseKey($query, $table) . ' ' . $this->parseKey($query, $options['alias'][$table]);
280
            } else {
281
                $item[] = $this->parseKey($query, $table);
282
            }
283
        }
284
285
        return implode(',', $item);
286
    }
287
288
    /**
289
     * where分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
290
     * @access protected
291
     * @param  Query     $query   查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 3 found
Loading history...
292
     * @param  mixed     $where   查询条件
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 3 found
Loading history...
293
     * @return string
294
     */
295
    protected function parseWhere(Query $query, array $where): string
296
    {
297
        $options  = $query->getOptions();
298
        $whereStr = $this->buildWhere($query, $where);
299
300
        if (!empty($options['soft_delete'])) {
301
            // 附加软删除条件
302
            list($field, $condition) = $options['soft_delete'];
303
304
            $binds    = $query->getFieldsBindType();
305
            $whereStr = $whereStr ? '( ' . $whereStr . ' ) AND ' : '';
306
            $whereStr = $whereStr . $this->parseWhereItem($query, $field, $condition, $binds);
307
        }
308
309
        return empty($whereStr) ? '' : ' WHERE ' . $whereStr;
310
    }
311
312
    /**
313
     * 生成查询条件SQL
314
     * @access public
315
     * @param  Query     $query     查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 5 found
Loading history...
316
     * @param  mixed     $where     查询条件
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 5 found
Loading history...
317
     * @return string
318
     */
319
    public function buildWhere(Query $query, array $where): string
320
    {
321
        if (empty($where)) {
322
            $where = [];
323
        }
324
325
        $whereStr = '';
326
327
        $binds = $query->getFieldsBindType();
328
329
        foreach ($where as $logic => $val) {
330
            $str = $this->parseWhereLogic($query, $logic, $val, $binds);
331
332
            $whereStr .= empty($whereStr) ? substr(implode(' ', $str), strlen($logic) + 1) : implode(' ', $str);
333
        }
334
335
        return $whereStr;
336
    }
337
338
    /**
339
     * 不同字段使用相同查询条件(AND)
340
     * @access protected
341
     * @param  Query  $query 查询对象
342
     * @param  string $logic Logic
343
     * @param  array  $val   查询条件
344
     * @param  array  $binds 参数绑定
345
     * @return string
346
     */
347
    protected function parseWhereLogic(Query $query, string $logic, array $val, array $binds = []): array
348
    {
349
        $where = [];
350
        foreach ($val as $value) {
351
            if ($value instanceof Raw) {
352
                $where[] = ' ' . $logic . ' ( ' . $value->getValue() . ' )';
353
                continue;
354
            }
355
356
            if (is_array($value)) {
357
                if (key($value) !== 0) {
358
                    throw new Exception('where express error:' . var_export($value, true));
359
                }
360
                $field = array_shift($value);
361
            } elseif (!($value instanceof \Closure)) {
362
                throw new Exception('where express error:' . var_export($value, true));
363
            }
364
365
            if ($value instanceof \Closure) {
366
                // 使用闭包查询
367
                $where[] = $this->parseClousre($query, $value, $logic);
368
            } 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...
369
                $where[] = $this->parseWhereField($query, $value, $field, $logic, $binds);
0 ignored issues
show
Bug introduced by
$field of type array is incompatible with the type string expected by parameter $field of think\db\Builder::parseWhereField(). ( Ignorable by Annotation )

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

369
                $where[] = $this->parseWhereField($query, $value, /** @scrutinizer ignore-type */ $field, $logic, $binds);
Loading history...
370
            } elseif ($field instanceof Raw) {
371
                $where[] = ' ' . $logic . ' ' . $this->parseWhereItem($query, $field, $value, $binds);
372
            } elseif (strpos($field, '|')) {
373
                $where[] = $this->parseMultiFieldOr($query, $value, $field, $logic, $binds);
374
            } elseif (strpos($field, '&')) {
375
                $where[] = $this->parseMultiFieldAnd($query, $value, $field, $logic, $binds);
376
            } else {
377
                // 对字段使用表达式查询
378
                $field   = is_string($field) ? $field : '';
379
                $where[] = ' ' . $logic . ' ' . $this->parseWhereItem($query, $field, $value, $binds);
380
            }
381
        }
382
383
        return $where;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $where returns the type array|string[] which is incompatible with the documented return type string.
Loading history...
384
    }
385
386
    /**
387
     * 不同字段使用相同查询条件(AND)
388
     * @access protected
389
     * @param  Query  $query 查询对象
390
     * @param  mixed  $value 查询条件
391
     * @param  string $field 查询字段
392
     * @param  string $logic Logic
393
     * @param  array  $binds 参数绑定
394
     * @return string
395
     */
396
    protected function parseMultiFieldAnd(Query $query, $value, string $field, string $logic, array $binds): string
397
    {
398
        $array = explode('&', $field);
399
        $item  = [];
400
401
        foreach ($array 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 parseMultiFieldOr(Query $query, $value, string $field, string $logic, array $binds): string
419
    {
420
        $array = explode('|', $field);
421
        $item  = [];
422
423
        foreach ($array as $k) {
424
            $item[] = $this->parseWhereItem($query, $k, $value, $binds);
425
        }
426
427
        return ' ' . $logic . ' ( ' . implode(' OR ', $item) . ' )';
428
    }
429
430
    /**
431
     * 闭包查询
432
     * @access protected
433
     * @param  Query   $query 查询对象
434
     * @param  Closure $value 查询条件
435
     * @param  string  $logic Logic
436
     * @return string
437
     */
438
    protected function parseClousre(Query $query, Closure $value, string $logic): string
0 ignored issues
show
Bug introduced by
The type think\db\Closure was not found. Did you mean Closure? If so, make sure to prefix the type with \.
Loading history...
439
    {
440
        $newQuery = $query->newQuery()->setConnection($this->connection);
441
        $value($newQuery);
442
        $whereClause = $this->buildWhere($query, $newQuery->getOptions('where') ?: []);
443
444
        if (!empty($whereClause)) {
445
            $where = ' ' . $logic . ' ( ' . $whereClause . ' )';
446
        }
447
448
        return $where ?? '';
449
    }
450
451
    /**
452
     * 复合条件查询
453
     * @access protected
454
     * @param  Query  $query 查询对象
455
     * @param  mixed  $value 查询条件
456
     * @param  string $field 查询字段
457
     * @param  string $logic Logic
458
     * @param  array  $binds 参数绑定
459
     * @return string
460
     */
461
    protected function parseWhereField(Query $query, $value, $field, $logic, $binds): string
462
    {
463
        array_unshift($value, $field);
464
        $str2 = [];
465
        foreach ($value as $item) {
466
            $str2[] = $this->parseWhereItem($query, array_shift($item), $item, $binds);
467
        }
468
469
        return ' ' . $logic . ' ( ' . implode(' AND ', $str2) . ' )';
470
    }
471
472
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $val should have a doc-comment as per coding-style.
Loading history...
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  string $field 查询字段
477
     * @param  array  $value 查询条件
0 ignored issues
show
Coding Style introduced by
Doc comment for parameter $value does not match actual variable name $val
Loading history...
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)) {
0 ignored issues
show
introduced by
The condition is_string($field) is always true.
Loading history...
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; 8 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  mixed     $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)) {
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; 8 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  Raw          $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; 8 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; 8 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; 8 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; 8 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; 8 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; 8 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
        return $key . ' ' . $exp . ' ' . $value;
702
    }
703
704
    /**
705
     * 时间范围查询
706
     * @access protected
707
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
708
     * @param  string    $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
709
     * @param  string    $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
710
     * @param  mixed     $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
711
     * @param  string    $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
712
     * @param  integer   $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
713
     * @return string
714
     */
715
    protected function parseBetweenTime(Query $query, string $key, string $exp, $value, $field, int $bindType): string
716
    {
717
        if (is_string($value)) {
718
            $value = explode(',', $value);
719
        }
720
721
        return $key . ' ' . substr($exp, 0, -4)
722
        . $this->parseDateTime($query, $value[0], $field, $bindType)
723
        . ' AND '
724
        . $this->parseDateTime($query, $value[1], $field, $bindType);
725
726
    }
727
728
    /**
729
     * IN查询
730
     * @access protected
731
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
732
     * @param  string    $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
733
     * @param  string    $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
734
     * @param  mixed     $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
735
     * @param  string    $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
736
     * @param  integer   $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
737
     * @return string
738
     */
739
    protected function parseIn(Query $query, string $key, string $exp, $value, $field, int $bindType): string
740
    {
741
        // IN 查询
742
        if ($value instanceof \Closure) {
743
            $value = $this->parseClosure($query, $value, false);
744
        } elseif ($value instanceof Raw) {
745
            $value = $value->getValue();
746
        } else {
747
            $value = array_unique(is_array($value) ? $value : explode(',', $value));
748
            $array = [];
749
750
            foreach ($value as $v) {
751
                $name    = $query->bindValue($v, $bindType);
752
                $array[] = ':' . $name;
753
            }
754
755
            $zone  = implode(',', $array);
756
            $value = empty($zone) ? "''" : $zone;
757
        }
758
759
        return $key . ' ' . $exp . ' (' . $value . ')';
760
    }
761
762
    /**
763
     * 闭包子查询
764
     * @access protected
765
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
766
     * @param  \Closure  $call
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
767
     * @param  bool      $show
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
768
     * @return string
769
     */
770
    protected function parseClosure(Query $query, \Closure $call, bool $show = true): string
771
    {
772
        $newQuery = $query->newQuery()->setConnection($this->connection);
773
        $call($newQuery);
774
775
        return $newQuery->buildSql($show);
776
    }
777
778
    /**
779
     * 日期时间条件解析
780
     * @access protected
781
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
782
     * @param  mixed     $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
783
     * @param  string    $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
784
     * @param  integer   $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
785
     * @return string
786
     */
787
    protected function parseDateTime(Query $query, $value, string $key, int $bindType): string
788
    {
789
        $options = $query->getOptions();
790
791
        // 获取时间字段类型
792
        if (strpos($key, '.')) {
793
            list($table, $key) = explode('.', $key);
794
795
            if (isset($options['alias']) && $pos = array_search($table, $options['alias'])) {
796
                $table = $pos;
797
            }
798
        } else {
799
            $table = $options['table'];
800
        }
801
802
        $type = $this->connection->getTableInfo($table, 'type');
803
804
        if (isset($type[$key])) {
805
            $info = $type[$key];
806
            if (is_string($value)) {
807
                $value = strtotime($value) ?: $value;
808
            }
809
810
            if (is_int($value)) {
811
                if (preg_match('/(datetime|timestamp)/is', $info)) {
812
                    // 日期及时间戳类型
813
                    $value = date('Y-m-d H:i:s', $value);
814
                } elseif (preg_match('/(date)/is', $info)) {
815
                    // 日期及时间戳类型
816
                    $value = date('Y-m-d', $value);
817
                }
818
            }
819
        }
820
821
        $name = $query->bindValue($value, $bindType);
822
823
        return ':' . $name;
824
    }
825
826
    /**
827
     * limit分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
828
     * @access protected
829
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
830
     * @param  mixed     $limit
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
831
     * @return string
832
     */
833
    protected function parseLimit(Query $query, string $limit): string
834
    {
835
        return (!empty($limit) && false === strpos($limit, '(')) ? ' LIMIT ' . $limit . ' ' : '';
836
    }
837
838
    /**
839
     * join分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
840
     * @access protected
841
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
842
     * @param  array     $join
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
843
     * @return string
844
     */
845
    protected function parseJoin(Query $query, array $join): string
846
    {
847
        $joinStr = '';
848
849
        foreach ($join as $item) {
850
            list($table, $type, $on) = $item;
851
852
            if (strpos($on, '=')) {
853
                list($val1, $val2) = explode('=', $on, 2);
854
855
                $condition = $this->parseKey($query, $val1) . '=' . $this->parseKey($query, $val2);
856
            } else {
857
                $condition = $on;
858
            }
859
860
            $table = $this->parseTable($query, $table);
861
862
            $joinStr .= ' ' . $type . ' JOIN ' . $table . ' ON ' . $condition;
863
        }
864
865
        return $joinStr;
866
    }
867
868
    /**
869
     * order分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
870
     * @access protected
871
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
872
     * @param  array     $order
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
873
     * @return string
874
     */
875
    protected function parseOrder(Query $query, array $order): string
876
    {
877
        $array = [];
878
        foreach ($order as $key => $val) {
879
            if ($val instanceof Raw) {
880
                $array[] = $val->getValue();
881
            } elseif (is_array($val) && preg_match('/^[\w\.]+$/', $key)) {
882
                $array[] = $this->parseOrderField($query, $key, $val);
883
            } elseif ('[rand]' == $val) {
884
                $array[] = $this->parseRand($query);
885
            } elseif (is_string($val)) {
886
                if (is_numeric($key)) {
887
                    list($key, $sort) = explode(' ', strpos($val, ' ') ? $val : $val . ' ');
888
                } else {
889
                    $sort = $val;
890
                }
891
892
                if (preg_match('/^[\w\.]+$/', $key)) {
893
                    $sort    = strtoupper($sort);
894
                    $sort    = in_array($sort, ['ASC', 'DESC'], true) ? ' ' . $sort : '';
895
                    $array[] = $this->parseKey($query, $key, true) . $sort;
896
                } else {
897
                    throw new Exception('order express error:' . $key);
898
                }
899
            }
900
        }
901
902
        return empty($array) ? '' : ' ORDER BY ' . implode(',', $array);
903
    }
904
905
    /**
906
     * 随机排序
907
     * @access protected
908
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
909
     * @return string
910
     */
911
    protected function parseRand(Query $query): string
912
    {
913
        return '';
914
    }
915
916
    /**
917
     * orderField分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
918
     * @access protected
919
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
920
     * @param  string    $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
921
     * @param  array     $val
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
922
     * @return string
923
     */
924
    protected function parseOrderField(Query $query, string $key, array $val): string
925
    {
926
        if (isset($val['sort'])) {
927
            $sort = $val['sort'];
928
            unset($val['sort']);
929
        } else {
930
            $sort = '';
931
        }
932
933
        $sort = strtoupper($sort);
934
        $sort = in_array($sort, ['ASC', 'DESC'], true) ? ' ' . $sort : '';
935
        $bind = $query->getFieldsBindType();
936
937
        foreach ($val as $item) {
938
            $val[] = $this->parseDataBind($query, $key, $item, $bind);
939
        }
940
941
        return 'field(' . $this->parseKey($query, $key, true) . ',' . implode(',', $val) . ')' . $sort;
942
    }
943
944
    /**
945
     * group分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
946
     * @access protected
947
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
948
     * @param  mixed     $group
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
949
     * @return string
950
     */
951
    protected function parseGroup(Query $query, $group): string
952
    {
953
        if (empty($group)) {
954
            return '';
955
        }
956
957
        if (is_string($group)) {
958
            $group = explode(',', $group);
959
        }
960
961
        $val = [];
962
        foreach ($group as $key) {
963
            $val[] = $this->parseKey($query, $key);
964
        }
965
966
        return ' GROUP BY ' . implode(',', $val);
967
    }
968
969
    /**
970
     * having分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
971
     * @access protected
972
     * @param  Query  $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 8 found
Loading history...
973
     * @param  string $having
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
974
     * @return string
975
     */
976
    protected function parseHaving(Query $query, string $having): string
977
    {
978
        return !empty($having) ? ' HAVING ' . $having : '';
979
    }
980
981
    /**
982
     * comment分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
983
     * @access protected
984
     * @param  Query  $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 8 found
Loading history...
985
     * @param  string $comment
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
986
     * @return string
987
     */
988
    protected function parseComment(Query $query, string $comment): string
989
    {
990
        if (false !== strpos($comment, '*/')) {
991
            $comment = strstr($comment, '*/', true);
992
        }
993
994
        return !empty($comment) ? ' /* ' . $comment . ' */' : '';
995
    }
996
997
    /**
998
     * distinct分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
999
     * @access protected
1000
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
1001
     * @param  mixed     $distinct
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1002
     * @return string
1003
     */
1004
    protected function parseDistinct(Query $query, bool $distinct): string
1005
    {
1006
        return !empty($distinct) ? ' DISTINCT ' : '';
1007
    }
1008
1009
    /**
1010
     * union分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
1011
     * @access protected
1012
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
1013
     * @param  array     $union
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1014
     * @return string
1015
     */
1016
    protected function parseUnion(Query $query, array $union): string
1017
    {
1018
        if (empty($union)) {
1019
            return '';
1020
        }
1021
1022
        $type = $union['type'];
1023
        unset($union['type']);
1024
1025
        foreach ($union as $u) {
1026
            if ($u instanceof \Closure) {
1027
                $sql[] = $type . ' ' . $this->parseClosure($query, $u);
1028
            } elseif (is_string($u)) {
1029
                $sql[] = $type . ' ( ' . $u . ' )';
1030
            }
1031
        }
1032
1033
        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 1025. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
1034
    }
1035
1036
    /**
1037
     * index分析,可在操作链中指定需要强制使用的索引
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
1038
     * @access protected
1039
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
1040
     * @param  mixed     $index
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1041
     * @return string
1042
     */
1043
    protected function parseForce(Query $query, $index): string
1044
    {
1045
        if (empty($index)) {
1046
            return '';
1047
        }
1048
1049
        if (is_array($index)) {
1050
            $index = join(',', $index);
1051
        }
1052
1053
        return sprintf(" FORCE INDEX ( %s ) ", $index);
1054
    }
1055
1056
    /**
1057
     * 设置锁机制
1058
     * @access protected
1059
     * @param  Query         $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
1060
     * @param  bool|string   $lock
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1061
     * @return string
1062
     */
1063
    protected function parseLock(Query $query, $lock = false): string
1064
    {
1065
        if (is_bool($lock)) {
1066
            return $lock ? ' FOR UPDATE ' : '';
1067
        }
1068
1069
        if (is_string($lock) && !empty($lock)) {
1070
            return ' ' . trim($lock) . ' ';
1071
        } else {
1072
            return '';
1073
        }
1074
    }
1075
1076
    /**
1077
     * 生成查询SQL
1078
     * @access public
1079
     * @param  Query  $query  查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1080
     * @param  bool   $one    是否仅获取一个记录
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 4 found
Loading history...
1081
     * @return string
1082
     */
1083
    public function select(Query $query, bool $one = false): string
1084
    {
1085
        $options = $query->getOptions();
1086
1087
        return str_replace(
1088
            ['%TABLE%', '%DISTINCT%', '%EXTRA%', '%FIELD%', '%JOIN%', '%WHERE%', '%GROUP%', '%HAVING%', '%ORDER%', '%LIMIT%', '%UNION%', '%LOCK%', '%COMMENT%', '%FORCE%'],
1089
            [
1090
                $this->parseTable($query, $options['table']),
1091
                $this->parseDistinct($query, $options['distinct']),
1092
                $this->parseExtra($query, $options['extra']),
1093
                $this->parseField($query, $options['field']),
1094
                $this->parseJoin($query, $options['join']),
1095
                $this->parseWhere($query, $options['where']),
1096
                $this->parseGroup($query, $options['group']),
1097
                $this->parseHaving($query, $options['having']),
1098
                $this->parseOrder($query, $options['order']),
1099
                $this->parseLimit($query, $one ? '1' : $options['limit']),
1100
                $this->parseUnion($query, $options['union']),
1101
                $this->parseLock($query, $options['lock']),
1102
                $this->parseComment($query, $options['comment']),
1103
                $this->parseForce($query, $options['force']),
1104
            ],
1105
            $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...
1106
    }
1107
1108
    /**
1109
     * 生成Insert SQL
1110
     * @access public
1111
     * @param  Query     $query   查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 3 found
Loading history...
1112
     * @return string
1113
     */
1114
    public function insert(Query $query): string
1115
    {
1116
        $options = $query->getOptions();
1117
1118
        // 分析并处理数据
1119
        $data = $this->parseData($query, $options['data']);
1120
        if (empty($data)) {
1121
            return '';
1122
        }
1123
1124
        $fields = array_keys($data);
1125
        $values = array_values($data);
1126
1127
        return str_replace(
1128
            ['%INSERT%', '%TABLE%', '%EXTRA%', '%FIELD%', '%DATA%', '%COMMENT%'],
1129
            [
1130
                !empty($options['replace']) ? 'REPLACE' : 'INSERT',
1131
                $this->parseTable($query, $options['table']),
1132
                $this->parseExtra($query, $options['extra']),
1133
                implode(' , ', $fields),
1134
                implode(' , ', $values),
1135
                $this->parseComment($query, $options['comment']),
1136
            ],
1137
            $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...
1138
    }
1139
1140
    /**
1141
     * 生成insertall SQL
1142
     * @access public
1143
     * @param  Query     $query   查询对象
1144
     * @param  array     $dataSet 数据集
1145
     * @return string
1146
     */
1147
    public function insertAll(Query $query, array $dataSet): string
1148
    {
1149
        $options = $query->getOptions();
1150
1151
        // 获取合法的字段
1152
        if ('*' == $options['field']) {
1153
            $allowFields = $this->connection->getTableFields($options['table']);
1154
        } else {
1155
            $allowFields = $options['field'];
1156
        }
1157
1158
        // 获取绑定信息
1159
        $bind   = $query->getFieldsBindType();
1160
        $fields = [];
1161
        $values = [];
1162
1163
        foreach ($dataSet as $k => $data) {
1164
            $data = $this->parseData($query, $data, $allowFields, $bind);
1165
1166
            $values[] = 'SELECT ' . implode(',', array_values($data));
1167
1168
            if (!isset($insertFields)) {
1169
                $insertFields = array_keys($data);
1170
            }
1171
        }
1172
1173
        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 1163. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
1174
            $fields[] = $this->parseKey($query, $field);
1175
        }
1176
1177
        return str_replace(
1178
            ['%INSERT%', '%TABLE%', '%EXTRA%', '%FIELD%', '%DATA%', '%COMMENT%'],
1179
            [
1180
                !empty($options['replace']) ? 'REPLACE' : 'INSERT',
1181
                $this->parseTable($query, $options['table']),
1182
                $this->parseExtra($query, $options['extra']),
1183
                implode(' , ', $fields),
1184
                implode(' UNION ALL ', $values),
1185
                $this->parseComment($query, $options['comment']),
1186
            ],
1187
            $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...
1188
    }
1189
1190
    /**
1191
     * 生成slect insert SQL
1192
     * @access public
1193
     * @param  Query     $query  查询对象
1194
     * @param  array     $fields 数据
1195
     * @param  string    $table  数据表
1196
     * @return string
1197
     */
1198
    public function selectInsert(Query $query, array $fields, string $table): string
1199
    {
1200
        foreach ($fields as &$field) {
1201
            $field = $this->parseKey($query, $field, true);
1202
        }
1203
1204
        return 'INSERT INTO ' . $this->parseTable($query, $table) . ' (' . implode(',', $fields) . ') ' . $this->select($query);
1205
    }
1206
1207
    /**
1208
     * 生成update SQL
1209
     * @access public
1210
     * @param  Query     $query  查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1211
     * @return string
1212
     */
1213
    public function update(Query $query): string
1214
    {
1215
        $options = $query->getOptions();
1216
1217
        $data = $this->parseData($query, $options['data']);
1218
1219
        if (empty($data)) {
1220
            return '';
1221
        }
1222
1223
        $set = [];
1224
        foreach ($data as $key => $val) {
1225
            $set[] = $key . ' = ' . $val;
1226
        }
1227
1228
        return str_replace(
1229
            ['%TABLE%', '%EXTRA%', '%SET%', '%JOIN%', '%WHERE%', '%ORDER%', '%LIMIT%', '%LOCK%', '%COMMENT%'],
1230
            [
1231
                $this->parseTable($query, $options['table']),
1232
                $this->parseExtra($query, $options['extra']),
1233
                implode(' , ', $set),
1234
                $this->parseJoin($query, $options['join']),
1235
                $this->parseWhere($query, $options['where']),
1236
                $this->parseOrder($query, $options['order']),
1237
                $this->parseLimit($query, $options['limit']),
1238
                $this->parseLock($query, $options['lock']),
1239
                $this->parseComment($query, $options['comment']),
1240
            ],
1241
            $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...
1242
    }
1243
1244
    /**
1245
     * 生成delete SQL
1246
     * @access public
1247
     * @param  Query  $query  查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1248
     * @return string
1249
     */
1250
    public function delete(Query $query): string
1251
    {
1252
        $options = $query->getOptions();
1253
1254
        return str_replace(
1255
            ['%TABLE%', '%EXTRA%', '%USING%', '%JOIN%', '%WHERE%', '%ORDER%', '%LIMIT%', '%LOCK%', '%COMMENT%'],
1256
            [
1257
                $this->parseTable($query, $options['table']),
1258
                $this->parseExtra($query, $options['extra']),
1259
                !empty($options['using']) ? ' USING ' . $this->parseTable($query, $options['using']) . ' ' : '',
1260
                $this->parseJoin($query, $options['join']),
1261
                $this->parseWhere($query, $options['where']),
1262
                $this->parseOrder($query, $options['order']),
1263
                $this->parseLimit($query, $options['limit']),
1264
                $this->parseLock($query, $options['lock']),
1265
                $this->parseComment($query, $options['comment']),
1266
            ],
1267
            $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...
1268
    }
1269
}
1270