Completed
Push — master ( ce46b7...20cdab )
by Andrii
02:21
created

AbstractQueryBuilder   B

Complexity

Total Complexity 40

Size/Duplication

Total Lines 256
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 12.09%

Importance

Changes 0
Metric Value
wmc 40
lcom 1
cbo 7
dl 0
loc 256
ccs 11
cts 91
cp 0.1209
rs 8.2608
c 0
b 0
f 0

29 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A build() 0 4 1
A createRequest() 0 6 2
buildAuth() 0 1 ?
buildMethod() 0 1 ?
buildUri() 0 1 ?
buildHeaders() 0 1 ?
buildProtocolVersion() 0 1 ?
buildQueryParams() 0 1 ?
buildFormParams() 0 1 ?
buildBody() 0 1 ?
A update() 0 6 1
A delete() 0 6 1
B buildCondition() 0 37 5
A buildLikeCondition() 0 4 1
A buildIlikeCondition() 0 4 1
A buildCompareCondition() 0 8 2
A buildBetweenCondition() 0 4 1
A buildNotInCondition() 0 4 1
A buildEqCondition() 0 6 1
A buildNotEqCondition() 0 6 1
A buildCompositeInCondition() 0 4 1
A prepare() 0 4 1
A insert() 0 4 1
A perform() 0 6 1
A createQuery() 0 6 1
A buildHashCondition() 0 14 3
A buildAndCondition() 0 14 4
D buildInCondition() 0 30 9

How to fix   Complexity   

Complex Class

Complex classes like AbstractQueryBuilder 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 AbstractQueryBuilder, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * ActiveRecord for API
4
 *
5
 * @link      https://github.com/hiqdev/yii2-hiart
6
 * @package   yii2-hiart
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2015-2017, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hiqdev\hiart;
12
13
use yii\base\InvalidParamException;
14
use yii\base\NotSupportedException;
15
use yii\helpers\ArrayHelper;
16
17
/**
18
 * Abstract QueryBuilder.
19
 *
20
 * QueryBuilder builds a request from the specification given as a [[Query]] object.
21
 */
22
abstract class AbstractQueryBuilder extends \yii\base\Object implements QueryBuilderInterface
23
{
24
    /**
25
     * @var AbstractConnection
26
     */
27
    public $db;
28
29 1
    public function __construct($connection, $config = [])
30
    {
31 1
        $this->db = $connection;
32 1
        parent::__construct($config);
33 1
    }
34
35
    /**
36
     * Builds config array to create Command.
37
     * @param Query $query
38
     * @throws NotSupportedException
39
     * @return array
40
     */
41 2
    public function build(Query $query)
42
    {
43 2
        return ['request' => $this->createRequest($query)];
44
    }
45
46 2
    public function createRequest($query)
47
    {
48 2
        $request = new $this->db->requestClass($this, $query);
49
50 2
        return $request instanceof RequestCreatorInterface ? $request->createRequest() : $request;
51
    }
52
53
    /**
54
     * Prepares query before actual building.
55
     * This function for you to redefine.
56
     * It will be called before other build functions.
57
     * @param Query $query
58
     */
59 2
    public function prepare(Query $query)
60
    {
61 2
        return $query->prepare($this);
0 ignored issues
show
Documentation introduced by
$this is of type this<hiqdev\hiart\AbstractQueryBuilder>, but the function expects a object<yii\db\QueryBuilder>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
62
    }
63
64
    /**
65
     * This function is for you to provide your authentication.
66
     * @param Query $query
67
     */
68
    abstract public function buildAuth(Query $query);
69
70
    abstract public function buildMethod(Query $query);
71
72
    abstract public function buildUri(Query $query);
73
74
    abstract public function buildHeaders(Query $query);
75
76
    abstract public function buildProtocolVersion(Query $query);
77
78
    abstract public function buildQueryParams(Query $query);
79
80
    abstract public function buildFormParams(Query $query);
81
82
    abstract public function buildBody(Query $query);
83
84
    /**
85
     * Creates insert request.
86
     * @param string $table
87
     * @param array $columns
88
     * @param array $options
89
     * @return AbstractRequest
90
     */
91
    public function insert($table, $columns, array $options = [])
92
    {
93
        return $this->perform('insert', $table, $columns, $options);
94
    }
95
96
    /**
97
     * Creates update request.
98
     * @param string $table
99
     * @param array $columns
100
     * @param array $options
101
     * @return AbstractRequest
102
     */
103
    public function update($table, $columns, $condition = [], array $options = [])
104
    {
105
        $query = $this->createQuery('update', $table, $options)->body($columns)->where($condition);
106
107
        return $this->createRequest($query);
108
    }
109
110
    public function delete($table, $condition = [], array $options = [])
111
    {
112
        $query = $this->createQuery('delete', $table, $options)->where($condition);
113
114
        return $this->createRequest($query);
115
    }
116
117
    public function perform($action, $table, $body, $options = [])
118
    {
119
        $query = $this->createQuery($action, $table, $options)->body($body);
120
121
        return $this->createRequest($query);
122
    }
123
124
    public function createQuery($action, $table, array $options = [])
125
    {
126
        $class = $this->db->queryClass;
127
128
        return $class::instantiate($action, $table, $options);
129
    }
130
131
    public function buildCondition($condition)
132
    {
133
        static $builders = [
134
            'and'     => 'buildAndCondition',
135
            'between' => 'buildBetweenCondition',
136
            'eq'      => 'buildEqCondition',
137
            'ne'      => 'buildNotEqCondition',
138
            'in'      => 'buildInCondition',
139
            'ni'      => 'buildNotInCondition',
140
            'like'    => 'buildLikeCondition',
141
            'ilike'   => 'buildIlikeCondition',
142
            'gt'      => 'buildCompareCondition',
143
            'ge'      => 'buildCompareCondition',
144
            'lt'      => 'buildCompareCondition',
145
            'le'      => 'buildCompareCondition',
146
        ];
147
        if (empty($condition)) {
148
            return [];
149
        }
150
        if (!is_array($condition)) {
151
            throw new NotSupportedException('String conditions in where() are not supported by HiArt.');
152
        }
153
154
        if (isset($condition[0])) { // operator format: operator, operand 1, operand 2, ...
155
            $operator = strtolower($condition[0]);
156
            if (isset($builders[$operator])) {
157
                $method = $builders[$operator];
158
                array_shift($condition); // Shift build condition
159
160
                return $this->$method($operator, $condition);
161
            } else {
162
                throw new InvalidParamException('Found unknown operator in query: ' . $operator);
163
            }
164
        } else {
165
            return $this->buildHashCondition($condition);
166
        }
167
    }
168
169
    protected function buildHashCondition($condition)
170
    {
171
        $parts = [];
172
        foreach ($condition as $attribute => $value) {
173
            if (is_array($value)) { // IN condition
174
                // $parts[] = [$attribute.'s' => join(',',$value)];
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
175
                $parts[$attribute . 's'] = implode(',', $value);
176
            } else {
177
                $parts[$attribute] = $value;
178
            }
179
        }
180
181
        return $parts;
182
    }
183
184
    protected function buildLikeCondition($operator, $operands)
0 ignored issues
show
Unused Code introduced by
The parameter $operator is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
185
    {
186
        return [$operands[0] . '_like' => $operands[1]];
187
    }
188
189
    protected function buildIlikeCondition($operator, $operands)
0 ignored issues
show
Unused Code introduced by
The parameter $operator is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
190
    {
191
        return [$operands[0] . '_ilike' => $operands[1]];
192
    }
193
194
    protected function buildCompareCondition($operator, $operands)
195
    {
196
        if (!isset($operands[0], $operands[1])) {
197
            throw new InvalidParamException("Operator '$operator' requires three operands.");
198
        }
199
200
        return [$operands[0] . '_' . $operator => $operands[1]];
201
    }
202
203
    protected function buildAndCondition($operator, $operands)
0 ignored issues
show
Unused Code introduced by
The parameter $operator is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
204
    {
205
        $parts = [];
206
        foreach ($operands as $operand) {
207
            if (is_array($operand)) {
208
                $parts = ArrayHelper::merge($this->buildCondition($operand), $parts);
209
            }
210
        }
211
        if (!empty($parts)) {
212
            return $parts;
213
        } else {
214
            return [];
215
        }
216
    }
217
218
    protected function buildBetweenCondition($operator, $operands)
0 ignored issues
show
Unused Code introduced by
The parameter $operator is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $operands is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
219
    {
220
        throw new NotSupportedException('Between condition is not supported by HiArt.');
221
    }
222
223
    protected function buildInCondition($operator, $operands, $not = false)
224
    {
225
        if (!isset($operands[0], $operands[1])) {
226
            throw new InvalidParamException("Operator '$operator' requires two operands.");
227
        }
228
229
        list($column, $values) = $operands;
230
231
        if (count($column) > 1) {
232
            return $this->buildCompositeInCondition($operator, $column, $values);
233
        } elseif (is_array($column)) {
234
            $column = reset($column);
235
        }
236
237
        foreach ((array) $values as $i => $value) {
238
            if (is_array($value)) {
239
                $values[$i] = $value = isset($value[$column]) ? $value[$column] : null;
240
            }
241
            if ($value === null) {
242
                unset($values[$i]);
243
            }
244
        }
245
246
        if ($not) {
247
            $key = $column . '_ni'; // not in
248
        } else {
249
            $key = $column . '_in';
250
        }
251
        return [$key => $values];
252
    }
253
254
    protected function buildNotInCondition($operator, $operands)
255
    {
256
        return $this->buildInCondition($operator, $operands, true);
257
    }
258
259
    protected function buildEqCondition($operator, $operands)
0 ignored issues
show
Unused Code introduced by
The parameter $operator is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
260
    {
261
        $key = array_shift($operands);
262
263
        return [$key => reset($operands)];
264
    }
265
266
    protected function buildNotEqCondition($operator, $operands)
267
    {
268
        $key = array_shift($operands);
269
270
        return [$key . '_' . $operator => reset($operands)];
271
    }
272
273
    protected function buildCompositeInCondition($operator, $columns, $values)
0 ignored issues
show
Unused Code introduced by
The parameter $operator is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $columns is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $values is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
274
    {
275
        throw new NotSupportedException('composite in is not supported by HiArt.');
276
    }
277
}
278