Passed
Push — master ( bab9dc...bf7b05 )
by Gabriel
02:36
created

Select::parseCols()   B

Complexity

Conditions 11
Paths 35

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 15.4801

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 8
cts 12
cp 0.6667
rs 7.3166
c 0
b 0
f 0
cc 11
nc 35
nop 0
crap 15.4801

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Nip\Database\Query;
4
5
use Nip\Database\Query\Select\Union;
6
7
/**
8
 * Class Select
9
 * @package Nip\Database\Query
10
 *
11
 * @method $this options() options(string $option = null)
12
 * @method $this setFrom() setFrom(string $table = null)
13
 * @method $this setOrder() setOrder(array | string $cols = null)
14
 */
15
class Select extends AbstractQuery
16
{
17
18
    /**
19
     * @param $name
20
     * @param $arguments
21
     * @return AbstractQuery|Select
22
     */
23 11
    public function __call($name, $arguments)
24
    {
25 11
        if (in_array($name, ['min', 'max', 'count', 'avg', 'sum'])) {
26
            $input = reset($arguments);
27
28
            if (is_array($input)) {
29
                $input[] = false;
30
            } else {
31
                $alias = isset($arguments[1]) ? $arguments[1] : null;
32
                $protected = isset($arguments[2]) ? $arguments[2] : null;
33
                $input = [$input, $alias, $protected];
34
            }
35
36
            $input[0] = strtoupper($name).'('.$this->protect($input[0]).')';
0 ignored issues
show
Documentation introduced by
$input[0] is of type boolean, but the function expects a string.

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...
37
38
            return $this->cols($input);
0 ignored issues
show
Unused Code introduced by
The call to Select::cols() has too many arguments starting with $input.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
39
        }
40
41 11
        return parent::__call($name, $arguments);
42
    }
43
44
    /**
45
     * Inserts FULLTEXT statement into $this->select and $this->where
46
     *
47
     * @param mixed $fields
48
     * @param string $against
49
     * @param string $alias
50
     * @param boolean $boolean_mode
51
     * @return $this
52
     */
53
    public function match($fields, $against, $alias, $boolean_mode = true)
54
    {
55
        if (!is_array($fields)) {
56
            $fields = [];
57
        }
58
59
        $match = [];
60
        foreach ($fields as $itemField) {
61
            if (!is_array($itemField)) {
62
                $itemField = [$itemField];
63
64
                $field = isset($itemField[0]) ? $itemField[0] : false;
65
                $protected = isset($itemField[1]) ? $itemField[1] : true;
66
67
                $match[] = $protected ? $this->protect($field) : $field;
68
            }
69
        }
70
        $match = "MATCH(".implode(",",
71
                $match).") AGAINST ('".$against."'".($boolean_mode ? " IN BOOLEAN MODE" : "").")";
72
73
        return $this->cols([$match, $alias, false])->where([$match]);
0 ignored issues
show
Unused Code introduced by
The call to Select::cols() has too many arguments starting with array($match, $alias, false).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
74
    }
75
76
    /**
77
     * Inserts JOIN entry for the last table inserted by $this->from()
78
     *
79
     * @param mixed $table the table to be joined, given as simple string or name - alias pair
80
     * @param string|boolean $on
81
     * @param string $type SQL join type (INNER, OUTER, LEFT INNER, etc.)
82
     * @return $this
83
     */
84 3
    public function join($table, $on = false, $type = '')
85
    {
86 3
        $lastTable = end($this->parts['from']);
87
88 3
        if (!$lastTable) {
89
            trigger_error('No previous table to JOIN', E_USER_ERROR);
90
        }
91
92 3
        if (is_array($lastTable)) {
93
            $lastTable = $lastTable[1];
94
        }
95
96 3
        $this->parts['join'][$lastTable][] = [$table, $on, $type];
97
98 3
        return $this;
99
    }
100
101
    /**
102
     * Sets the group paramater for the query
103
     *
104
     * @param array $fields
105
     * @param boolean $rollup suport for modifier WITH ROLLUP
106
     * @return $this
107
     */
108
    public function group($fields, $rollup = false)
109
    {
110
        $this->parts['group']['fields'] = $fields;
111
        $this->parts['group']['rollup'] = $rollup;
112
113
        return $this;
114
    }
115
116
    /**
117
     * @return string
118
     */
119 10
    public function assemble()
120
    {
121 10
        $select = $this->parseCols();
122 10
        $options = $this->parseOptions();
123 10
        $from = $this->parseFrom();
124
125 10
        $group = $this->parseGroup();
126 10
        $having = $this->parseHaving();
127
128 10
        $order = $this->parseOrder();
129
130 10
        $query = "SELECT";
131
132 10
        if (!empty($options)) {
133 1
            $query .= " $options";
134
        }
135
136 10
        if (!empty($select)) {
137 10
            $query .= " $select";
138
        }
139
140 10
        if (!empty($from)) {
141 10
            $query .= " FROM $from";
142
        }
143
144 10
        $query .= $this->assembleWhere();
145
146 10
        if (!empty($group)) {
147
            $query .= " GROUP BY $group";
148
        }
149
150 10
        if (!empty($having)) {
151
            $query .= " HAVING $having";
152
        }
153
154 10
        if (!empty($order)) {
155
            $query .= " ORDER BY $order";
156
        }
157
158 10
        $query .= $this->assembleLimit();
159
160 10
        return $query;
161
    }
162
163
    /**
164
     * @return null|string
165
     */
166 10
    public function parseOptions()
167
    {
168 10
        if (!empty($this->parts['options'])) {
169 1
            return implode(" ", array_map("strtoupper", $this->parts['options']));
170
        }
171
172 9
        return null;
173
    }
174
175
    /**
176
     * @param $query
177
     * @return Union
178
     */
179 1
    public function union($query)
180
    {
181 1
        return new Union($this, $query);
182
    }
183
184
    /**
185
     * Parses SELECT entries
186
     *
187
     * @return string
188
     */
189 10
    protected function parseCols()
190
    {
191 10
        if (!isset($this->parts['cols']) || !is_array($this->parts['cols']) || count($this->parts['cols']) < 1) {
192 5
            return '*';
193
        } else {
194 5
            $selectParts = [];
195
196 5
            foreach ($this->parts['cols'] as $itemSelect) {
197 5
                if (is_array($itemSelect)) {
198
                    $field = isset($itemSelect[0]) ? $itemSelect[0] : false;
199
                    $alias = isset($itemSelect[1]) ? $itemSelect[1] : false;
200
                    $protected = isset($itemSelect[2]) ? $itemSelect[2] : true;
201
202
                    $selectParts[] = ($protected ? $this->protect($field) : $field).(!empty($alias) ? ' AS '.$this->protect($alias) : '');
203
                } else {
204 5
                    $selectParts[] = $itemSelect;
205
                }
206
            }
207
208 5
            return implode(', ', $selectParts);
209
        }
210
    }
211
212
    /**
213
     * Parses FROM entries
214
     * @return string
215
     */
216 10
    private function parseFrom()
217
    {
218 10
        if (!empty($this->parts['from'])) {
219 10
            $parts = [];
220
221 10
            foreach ($this->parts['from'] as $key => $item) {
222 10
                if (is_array($item)) {
223
                    $table = isset($item[0]) ? $item[0] : false;
224
                    $alias = isset($item[1]) ? $item[1] : false;
225
226
                    if (is_object($table)) {
227
                        if (!$alias) {
228
                            trigger_error('Select statements in for need aliases defined', E_USER_ERROR);
229
                        }
230
                        $parts[$key] = '('.$table.') AS '.$this->protect($alias).$this->parseJoin($alias);
231
                    } else {
232
                        $parts[$key] = $this->protect($table).' AS '.$this->protect((!empty($alias) ? $alias : $table)).$this->parseJoin($alias);
233
                    }
234 10
                } elseif (!strpos($item, ' ')) {
235 5
                    $parts[] = $this->protect($item).$this->parseJoin($item);
236
                } else {
237 10
                    $parts[] = $item;
238
                }
239
            }
240
241 10
            return implode(", ", array_unique($parts));
242
        }
243
244
        return null;
245
    }
246
247
    /**
248
     * Parses JOIN entries for a given table
249
     * Concatenates $this->join entries for input table
250
     *
251
     * @param string $table table to build JOIN statement for
252
     * @return string
253
     */
254 5
    private function parseJoin($table)
255
    {
256 5
        $result = '';
257
258 5
        if (isset($this->parts['join'][$table])) {
259 3
            foreach ($this->parts['join'][$table] as $join) {
260 3
                if (!is_array($join[0])) {
261 1
                    $join[0] = [$join[0]];
262
                }
263
264 3
                $joinTable = isset($join[0][0]) ? $join[0][0] : false;
265 3
                $joinAlias = isset($join[0][1]) ? $join[0][1] : false;
266 3
                $joinOn = isset($join[1]) ? $join[1] : false;
267
268
269 3
                $joinType = isset($join[2]) ? $join[2] : '';
270
271 3
                $result .= ($joinType ? ' '.strtoupper($joinType) : '').' JOIN ';
272 3
                if ($joinTable instanceof AbstractQuery) {
273 1
                    $result .= '('.$joinTable.')';
274 1
                    if (empty($joinAlias)) {
275
                        $joinAlias = 'join1';
276
                    }
277 1
                    $joinTable = $joinAlias;
278 2
                } elseif (strpos($joinTable, '(') !== false) {
279
                    $result .= $joinTable;
280
                } else {
281 2
                    $result .= $this->protect($joinTable);
282
                }
283 3
                $result .= (!empty($joinAlias) ? ' AS '.$this->protect($joinAlias) : '');
284
285 3
                if ($joinOn) {
286 3
                    $result .= ' ON ';
287 3
                    if (is_array($joinOn)) {
288 3
                        $result .= $this->protect($table.'.'.$joinOn[0])
289 3
                            .' = '
290 3
                            .$this->protect($joinTable.'.'.$joinOn[1]);
291
                    } else {
292 3
                        $result .= '('.$joinOn.')';
293
                    }
294
                }
295
            }
296
        }
297
298 5
        return $result;
299
    }
300
301
    /**
302
     * Parses GROUP entries
303
     *
304
     * @uses $this->group['fields'] array with elements to group by
305
     * @return string
306
     */
307 10
    private function parseGroup()
308
    {
309 10
        $group = '';
310 10
        if (isset($this->parts['group']['fields'])) {
311
            if (is_array($this->parts['group']['fields'])) {
312
                $groupFields = [];
313
                foreach ($this->parts['group']['fields'] as $field) {
314
                    $field = is_array($field) ? $field : [$field];
315
                    $column = isset($field[0]) ? $field[0] : false;
316
                    $type = isset($field[1]) ? $field[1] : '';
317
318
                    $groupFields[] = $this->protect($column).($type ? ' '.strtoupper($type) : '');
319
                }
320
321
                $group .= implode(', ', $groupFields);
322
            } else {
323
                $group .= $this->parts['group']['fields'];
324
            }
325
        }
326
327 10
        if (isset($this->parts['group']['rollup']) && $this->parts['group']['rollup'] !== false) {
328
            $group .= ' WITH ROLLUP';
329
        }
330
331 10
        return $group;
332
    }
333
}
334