Completed
Push — 6.0 ( be0b6e...c47dd5 )
by liu
06:54 queued 10s
created

JoinAndViewQuery   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 255
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
eloc 102
dl 0
loc 255
ccs 0
cts 102
cp 0
rs 8.8
c 0
b 0
f 0
wmc 45

8 Methods

Rating   Name   Duplication   Size   Complexity  
A rightJoin() 0 3 1
B withJoin() 0 43 8
B getJoinTable() 0 37 11
A leftJoin() 0 3 1
A fullJoin() 0 3 1
A join() 0 11 3
C parseView() 0 32 13
B view() 0 42 7

How to fix   Complexity   

Complex Class

Complex classes like JoinAndViewQuery often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use JoinAndViewQuery, and based on these observations, apply Extract Interface, too.

1
<?php
2
// +----------------------------------------------------------------------
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\concern;
14
15
use Closure;
16
use think\App;
17
use think\db\Raw;
18
use think\model\relation\OneToOne;
19
20
/**
21
 * JOIN和VIEW查询
22
 */
23
trait JoinAndViewQuery
24
{
25
26
    /**
27
     * 查询SQL组装 join
28
     * @access public
29
     * @param mixed  $join      关联的表名
30
     * @param mixed  $condition 条件
31
     * @param string $type      JOIN类型
32
     * @param array  $bind      参数绑定
33
     * @return $this
34
     */
35
    public function join($join, string $condition = null, string $type = 'INNER', array $bind = [])
36
    {
37
        $table = $this->getJoinTable($join);
38
39
        if (!empty($bind) && $condition) {
40
            $this->bindParams($condition, $bind);
0 ignored issues
show
Bug introduced by
It seems like bindParams() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

40
            $this->/** @scrutinizer ignore-call */ 
41
                   bindParams($condition, $bind);
Loading history...
41
        }
42
43
        $this->options['join'][] = [$table, strtoupper($type), $condition];
0 ignored issues
show
Bug Best Practice introduced by
The property options does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
44
45
        return $this;
46
    }
47
48
    /**
49
     * LEFT JOIN
50
     * @access public
51
     * @param mixed $join      关联的表名
52
     * @param mixed $condition 条件
53
     * @param array $bind      参数绑定
54
     * @return $this
55
     */
56
    public function leftJoin($join, string $condition = null, array $bind = [])
57
    {
58
        return $this->join($join, $condition, 'LEFT', $bind);
59
    }
60
61
    /**
62
     * RIGHT JOIN
63
     * @access public
64
     * @param mixed $join      关联的表名
65
     * @param mixed $condition 条件
66
     * @param array $bind      参数绑定
67
     * @return $this
68
     */
69
    public function rightJoin($join, string $condition = null, array $bind = [])
70
    {
71
        return $this->join($join, $condition, 'RIGHT', $bind);
72
    }
73
74
    /**
75
     * FULL JOIN
76
     * @access public
77
     * @param mixed $join      关联的表名
78
     * @param mixed $condition 条件
79
     * @param array $bind      参数绑定
80
     * @return $this
81
     */
82
    public function fullJoin($join, string $condition = null, array $bind = [])
83
    {
84
        return $this->join($join, $condition, 'FULL');
85
    }
86
87
    /**
88
     * 获取Join表名及别名 支持
89
     * ['prefix_table或者子查询'=>'alias'] 'table alias'
90
     * @access protected
91
     * @param array|string|Raw $join  JION表名
92
     * @param string           $alias 别名
93
     * @return string|array
94
     */
95
    protected function getJoinTable($join, &$alias = null)
96
    {
97
        if (is_array($join)) {
98
            $table = $join;
99
            $alias = array_shift($join);
100
            return $table;
101
        } elseif ($join instanceof Raw) {
102
            return $join;
103
        }
104
105
        $join = trim($join);
106
107
        if (false !== strpos($join, '(')) {
108
            // 使用子查询
109
            $table = $join;
110
        } else {
111
            // 使用别名
112
            if (strpos($join, ' ')) {
113
                // 使用别名
114
                list($table, $alias) = explode(' ', $join);
115
            } else {
116
                $table = $join;
117
                if (false === strpos($join, '.')) {
118
                    $alias = $join;
119
                }
120
            }
121
122
            if ($this->prefix && false === strpos($table, '.') && 0 !== strpos($table, $this->prefix)) {
123
                $table = $this->getTable($table);
0 ignored issues
show
Bug introduced by
The method getTable() does not exist on think\db\concern\JoinAndViewQuery. Did you maybe mean getJoinTable()? ( Ignorable by Annotation )

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

123
                /** @scrutinizer ignore-call */ 
124
                $table = $this->getTable($table);

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...
124
            }
125
        }
126
127
        if (!empty($alias) && $table != $alias) {
128
            $table = [$table => $alias];
129
        }
130
131
        return $table;
132
    }
133
134
    /**
135
     * 关联预载入 JOIN方式
136
     * @access protected
137
     * @param array|string $with     关联方法名
138
     * @param string       $joinType JOIN方式
139
     * @return $this
140
     */
141
    public function withJoin($with, string $joinType = '')
142
    {
143
        if (empty($with)) {
144
            return $this;
145
        }
146
147
        $first = true;
148
149
        /** @var Model $class */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
150
        $class = $this->model;
151
        foreach ((array) $with as $key => $relation) {
152
            $closure = null;
153
            $field   = true;
154
155
            if ($relation instanceof Closure) {
156
                // 支持闭包查询过滤关联条件
157
                $closure  = $relation;
158
                $relation = $key;
159
            } elseif (is_array($relation)) {
160
                $field    = $relation;
161
                $relation = $key;
162
            } elseif (is_string($relation) && strpos($relation, '.')) {
163
                $relation = strstr($relation, '.', true);
164
            }
165
166
            /** @var Relation $model */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
167
            $relation = App::parseName($relation, 1, false);
168
            $model    = $class->$relation();
169
170
            if ($model instanceof OneToOne) {
171
                $model->eagerly($this, $relation, $field, $joinType, $closure, $first);
172
                $first = false;
173
            } else {
174
                // 不支持其它关联
175
                unset($with[$key]);
176
            }
177
        }
178
179
        $this->via();
0 ignored issues
show
Bug introduced by
It seems like via() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

179
        $this->/** @scrutinizer ignore-call */ 
180
               via();
Loading history...
180
181
        $this->options['with_join'] = $with;
0 ignored issues
show
Bug Best Practice introduced by
The property options does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
182
183
        return $this;
184
    }
185
186
    /**
187
     * 指定JOIN查询字段
188
     * @access public
189
     * @param string|array $join  数据表
190
     * @param string|array $field 查询字段
191
     * @param string       $on    JOIN条件
192
     * @param string       $type  JOIN类型
193
     * @param array        $bind  参数绑定
194
     * @return $this
195
     */
196
    public function view($join, $field = true, $on = null, string $type = 'INNER', array $bind = [])
197
    {
198
        $this->options['view'] = true;
0 ignored issues
show
Bug Best Practice introduced by
The property options does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
199
200
        $fields = [];
201
        $table  = $this->getJoinTable($join, $alias);
202
203
        if (true === $field) {
204
            $fields = $alias . '.*';
205
        } else {
206
            if (is_string($field)) {
207
                $field = explode(',', $field);
208
            }
209
210
            foreach ($field as $key => $val) {
211
                if (is_numeric($key)) {
212
                    $fields[] = $alias . '.' . $val;
213
214
                    $this->options['map'][$val] = $alias . '.' . $val;
215
                } else {
216
                    if (preg_match('/[,=\.\'\"\(\s]/', $key)) {
217
                        $name = $key;
218
                    } else {
219
                        $name = $alias . '.' . $key;
220
                    }
221
222
                    $fields[] = $name . ' AS ' . $val;
223
224
                    $this->options['map'][$val] = $name;
225
                }
226
            }
227
        }
228
229
        $this->field($fields);
0 ignored issues
show
Bug introduced by
It seems like field() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

229
        $this->/** @scrutinizer ignore-call */ 
230
               field($fields);
Loading history...
230
231
        if ($on) {
232
            $this->join($table, $on, $type, $bind);
233
        } else {
234
            $this->table($table);
0 ignored issues
show
Bug introduced by
It seems like table() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

234
            $this->/** @scrutinizer ignore-call */ 
235
                   table($table);
Loading history...
235
        }
236
237
        return $this;
238
    }
239
240
    /**
241
     * 视图查询处理
242
     * @access protected
243
     * @param array $options 查询参数
244
     * @return void
245
     */
246
    protected function parseView(array &$options): void
247
    {
248
        foreach (['AND', 'OR'] as $logic) {
249
            if (isset($options['where'][$logic])) {
250
                foreach ($options['where'][$logic] as $key => $val) {
251
                    if (array_key_exists($key, $options['map'])) {
252
                        array_shift($val);
253
                        array_unshift($val, $options['map'][$key]);
254
                        $options['where'][$logic][$options['map'][$key]] = $val;
255
                        unset($options['where'][$logic][$key]);
256
                    }
257
                }
258
            }
259
        }
260
261
        if (isset($options['order'])) {
262
            // 视图查询排序处理
263
            foreach ($options['order'] as $key => $val) {
264
                if (is_numeric($key) && is_string($val)) {
265
                    if (strpos($val, ' ')) {
266
                        list($field, $sort) = explode(' ', $val);
267
                        if (array_key_exists($field, $options['map'])) {
268
                            $options['order'][$options['map'][$field]] = $sort;
269
                            unset($options['order'][$key]);
270
                        }
271
                    } elseif (array_key_exists($val, $options['map'])) {
272
                        $options['order'][$options['map'][$val]] = 'asc';
273
                        unset($options['order'][$key]);
274
                    }
275
                } elseif (array_key_exists($key, $options['map'])) {
276
                    $options['order'][$options['map'][$key]] = $val;
277
                    unset($options['order'][$key]);
278
                }
279
            }
280
        }
281
    }
282
283
}
284