GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Select::join()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 4
nop 3
dl 0
loc 16
ccs 0
cts 8
cp 0
crap 12
rs 9.4285
c 0
b 0
f 0
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 $this
22
     */
23 7
    public function __call($name, $arguments)
24
    {
25 7
        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 7
        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
    public function join($table, $on = false, $type = '')
85
    {
86
        $lastTable = end($this->parts['from']);
87
88
        if (!$lastTable) {
89
            trigger_error('No previous table to JOIN', E_USER_ERROR);
90
        }
91
92
        if (is_array($lastTable)) {
93
            $lastTable = $lastTable[1];
94
        }
95
96
        $this->parts['join'][$lastTable][] = [$table, $on, $type];
97
98
        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 7
    public function assemble()
120
    {
121 7
        $select = $this->parseCols();
122 7
        $options = $this->parseOptions();
123 7
        $from = $this->parseFrom();
124
125 7
        $group = $this->parseGroup();
126 7
        $having = $this->parseHaving();
127
128 7
        $order = $this->parseOrder();
129
130 7
        $query = "SELECT";
131
132 7
        if (!empty($options)) {
133 1
            $query .= " $options";
134
        }
135
136 7
        if (!empty($select)) {
137 7
            $query .= " $select";
138
        }
139
140 7
        if (!empty($from)) {
141 7
            $query .= " FROM $from";
142
        }
143
144 7
        $query .= $this->assembleWhere();
145
146 7
        if (!empty($group)) {
147
            $query .= " GROUP BY $group";
148
        }
149
150 7
        if (!empty($having)) {
151
            $query .= " HAVING $having";
152
        }
153
154 7
        if (!empty($order)) {
155
            $query .= " ORDER BY $order";
156
        }
157
158 7
        $query .= $this->assembleLimit();
159
160 7
        return $query;
161
    }
162
163
    /**
164
     * @return null|string
165
     */
166 7
    public function parseOptions()
167
    {
168 7
        if (!empty($this->parts['options'])) {
169 1
            return implode(" ", array_map("strtoupper", $this->parts['options']));
170
        }
171
172 6
        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 7
    protected function parseCols()
190
    {
191 7
        if (!isset($this->parts['cols']) or !is_array($this->parts['cols']) or count($this->parts['cols']) < 1) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
192 2
            return '*';
193
        } else {
194 5
            $selectParts = [];
195
196 5
            foreach ($this->parts['cols'] as $itemSelect) {
197 5
                if (is_array($itemSelect)) {
198 1
                    $field = isset($itemSelect[0]) ? $itemSelect[0] : false;
199 1
                    $alias = isset($itemSelect[1]) ? $itemSelect[1] : false;
200 1
                    $protected = isset($itemSelect[2]) ? $itemSelect[2] : true;
201
202 1
                    $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 7
    private function parseFrom()
217
    {
218 7
        if (!empty($this->parts['from'])) {
219 7
            $parts = [];
220
221 7
            foreach ($this->parts['from'] as $key => $item) {
222 7
                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 7
                } elseif (!strpos($item, ' ')) {
235 3
                    $parts[] = $this->protect($item) . $this->parseJoin($item);
236
                } else {
237 7
                    $parts[] = $item;
238
                }
239
            }
240
241 7
            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 3
    private function parseJoin($table)
255
    {
256 3
        $result = '';
257
258 3
        if (isset($this->parts['join'][$table])) {
259
            foreach ($this->parts['join'][$table] as $join) {
260
                if (!is_array($join[0])) {
261
                    $join[0] = [$join[0]];
262
                }
263
264
                $joinTable = isset($join[0][0]) ? $join[0][0] : false;
265
                $joinAlias = isset($join[0][1]) ? $join[0][1] : false;
266
                $joinOn = isset($join[1]) ? $join[1] : false;
267
268
269
                $joinType = isset($join[2]) ? $join[2] : '';
270
271
                $result .= ($joinType ? ' ' . strtoupper($joinType) : '') . ' JOIN ';
272
                if (strpos($joinTable, '(') !== false) {
273
                    $result .= $joinTable;
274
                } else {
275
                    $result .= $this->protect($joinTable);
276
                }
277
                $result .= (!empty($joinAlias) ? ' AS ' . $this->protect($joinAlias) : '');
278
279
                if ($joinOn) {
280
                    $result .= ' ON ';
281
                    if (is_array($joinOn)) {
282
                        $result .= $this->protect($table . '.' . $joinOn[0]) . ' = ' . $this->protect($joinTable . '.' . $joinOn[1]);
283
                    } else {
284
                        $result .= '(' . $joinOn . ')';
285
                    }
286
                }
287
288
            }
289
        }
290
291 3
        return $result;
292
    }
293
294
    /**
295
     * Parses GROUP entries
296
     *
297
     * @uses $this->group['fields'] array with elements to group by
298
     * @return string
299
     */
300 7
    private function parseGroup()
301
    {
302 7
        $group = '';
303 7
        if (isset ($this->parts['group']['fields'])) {
304
            if (is_array($this->parts['group']['fields'])) {
305
                $groupFields = [];
306
                foreach ($this->parts['group']['fields'] as $field) {
307
                    $field = is_array($field) ? $field : [$field];
308
                    $column = isset($field[0]) ? $field[0] : false;
309
                    $type = isset($field[1]) ? $field[1] : '';
310
311
                    $groupFields[] = $this->protect($column) . ($type ? ' ' . strtoupper($type) : '');
312
                }
313
314
                $group .= implode(', ', $groupFields);
315
            } else {
316
                $group .= $this->parts['group']['fields'];
317
            }
318
        }
319
320 7
        if (isset($this->parts['group']['rollup']) && $this->parts['group']['rollup'] !== false) {
321
            $group .= ' WITH ROLLUP';
322
        }
323
324 7
        return $group;
325
    }
326
}
327