Passed
Push — 5.1 ( c94f65...4b586a )
by liu
13:22 queued 05:25
created

Builder::parseIn()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 25
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 16
nc 5
nop 6
dl 0
loc 25
rs 8.8333
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~2018 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
12
namespace think\db;
13
14
use PDO;
15
use think\Exception;
16
17
abstract class Builder
1 ignored issue
show
Coding Style introduced by
Missing class doc comment
Loading history...
18
{
19
    // connection对象实例
20
    protected $connection;
21
22
    // 查询表达式映射
23
    protected $exp = ['EQ' => '=', 'NEQ' => '<>', 'GT' => '>', 'EGT' => '>=', 'LT' => '<', 'ELT' => '<=', 'NOTLIKE' => 'NOT LIKE', 'NOTIN' => 'NOT IN', 'NOTBETWEEN' => 'NOT BETWEEN', 'NOTEXISTS' => 'NOT EXISTS', 'NOTNULL' => 'NOT NULL', 'NOTBETWEEN TIME' => 'NOT BETWEEN TIME'];
24
25
    // 查询表达式解析
26
    protected $parser = [
27
        'parseCompare'     => ['=', '<>', '>', '>=', '<', '<='],
28
        'parseLike'        => ['LIKE', 'NOT LIKE'],
29
        'parseBetween'     => ['NOT BETWEEN', 'BETWEEN'],
30
        'parseIn'          => ['NOT IN', 'IN'],
31
        'parseExp'         => ['EXP'],
32
        'parseNull'        => ['NOT NULL', 'NULL'],
33
        'parseBetweenTime' => ['BETWEEN TIME', 'NOT BETWEEN TIME'],
34
        'parseTime'        => ['< TIME', '> TIME', '<= TIME', '>= TIME'],
35
        'parseExists'      => ['NOT EXISTS', 'EXISTS'],
36
        'parseColumn'      => ['COLUMN'],
37
    ];
38
39
    // SQL表达式
40
    protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%UNION%%ORDER%%LIMIT% %LOCK%%COMMENT%';
41
42
    protected $insertSql = '%INSERT% INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%';
43
44
    protected $insertAllSql = '%INSERT% INTO %TABLE% (%FIELD%) %DATA% %COMMENT%';
45
46
    protected $updateSql = 'UPDATE %TABLE% SET %SET%%JOIN%%WHERE%%ORDER%%LIMIT% %LOCK%%COMMENT%';
47
48
    protected $deleteSql = 'DELETE FROM %TABLE%%USING%%JOIN%%WHERE%%ORDER%%LIMIT% %LOCK%%COMMENT%';
49
50
    /**
51
     * 架构函数
52
     * @access public
53
     * @param  Connection    $connection 数据库连接对象实例
54
     */
55
    public function __construct(Connection $connection)
56
    {
57
        $this->connection = $connection;
58
    }
59
60
    /**
61
     * 获取当前的连接对象实例
62
     * @access public
63
     * @return Connection
64
     */
65
    public function getConnection()
66
    {
67
        return $this->connection;
68
    }
69
70
    /**
71
     * 注册查询表达式解析
72
     * @access public
73
     * @param  string    $name   解析方法
74
     * @param  array     $parser 匹配表达式数据
75
     * @return $this
76
     */
77
    public function bindParser($name, $parser)
78
    {
79
        $this->parser[$name] = $parser;
80
        return $this;
81
    }
82
83
    /**
84
     * 数据分析
85
     * @access protected
86
     * @param  Query     $query     查询对象
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 5 found
Loading history...
87
     * @param  array     $data      数据
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 6 found
Loading history...
88
     * @param  array     $fields    字段信息
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
89
     * @param  array     $bind      参数绑定
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 6 found
Loading history...
90
     * @return array
91
     */
92
    protected function parseData(Query $query, $data = [], $fields = [], $bind = [])
93
    {
94
        if (empty($data)) {
95
            return [];
96
        }
97
98
        $options = $query->getOptions();
99
100
        // 获取绑定信息
101
        if (empty($bind)) {
102
            $bind = $this->connection->getFieldsBind($options['table']);
103
        }
104
105
        if (empty($fields)) {
106
            if ('*' == $options['field']) {
107
                $fields = array_keys($bind);
108
            } else {
109
                $fields = $options['field'];
110
            }
111
        }
112
113
        $result = [];
114
115
        foreach ($data as $key => $val) {
116
            if ('*' != $options['field'] && !in_array($key, $fields, true)) {
117
                continue;
118
            }
119
120
            $item = $this->parseKey($query, $key, true);
121
122
            if ($val instanceof Expression) {
123
                $result[$item] = $val->getValue();
124
                continue;
125
            } elseif (!is_scalar($val) && (in_array($key, (array) $query->getOptions('json')) || 'json' == $this->connection->getFieldsType($options['table'], $key))) {
126
                $val = json_encode($val, JSON_UNESCAPED_UNICODE);
127
            } elseif (is_object($val) && method_exists($val, '__toString')) {
128
                // 对象数据写入
129
                $val = $val->__toString();
130
            }
131
132
            if (false !== strpos($key, '->')) {
133
                list($key, $name) = explode('->', $key);
134
                $item             = $this->parseKey($query, $key);
135
                $result[$item]    = 'json_set(' . $item . ', \'$.' . $name . '\', ' . $this->parseDataBind($query, $key, $val, $bind) . ')';
136
            } elseif ('*' == $options['field'] && false === strpos($key, '.') && !in_array($key, $fields, true)) {
137
                if ($options['strict']) {
138
                    throw new Exception('fields not exists:[' . $key . ']');
139
                }
140
            } elseif (is_null($val)) {
141
                $result[$item] = 'NULL';
142
            } elseif (is_array($val) && !empty($val)) {
143
                switch (strtoupper($val[0])) {
144
                    case 'INC':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 16 spaces, found 20
Loading history...
145
                        $result[$item] = $item . ' + ' . floatval($val[1]);
146
                        break;
147
                    case 'DEC':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 16 spaces, found 20
Loading history...
148
                        $result[$item] = $item . ' - ' . floatval($val[1]);
149
                        break;
150
                    case 'EXP':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 16 spaces, found 20
Loading history...
151
                        throw new Exception('not support data:[' . $val[0] . ']');
152
                }
153
            } elseif (is_scalar($val)) {
154
                // 过滤非标量数据
155
                $result[$item] = $this->parseDataBind($query, $key, $val, $bind);
156
            }
157
        }
158
159
        return $result;
160
    }
161
162
    /**
163
     * 数据绑定处理
164
     * @access protected
165
     * @param  Query     $query     查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 5 found
Loading history...
166
     * @param  string    $key       字段名
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 7 found
Loading history...
167
     * @param  mixed     $data      数据
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 6 found
Loading history...
168
     * @param  array     $bind      绑定数据
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 6 found
Loading history...
169
     * @return string
170
     */
171
    protected function parseDataBind(Query $query, $key, $data, $bind = [])
172
    {
173
        if ($data instanceof Expression) {
174
            return $data->getValue();
175
        }
176
177
        $name = $query->bind($data, isset($bind[$key]) ? $bind[$key] : PDO::PARAM_STR);
178
179
        return ':' . $name;
0 ignored issues
show
Bug introduced by
Are you sure $name of type string|think\db\Query can be used in concatenation? ( Ignorable by Annotation )

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

179
        return ':' . /** @scrutinizer ignore-type */ $name;
Loading history...
180
    }
181
182
    /**
183
     * 字段名分析
184
     * @access public
185
     * @param  Query  $query    查询对象
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 4 found
Loading history...
186
     * @param  mixed  $key      字段名
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 6 found
Loading history...
187
     * @param  bool   $strict   严格检测
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 3 found
Loading history...
188
     * @return string
189
     */
190
    public function parseKey(Query $query, $key, $strict = false)
191
    {
192
        return $key instanceof Expression ? $key->getValue() : $key;
193
    }
194
195
    /**
196
     * field分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
197
     * @access protected
198
     * @param  Query     $query     查询对象
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 5 found
Loading history...
199
     * @param  mixed     $fields    字段名
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
200
     * @return string
201
     */
202
    protected function parseField(Query $query, $fields)
203
    {
204
        if ('*' == $fields || empty($fields)) {
205
            $fieldsStr = '*';
206
        } elseif (is_array($fields)) {
207
            // 支持 'field1'=>'field2' 这样的字段别名定义
208
            $array = [];
209
210
            foreach ($fields as $key => $field) {
211
                if (!is_numeric($key)) {
212
                    $array[] = $this->parseKey($query, $key) . ' AS ' . $this->parseKey($query, $field, true);
213
                } else {
214
                    $array[] = $this->parseKey($query, $field);
215
                }
216
            }
217
218
            $fieldsStr = implode(',', $array);
219
        }
220
221
        return $fieldsStr;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $fieldsStr does not seem to be defined for all execution paths leading up to this point.
Loading history...
222
    }
223
224
    /**
225
     * table分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
226
     * @access protected
227
     * @param  Query     $query         查询对象
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 9 found
Loading history...
228
     * @param  mixed     $tables        表名
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
229
     * @return string
230
     */
231
    protected function parseTable(Query $query, $tables)
232
    {
233
        $item    = [];
234
        $options = $query->getOptions();
235
236
        foreach ((array) $tables as $key => $table) {
237
            if (!is_numeric($key)) {
238
                $key    = $this->connection->parseSqlTable($key);
239
                $item[] = $this->parseKey($query, $key) . ' ' . $this->parseKey($query, $table);
240
            } else {
241
                $table = $this->connection->parseSqlTable($table);
242
243
                if (isset($options['alias'][$table])) {
244
                    $item[] = $this->parseKey($query, $table) . ' ' . $this->parseKey($query, $options['alias'][$table]);
245
                } else {
246
                    $item[] = $this->parseKey($query, $table);
247
                }
248
            }
249
        }
250
251
        return implode(',', $item);
252
    }
253
254
    /**
255
     * where分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
256
     * @access protected
257
     * @param  Query     $query   查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 3 found
Loading history...
258
     * @param  mixed     $where   查询条件
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 3 found
Loading history...
259
     * @return string
260
     */
261
    protected function parseWhere(Query $query, $where)
262
    {
263
        $options  = $query->getOptions();
264
        $whereStr = $this->buildWhere($query, $where);
265
266
        if (!empty($options['soft_delete'])) {
267
            // 附加软删除条件
268
            list($field, $condition) = $options['soft_delete'];
269
270
            $binds    = $this->connection->getFieldsBind($options['table']);
271
            $whereStr = $whereStr ? '( ' . $whereStr . ' ) AND ' : '';
272
            $whereStr = $whereStr . $this->parseWhereItem($query, $field, $condition, '', $binds);
273
        }
274
275
        return empty($whereStr) ? '' : ' WHERE ' . $whereStr;
276
    }
277
278
    /**
279
     * 生成查询条件SQL
280
     * @access public
281
     * @param  Query     $query     查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 5 found
Loading history...
282
     * @param  mixed     $where     查询条件
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 5 found
Loading history...
283
     * @return string
284
     */
285
    public function buildWhere(Query $query, $where)
286
    {
287
        if (empty($where)) {
288
            $where = [];
289
        }
290
291
        $whereStr = '';
292
        $binds    = $this->connection->getFieldsBind($query->getOptions('table'));
293
294
        foreach ($where as $logic => $val) {
295
            $str = [];
296
297
            foreach ($val as $value) {
298
                if ($value instanceof Expression) {
299
                    $str[] = ' ' . $logic . ' ( ' . $value->getValue() . ' )';
300
                    continue;
301
                }
302
303
                if (is_array($value)) {
304
                    if (key($value) !== 0) {
305
                        throw new Exception('where express error:' . var_export($value, true));
306
                    }
307
                    $field = array_shift($value);
308
                } elseif (!($value instanceof \Closure)) {
309
                    throw new Exception('where express error:' . var_export($value, true));
310
                }
311
312
                if ($value instanceof \Closure) {
313
                    // 使用闭包查询
314
                    $newQuery = $query->newQuery()->setConnection($this->connection);
315
                    $value($newQuery);
316
                    $whereClause = $this->buildWhere($query, $newQuery->getOptions('where'));
317
318
                    if (!empty($whereClause)) {
319
                        $str[] = ' ' . $logic . ' ( ' . $whereClause . ' )';
320
                    }
321
                } 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...
322
                    array_unshift($value, $field);
323
                    $str2 = [];
324
                    foreach ($value as $item) {
325
                        $str2[] = $this->parseWhereItem($query, array_shift($item), $item, $logic, $binds);
326
                    }
327
328
                    $str[] = ' ' . $logic . ' ( ' . implode(' AND ', $str2) . ' )';
329
                } elseif (strpos($field, '|')) {
330
                    // 不同字段使用相同查询条件(OR)
331
                    $array = explode('|', $field);
332
                    $item  = [];
333
334
                    foreach ($array as $k) {
335
                        $item[] = $this->parseWhereItem($query, $k, $value, '', $binds);
336
                    }
337
338
                    $str[] = ' ' . $logic . ' ( ' . implode(' OR ', $item) . ' )';
339
                } elseif (strpos($field, '&')) {
340
                    // 不同字段使用相同查询条件(AND)
341
                    $array = explode('&', $field);
342
                    $item  = [];
343
344
                    foreach ($array as $k) {
345
                        $item[] = $this->parseWhereItem($query, $k, $value, '', $binds);
346
                    }
347
348
                    $str[] = ' ' . $logic . ' ( ' . implode(' AND ', $item) . ' )';
349
                } else {
350
                    // 对字段使用表达式查询
351
                    $field = is_string($field) ? $field : '';
352
                    $str[] = ' ' . $logic . ' ' . $this->parseWhereItem($query, $field, $value, $logic, $binds);
353
                }
354
            }
355
356
            $whereStr .= empty($whereStr) ? substr(implode(' ', $str), strlen($logic) + 1) : implode(' ', $str);
357
        }
358
359
        return $whereStr;
360
    }
361
362
    // where子单元分析
363
    protected function parseWhereItem(Query $query, $field, $val, $rule = '', $binds = [])
0 ignored issues
show
Coding Style introduced by
You must use "/**" style comments for a function comment
Loading history...
364
    {
365
        // 字段分析
366
        $key = $field ? $this->parseKey($query, $field, true) : '';
367
368
        // 查询规则和条件
369
        if (!is_array($val)) {
370
            $val = is_null($val) ? ['NULL', ''] : ['=', $val];
371
        }
372
373
        list($exp, $value) = $val;
374
375
        // 对一个字段使用多个查询条件
376
        if (is_array($exp)) {
377
            $item = array_pop($val);
378
379
            // 传入 or 或者 and
380
            if (is_string($item) && in_array($item, ['AND', 'and', 'OR', 'or'])) {
381
                $rule = $item;
382
            } else {
383
                array_push($val, $item);
384
            }
385
386
            foreach ($val as $k => $item) {
387
                $str[] = $this->parseWhereItem($query, $field, $item, $rule, $binds);
388
            }
389
390
            return '( ' . implode(' ' . $rule . ' ', $str) . ' )';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $str seems to be defined by a foreach iteration on line 386. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
391
        }
392
393
        // 检测操作符
394
        $exp = strtoupper($exp);
395
        if (isset($this->exp[$exp])) {
396
            $exp = $this->exp[$exp];
397
        }
398
399
        if ($value instanceof Expression) {
400
401
        } elseif (is_object($value) && method_exists($value, '__toString')) {
402
            // 对象数据写入
403
            $value = $value->__toString();
404
        }
405
406
        if (strpos($field, '->')) {
407
            $jsonType = $query->getJsonFieldType($field);
408
            $bindType = $this->connection->getFieldBindType($jsonType);
409
        } else {
410
            $bindType = isset($binds[$field]) ? $binds[$field] : PDO::PARAM_STR;
411
        }
412
413
        if (is_scalar($value) && !in_array($exp, ['EXP', 'NOT NULL', 'NULL', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN']) && strpos($exp, 'TIME') === false) {
414
            if (0 === strpos($value, ':') && $query->isBind(substr($value, 1))) {
415
            } else {
416
                $name  = $query->bind($value, $bindType);
417
                $value = ':' . $name;
0 ignored issues
show
Bug introduced by
Are you sure $name of type string|think\db\Query can be used in concatenation? ( Ignorable by Annotation )

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

417
                $value = ':' . /** @scrutinizer ignore-type */ $name;
Loading history...
418
            }
419
        }
420
421
        // 解析查询表达式
422
        foreach ($this->parser as $fun => $parse) {
423
            if (in_array($exp, $parse)) {
424
                $whereStr = $this->$fun($query, $key, $exp, $value, $field, $bindType, isset($val[2]) ? $val[2] : 'AND');
425
                break;
426
            }
427
        }
428
429
        if (!isset($whereStr)) {
430
            throw new Exception('where express error:' . $exp);
431
        }
432
433
        return $whereStr;
434
    }
435
436
    /**
437
     * 模糊查询
438
     * @access protected
439
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
440
     * @param  string    $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
441
     * @param  string    $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
442
     * @param  mixed     $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
443
     * @param  string    $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
444
     * @param  integer   $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
445
     * @param  string    $logic
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
446
     * @return string
447
     */
448
    protected function parseLike(Query $query, $key, $exp, $value, $field, $bindType, $logic)
449
    {
450
        // 模糊匹配
451
        if (is_array($value)) {
452
            foreach ($value as $item) {
453
                $name    = $query->bind($item, $bindType);
454
                $array[] = $key . ' ' . $exp . ' :' . $name;
0 ignored issues
show
Bug introduced by
Are you sure $name of type string|think\db\Query can be used in concatenation? ( Ignorable by Annotation )

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

454
                $array[] = $key . ' ' . $exp . ' :' . /** @scrutinizer ignore-type */ $name;
Loading history...
455
            }
456
457
            $whereStr = '(' . implode(' ' . strtoupper($logic) . ' ', $array) . ')';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $array seems to be defined by a foreach iteration on line 452. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
458
        } else {
459
            $whereStr = $key . ' ' . $exp . ' ' . $value;
460
        }
461
462
        return $whereStr;
463
    }
464
465
    /**
466
     * 表达式查询
467
     * @access protected
468
     * @param  Query        $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
469
     * @param  string       $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
470
     * @param  string       $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
471
     * @param  array        $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
472
     * @param  string       $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
473
     * @param  integer      $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
474
     * @return string
475
     */
476
    protected function parseColumn(Query $query, $key, $exp, array $value, $field, $bindType)
477
    {
478
        // 字段比较查询
479
        list($op, $field2) = $value;
480
481
        if (!in_array($op, ['=', '<>', '>', '>=', '<', '<='])) {
482
            throw new Exception('where express error:' . var_export($value, true));
483
        }
484
485
        return '( ' . $key . ' ' . $op . ' ' . $this->parseKey($query, $field2, true) . ' )';
486
    }
487
488
    /**
489
     * 表达式查询
490
     * @access protected
491
     * @param  Query        $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
492
     * @param  string       $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
493
     * @param  string       $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
494
     * @param  Expression   $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
495
     * @param  string       $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
496
     * @param  integer      $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
497
     * @return string
498
     */
499
    protected function parseExp(Query $query, $key, $exp, Expression $value, $field, $bindType)
500
    {
501
        // 表达式查询
502
        return '( ' . $key . ' ' . $value->getValue() . ' )';
503
    }
504
505
    /**
506
     * Null查询
507
     * @access protected
508
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
509
     * @param  string    $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
510
     * @param  string    $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
511
     * @param  mixed     $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
512
     * @param  string    $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
513
     * @param  integer   $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
514
     * @return string
515
     */
516
    protected function parseNull(Query $query, $key, $exp, $value, $field, $bindType)
517
    {
518
        // NULL 查询
519
        return $key . ' IS ' . $exp;
520
    }
521
522
    /**
523
     * 范围查询
524
     * @access protected
525
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
526
     * @param  string    $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
527
     * @param  string    $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
528
     * @param  mixed     $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
529
     * @param  string    $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
530
     * @param  integer   $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
531
     * @return string
532
     */
533
    protected function parseBetween(Query $query, $key, $exp, $value, $field, $bindType)
534
    {
535
        // BETWEEN 查询
536
        $data = is_array($value) ? $value : explode(',', $value);
537
538
        $min = $query->bind($data[0], $bindType);
539
        $max = $query->bind($data[1], $bindType);
540
541
        return $key . ' ' . $exp . ' :' . $min . ' AND :' . $max . ' ';
0 ignored issues
show
Bug introduced by
Are you sure $max of type string|think\db\Query can be used in concatenation? ( Ignorable by Annotation )

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

541
        return $key . ' ' . $exp . ' :' . $min . ' AND :' . /** @scrutinizer ignore-type */ $max . ' ';
Loading history...
Bug introduced by
Are you sure $min of type string|think\db\Query can be used in concatenation? ( Ignorable by Annotation )

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

541
        return $key . ' ' . $exp . ' :' . /** @scrutinizer ignore-type */ $min . ' AND :' . $max . ' ';
Loading history...
542
    }
543
544
    /**
545
     * Exists查询
546
     * @access protected
547
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
548
     * @param  string    $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
549
     * @param  string    $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
550
     * @param  mixed     $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
551
     * @param  string    $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
552
     * @param  integer   $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
553
     * @return string
554
     */
555
    protected function parseExists(Query $query, $key, $exp, $value, $field, $bindType)
556
    {
557
        // EXISTS 查询
558
        if ($value instanceof \Closure) {
559
            $value = $this->parseClosure($query, $value, false);
560
        } elseif ($value instanceof Expression) {
561
            $value = $value->getValue();
562
        } else {
563
            throw new Exception('where express error:' . $value);
564
        }
565
566
        return $exp . ' (' . $value . ')';
567
    }
568
569
    /**
570
     * 时间比较查询
571
     * @access protected
572
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
573
     * @param  string    $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
574
     * @param  string    $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
575
     * @param  mixed     $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
576
     * @param  string    $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
577
     * @param  integer   $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
578
     * @return string
579
     */
580
    protected function parseTime(Query $query, $key, $exp, $value, $field, $bindType)
581
    {
582
        return $key . ' ' . substr($exp, 0, 2) . ' ' . $this->parseDateTime($query, $value, $field, $bindType);
583
    }
584
585
    /**
586
     * 大小比较查询
587
     * @access protected
588
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
589
     * @param  string    $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
590
     * @param  string    $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
591
     * @param  mixed     $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
592
     * @param  string    $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
593
     * @param  integer   $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
594
     * @return string
595
     */
596
    protected function parseCompare(Query $query, $key, $exp, $value, $field, $bindType)
597
    {
598
        if (is_array($value)) {
599
            throw new Exception('where express error:' . $exp . var_export($value, true));
600
        }
601
602
        // 比较运算
603
        if ($value instanceof \Closure) {
604
            $value = $this->parseClosure($query, $value);
605
        }
606
607
        if ('=' == $exp && is_null($value)) {
608
            return $key . ' IS NULL';
609
        }
610
611
        return $key . ' ' . $exp . ' ' . $value;
612
    }
613
614
    /**
615
     * 时间范围查询
616
     * @access protected
617
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
618
     * @param  string    $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
619
     * @param  string    $exp
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
620
     * @param  mixed     $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
621
     * @param  string    $field
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
622
     * @param  integer   $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
623
     * @return string
624
     */
625
    protected function parseBetweenTime(Query $query, $key, $exp, $value, $field, $bindType)
626
    {
627
        if (is_string($value)) {
628
            $value = explode(',', $value);
629
        }
630
631
        return $key . ' ' . substr($exp, 0, -4)
632
        . $this->parseDateTime($query, $value[0], $field, $bindType)
633
        . ' AND '
634
        . $this->parseDateTime($query, $value[1], $field, $bindType);
635
636
    }
637
638
    /**
639
     * IN查询
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 parseIn(Query $query, $key, $exp, $value, $field, $bindType)
650
    {
651
        // IN 查询
652
        if ($value instanceof \Closure) {
653
            $value = $this->parseClosure($query, $value, false);
654
        } elseif ($value instanceof Expression) {
655
            $value = $value->getValue();
656
        } else {
657
            $value = array_unique(is_array($value) ? $value : explode(',', $value));
658
            $array = [];
659
660
            foreach ($value as $k => $v) {
661
                $name    = $query->bind($v, $bindType);
662
                $array[] = ':' . $name;
0 ignored issues
show
Bug introduced by
Are you sure $name of type string|think\db\Query can be used in concatenation? ( Ignorable by Annotation )

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

662
                $array[] = ':' . /** @scrutinizer ignore-type */ $name;
Loading history...
663
            }
664
665
            if (count($array) == 1) {
666
                return $key . ' = ' . $array[0];
667
            } else {
668
                $zone  = implode(',', $array);
669
                $value = empty($zone) ? "''" : $zone;
670
            }
671
        }
672
673
        return $key . ' ' . $exp . ' (' . $value . ')';
674
    }
675
676
    /**
677
     * 闭包子查询
678
     * @access protected
679
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
680
     * @param  \Closure  $call
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
681
     * @param  bool      $show
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
682
     * @return string
683
     */
684
    protected function parseClosure(Query $query, $call, $show = true)
685
    {
686
        $newQuery = $query->newQuery()->setConnection($this->connection);
687
        $call($newQuery);
688
689
        return $newQuery->buildSql($show);
690
    }
691
692
    /**
693
     * 日期时间条件解析
694
     * @access protected
695
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
696
     * @param  string    $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
697
     * @param  string    $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
698
     * @param  integer   $bindType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
699
     * @return string
700
     */
701
    protected function parseDateTime(Query $query, $value, $key, $bindType = null)
702
    {
703
        $options = $query->getOptions();
704
705
        // 获取时间字段类型
706
        if (strpos($key, '.')) {
707
            list($table, $key) = explode('.', $key);
708
709
            if (isset($options['alias']) && $pos = array_search($table, $options['alias'])) {
710
                $table = $pos;
711
            }
712
        } else {
713
            $table = $options['table'];
714
        }
715
716
        $type = $this->connection->getTableInfo($table, 'type');
717
718
        if (isset($type[$key])) {
719
            $info = $type[$key];
720
        }
721
722
        if (isset($info)) {
723
            if (is_string($value)) {
0 ignored issues
show
introduced by
The condition is_string($value) is always true.
Loading history...
724
                $value = strtotime($value) ?: $value;
725
            }
726
727
            if (preg_match('/(datetime|timestamp)/is', $info)) {
728
                // 日期及时间戳类型
729
                $value = date('Y-m-d H:i:s', $value);
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type string; however, parameter $timestamp of date() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

729
                $value = date('Y-m-d H:i:s', /** @scrutinizer ignore-type */ $value);
Loading history...
730
            } elseif (preg_match('/(date)/is', $info)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $info does not seem to be defined for all execution paths leading up to this point.
Loading history...
731
                // 日期及时间戳类型
732
                $value = date('Y-m-d', $value);
733
            }
734
        }
735
736
        $name = $query->bind($value, $bindType);
737
738
        return ':' . $name;
739
    }
740
741
    /**
742
     * limit分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
743
     * @access protected
744
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
745
     * @param  mixed     $limit
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
746
     * @return string
747
     */
748
    protected function parseLimit(Query $query, $limit)
749
    {
750
        return (!empty($limit) && false === strpos($limit, '(')) ? ' LIMIT ' . $limit . ' ' : '';
751
    }
752
753
    /**
754
     * join分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
755
     * @access protected
756
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
757
     * @param  array     $join
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
758
     * @return string
759
     */
760
    protected function parseJoin(Query $query, $join)
761
    {
762
        $joinStr = '';
763
764
        if (!empty($join)) {
765
            foreach ($join as $item) {
766
                list($table, $type, $on) = $item;
767
768
                $condition = [];
769
770
                foreach ((array) $on as $val) {
771
                    if ($val instanceof Expression) {
772
                        $condition[] = $val->getValue();
773
                    } elseif (strpos($val, '=')) {
774
                        list($val1, $val2) = explode('=', $val, 2);
775
776
                        $condition[] = $this->parseKey($query, $val1) . '=' . $this->parseKey($query, $val2);
777
                    } else {
778
                        $condition[] = $val;
779
                    }
780
                }
781
782
                $table = $this->parseTable($query, $table);
783
784
                $joinStr .= ' ' . $type . ' JOIN ' . $table . ' ON ' . implode(' AND ', $condition);
785
            }
786
        }
787
788
        return $joinStr;
789
    }
790
791
    /**
792
     * order分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
793
     * @access protected
794
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
795
     * @param  mixed     $order
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
796
     * @return string
797
     */
798
    protected function parseOrder(Query $query, $order)
799
    {
800
        foreach ($order as $key => $val) {
801
            if ($val instanceof Expression) {
802
                $array[] = $val->getValue();
803
            } elseif (is_array($val) && preg_match('/^[\w\.]+$/', $key)) {
804
                $array[] = $this->parseOrderField($query, $key, $val);
805
            } elseif ('[rand]' == $val) {
806
                $array[] = $this->parseRand($query);
0 ignored issues
show
Bug introduced by
The method parseRand() does not exist on think\db\Builder. Did you maybe mean parseIn()? ( Ignorable by Annotation )

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

806
                /** @scrutinizer ignore-call */ 
807
                $array[] = $this->parseRand($query);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
807
            } elseif (is_string($val)) {
808
                if (is_numeric($key)) {
809
                    list($key, $sort) = explode(' ', strpos($val, ' ') ? $val : $val . ' ');
810
                } else {
811
                    $sort = $val;
812
                }
813
814
                if (preg_match('/^[\w\.]+$/', $key)) {
815
                    $sort    = strtoupper($sort);
816
                    $sort    = in_array($sort, ['ASC', 'DESC'], true) ? ' ' . $sort : '';
817
                    $array[] = $this->parseKey($query, $key, true) . $sort;
818
                } else {
819
                    throw new Exception('order express error:' . $key);
820
                }
821
            }
822
        }
823
824
        return empty($array) ? '' : ' ORDER BY ' . implode(',', $array);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $array seems to be defined by a foreach iteration on line 800. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
825
    }
826
827
    /**
828
     * orderField分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
829
     * @access protected
830
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
831
     * @param  mixed     $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
832
     * @param  array     $val
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
833
     * @return string
834
     */
835
    protected function parseOrderField($query, $key, $val)
836
    {
837
        if (isset($val['sort'])) {
838
            $sort = $val['sort'];
839
            unset($val['sort']);
840
        } else {
841
            $sort = '';
842
        }
843
844
        $sort = strtoupper($sort);
845
        $sort = in_array($sort, ['ASC', 'DESC'], true) ? ' ' . $sort : '';
846
847
        $options = $query->getOptions();
848
        $bind    = $this->connection->getFieldsBind($options['table']);
849
850
        foreach ($val as $k => $item) {
851
            $val[$k] = $this->parseDataBind($query, $key, $item, $bind);
852
        }
853
854
        return 'field(' . $this->parseKey($query, $key, true) . ',' . implode(',', $val) . ')' . $sort;
855
    }
856
857
    /**
858
     * group分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
859
     * @access protected
860
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
861
     * @param  mixed     $group
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
862
     * @return string
863
     */
864
    protected function parseGroup(Query $query, $group)
865
    {
866
        if (empty($group)) {
867
            return '';
868
        }
869
870
        if (is_string($group)) {
871
            $group = explode(',', $group);
872
        }
873
874
        foreach ($group as $key) {
875
            $val[] = $this->parseKey($query, $key);
876
        }
877
878
        return ' GROUP BY ' . implode(',', $val);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $val seems to be defined by a foreach iteration on line 874. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
879
    }
880
881
    /**
882
     * having分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
883
     * @access protected
884
     * @param  Query  $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 8 found
Loading history...
885
     * @param  string $having
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
886
     * @return string
887
     */
888
    protected function parseHaving(Query $query, $having)
889
    {
890
        return !empty($having) ? ' HAVING ' . $having : '';
891
    }
892
893
    /**
894
     * comment分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
895
     * @access protected
896
     * @param  Query  $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 8 found
Loading history...
897
     * @param  string $comment
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
898
     * @return string
899
     */
900
    protected function parseComment(Query $query, $comment)
901
    {
902
        if (false !== strpos($comment, '*/')) {
903
            $comment = strstr($comment, '*/', true);
904
        }
905
906
        return !empty($comment) ? ' /* ' . $comment . ' */' : '';
907
    }
908
909
    /**
910
     * distinct分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
911
     * @access protected
912
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 8 found
Loading history...
913
     * @param  mixed     $distinct
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
914
     * @return string
915
     */
916
    protected function parseDistinct(Query $query, $distinct)
917
    {
918
        return !empty($distinct) ? ' DISTINCT ' : '';
919
    }
920
921
    /**
922
     * union分析
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
923
     * @access protected
924
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
925
     * @param  mixed     $union
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
926
     * @return string
927
     */
928
    protected function parseUnion(Query $query, $union)
929
    {
930
        if (empty($union)) {
931
            return '';
932
        }
933
934
        $type = $union['type'];
935
        unset($union['type']);
936
937
        foreach ($union as $u) {
938
            if ($u instanceof \Closure) {
939
                $sql[] = $type . ' ' . $this->parseClosure($query, $u);
940
            } elseif (is_string($u)) {
941
                $sql[] = $type . ' ( ' . $this->connection->parseSqlTable($u) . ' )';
942
            }
943
        }
944
945
        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 937. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
946
    }
947
948
    /**
949
     * index分析,可在操作链中指定需要强制使用的索引
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
950
     * @access protected
951
     * @param  Query     $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
952
     * @param  mixed     $index
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
953
     * @return string
954
     */
955
    protected function parseForce(Query $query, $index)
956
    {
957
        if (empty($index)) {
958
            return '';
959
        }
960
961
        return sprintf(" FORCE INDEX ( %s ) ", is_array($index) ? implode(',', $index) : $index);
962
    }
963
964
    /**
965
     * 设置锁机制
966
     * @access protected
967
     * @param  Query         $query        查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 8 found
Loading history...
968
     * @param  bool|string   $lock
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
969
     * @return string
970
     */
971
    protected function parseLock(Query $query, $lock = false)
972
    {
973
        if (is_bool($lock)) {
974
            return $lock ? ' FOR UPDATE ' : '';
975
        } elseif (is_string($lock) && !empty($lock)) {
976
            return ' ' . trim($lock) . ' ';
977
        }
978
    }
979
980
    /**
981
     * 生成查询SQL
982
     * @access public
983
     * @param  Query  $query  查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
984
     * @return string
985
     */
986
    public function select(Query $query)
987
    {
988
        $options = $query->getOptions();
989
990
        return str_replace(
991
            ['%TABLE%', '%DISTINCT%', '%FIELD%', '%JOIN%', '%WHERE%', '%GROUP%', '%HAVING%', '%ORDER%', '%LIMIT%', '%UNION%', '%LOCK%', '%COMMENT%', '%FORCE%'],
992
            [
993
                $this->parseTable($query, $options['table']),
994
                $this->parseDistinct($query, $options['distinct']),
995
                $this->parseField($query, $options['field']),
996
                $this->parseJoin($query, $options['join']),
997
                $this->parseWhere($query, $options['where']),
998
                $this->parseGroup($query, $options['group']),
999
                $this->parseHaving($query, $options['having']),
1000
                $this->parseOrder($query, $options['order']),
1001
                $this->parseLimit($query, $options['limit']),
1002
                $this->parseUnion($query, $options['union']),
1003
                $this->parseLock($query, $options['lock']),
1004
                $this->parseComment($query, $options['comment']),
1005
                $this->parseForce($query, $options['force']),
1006
            ],
1007
            $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...
1008
    }
1009
1010
    /**
1011
     * 生成Insert SQL
1012
     * @access public
1013
     * @param  Query     $query   查询对象
1014
     * @param  bool      $replace 是否replace
1015
     * @return string
1016
     */
1017
    public function insert(Query $query, $replace = false)
1018
    {
1019
        $options = $query->getOptions();
1020
1021
        // 分析并处理数据
1022
        $data = $this->parseData($query, $options['data']);
1023
        if (empty($data)) {
1024
            return '';
1025
        }
1026
1027
        $fields = array_keys($data);
1028
        $values = array_values($data);
1029
1030
        return str_replace(
1031
            ['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'],
1032
            [
1033
                $replace ? 'REPLACE' : 'INSERT',
1034
                $this->parseTable($query, $options['table']),
1035
                implode(' , ', $fields),
1036
                implode(' , ', $values),
1037
                $this->parseComment($query, $options['comment']),
1038
            ],
1039
            $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...
1040
    }
1041
1042
    /**
1043
     * 生成insertall SQL
1044
     * @access public
1045
     * @param  Query     $query   查询对象
1046
     * @param  array     $dataSet 数据集
1047
     * @param  bool      $replace 是否replace
1048
     * @return string
1049
     */
1050
    public function insertAll(Query $query, $dataSet, $replace = false)
1051
    {
1052
        $options = $query->getOptions();
1053
1054
        // 获取合法的字段
1055
        if ('*' == $options['field']) {
1056
            $allowFields = $this->connection->getTableFields($options['table']);
1057
        } else {
1058
            $allowFields = $options['field'];
1059
        }
1060
1061
        // 获取绑定信息
1062
        $bind = $this->connection->getFieldsBind($options['table']);
1063
1064
        foreach ($dataSet as $data) {
1065
            $data = $this->parseData($query, $data, $allowFields, $bind);
1066
1067
            $values[] = 'SELECT ' . implode(',', array_values($data));
1068
1069
            if (!isset($insertFields)) {
1070
                $insertFields = array_keys($data);
1071
            }
1072
        }
1073
1074
        $fields = [];
1075
1076
        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 1064. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
1077
            $fields[] = $this->parseKey($query, $field);
1078
        }
1079
1080
        return str_replace(
1081
            ['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'],
1082
            [
1083
                $replace ? 'REPLACE' : 'INSERT',
1084
                $this->parseTable($query, $options['table']),
1085
                implode(' , ', $fields),
1086
                implode(' UNION ALL ', $values),
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $values seems to be defined by a foreach iteration on line 1064. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
1087
                $this->parseComment($query, $options['comment']),
1088
            ],
1089
            $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...
1090
    }
1091
1092
    /**
1093
     * 生成slect insert SQL
1094
     * @access public
1095
     * @param  Query     $query  查询对象
1096
     * @param  array     $fields 数据
1097
     * @param  string    $table  数据表
1098
     * @return string
1099
     */
1100
    public function selectInsert(Query $query, $fields, $table)
1101
    {
1102
        if (is_string($fields)) {
0 ignored issues
show
introduced by
The condition is_string($fields) is always false.
Loading history...
1103
            $fields = explode(',', $fields);
1104
        }
1105
1106
        foreach ($fields as &$field) {
1107
            $field = $this->parseKey($query, $field, true);
1108
        }
1109
1110
        return 'INSERT INTO ' . $this->parseTable($query, $table) . ' (' . implode(',', $fields) . ') ' . $this->select($query);
1111
    }
1112
1113
    /**
1114
     * 生成update SQL
1115
     * @access public
1116
     * @param  Query     $query  查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1117
     * @return string
1118
     */
1119
    public function update(Query $query)
1120
    {
1121
        $options = $query->getOptions();
1122
1123
        $data = $this->parseData($query, $options['data']);
1124
1125
        if (empty($data)) {
1126
            return '';
1127
        }
1128
1129
        foreach ($data as $key => $val) {
1130
            $set[] = $key . ' = ' . $val;
1131
        }
1132
1133
        return str_replace(
1134
            ['%TABLE%', '%SET%', '%JOIN%', '%WHERE%', '%ORDER%', '%LIMIT%', '%LOCK%', '%COMMENT%'],
1135
            [
1136
                $this->parseTable($query, $options['table']),
1137
                implode(' , ', $set),
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $set seems to be defined by a foreach iteration on line 1129. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
1138
                $this->parseJoin($query, $options['join']),
1139
                $this->parseWhere($query, $options['where']),
1140
                $this->parseOrder($query, $options['order']),
1141
                $this->parseLimit($query, $options['limit']),
1142
                $this->parseLock($query, $options['lock']),
1143
                $this->parseComment($query, $options['comment']),
1144
            ],
1145
            $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...
1146
    }
1147
1148
    /**
1149
     * 生成delete SQL
1150
     * @access public
1151
     * @param  Query  $query  查询对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1152
     * @return string
1153
     */
1154
    public function delete(Query $query)
1155
    {
1156
        $options = $query->getOptions();
1157
1158
        return str_replace(
1159
            ['%TABLE%', '%USING%', '%JOIN%', '%WHERE%', '%ORDER%', '%LIMIT%', '%LOCK%', '%COMMENT%'],
1160
            [
1161
                $this->parseTable($query, $options['table']),
1162
                !empty($options['using']) ? ' USING ' . $this->parseTable($query, $options['using']) . ' ' : '',
1163
                $this->parseJoin($query, $options['join']),
1164
                $this->parseWhere($query, $options['where']),
1165
                $this->parseOrder($query, $options['order']),
1166
                $this->parseLimit($query, $options['limit']),
1167
                $this->parseLock($query, $options['lock']),
1168
                $this->parseComment($query, $options['comment']),
1169
            ],
1170
            $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...
1171
    }
1172
}
1173