Completed
Push — master ( c43049...0986b8 )
by Alexey
04:57
created

Query::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 8
rs 9.4285
cc 2
eloc 5
nc 2
nop 1
1
<?php
2
3
/**
4
 * Query class for mysql driver
5
 *
6
 * @author Alexey Krupskiy <[email protected]>
7
 * @link http://inji.ru/
8
 * @copyright 2015 Alexey Krupskiy
9
 * @license https://github.com/injitools/cms-Inji/blob/master/LICENSE
10
 */
11
12
namespace Db\Mysql;
13
14
class Query extends \Object
15
{
16
    public $curInstance = null;
17
    public $where = [];
18
    public $whereString = '';
19
    public $cols = [];
20
    public $order = NULL;
21
    public $join = [];
22
    public $group = [];
23
    public $limit = '';
24
    public $error = '';
25
    public $query = '';
26
    public $table = '';
27
    public $operation = '';
28
    public $indexes = [];
29
    public $params = [];
30
    public $distinct = false;
31
32
    public function __construct($instance = null)
33
    {
34
        if (!$instance) {
35
            $this->curInstance = \App::$cur->db->connection;
36
        } else {
37
            $this->curInstance = $instance;
38
        }
39
    }
40
41
    public function insert($table, $data)
42
    {
43
        $this->operation = 'INSERT';
44
        $this->table = $table;
45
        $this->cols = $data;
46
        $this->query();
47
        return $this->curInstance->pdo->lastInsertId();
48
    }
49
50
    public function select($table)
51
    {
52
        $this->operation = 'SELECT';
53
        $this->table = $table;
54
        return $this->query();
55
    }
56
57 View Code Duplication
    public function update($table, $data)
58
    {
59
        $this->operation = 'UPDATE';
60
        $this->table = $table;
61
        $this->cols = $data;
62
        $result = $this->query();
63
        return $result->pdoResult->rowCount();
64
    }
65
66 View Code Duplication
    public function delete($table)
67
    {
68
        $this->operation = 'DELETE';
69
        $this->table = $table;
70
        $result = $this->query();
71
        return $result->pdoResult->rowCount();
72
    }
73
74
    public function createTable($table_name, $cols, $indexes = [])
75
    {
76
        $this->operation = 'CREATE TABLE';
77
        $this->table = $table_name;
78
        $this->cols = $cols;
79
        $this->indexes = $indexes;
80
        return $this->query();
81
    }
82
83
    public function cols($cols)
84
    {
85
        if (is_array($cols)) {
86
            $this->cols = array_merge($this->cols, array_values($cols));
87
        } else {
88
            $this->cols[] = $cols;
89
        }
90
    }
91
92
    public function join($table, $where = false, $type = 'LEFT', $alias = '')
93
    {
94
        if (is_array($table)) {
95 View Code Duplication
            foreach ($table as $item) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
96
                if (!is_array($item)) {
97
                    call_user_func_array(array($this, 'join'), $table);
98
                    break;
99
                } else {
100
                    $this->join($item);
101
                }
102
            }
103
        } else {
104
            $this->join[] = [$table, $where, $type, $alias];
105
        }
106
    }
107
108
    public function where($where = '', $value = '', $operation = false, $concatenation = 'AND')
109
    {
110
        if (!is_array($where)) {
111
            $this->where[] = [$where, $value, $operation, $concatenation];
112
        } else {
113
            $this->where[] = $where;
114
        }
115
    }
116
117
    public function group($colname)
118
    {
119
        $this->group[] = $colname;
120
    }
121
122
    public function order($order, $type = 'ASC')
123
    {
124
125
126
        if (!is_array($order)) {
127
            $this->order[] = "{$order} {$type}";
128
        } else {
129 View Code Duplication
            foreach ($order as $item)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
130
                if (!is_array($item)) {
131
                    call_user_func_array(array($this, 'order'), $order);
132
                    break;
133
                } else
134
                    $this->order($item);
135
        }
136
    }
137
138
    public function limit($start = 0, $len = 0)
139
    {
140
        $start = intval($start);
141
        $len = intval($len);
142
        $this->limit = "LIMIT {$start}";
143
        if ($len !== 0)
144
            $this->limit .= ",{$len}";
145
    }
146
147
    public function buildJoin($table, $where = false, $type = 'LEFT', $alias = '')
148
    {
149
        $join = '';
150
        if (is_array($table)) {
151
            $joins = func_get_args();
152
            foreach ($joins as $joinAr) {
153
                $join .= call_user_func_array([$this, 'buildJoin'], $joinAr);
154
            }
155
        } else {
156
            $join .= " {$type} JOIN {$this->curInstance->table_prefix}{$table}";
157
            if ($alias)
158
                $join .= " AS `{$alias}`";
159
            if ($where)
160
                $join .= " ON {$where}";
161
        }
162
        return $join;
163
    }
164
165
    /**
166
     * Build where string
167
     * 
168
     * @param string|array $where
169
     * @param mixed $value
170
     * @param string $operation
171
     * @param string $concatenation
172
     */
173
    public function buildWhere($where = '', $value = '', $operation = '=', $concatenation = 'AND')
174
    {
175
        if (!is_array($where)) {
176
            if (empty($operation)) {
177
                $operation = '=';
178
            }
179
180
            if ($concatenation === false)
181
                $concatenation = 'AND';
182
            elseif ($concatenation === true)
183
                $concatenation = '';
184
185
            if ($this->whereString == NULL)
186
                $this->whereString = ' WHERE ';
187
188
            if (stristr($operation, 'IN') || stristr($operation, 'NOT IN')) {
189
                if (is_array($value)) {
190
                    $newValue = '';
191
                    foreach ($value as $item) {
192
                        if ($newValue) {
193
                            $newValue.=',';
194
                        }
195
                        if (is_string($item)) {
196
                            $newValue .='"' . $item . '"';
197
                        } else {
198
                            $newValue .=$item;
199
                        }
200
                    }
201
                    $value = '(' . $newValue . ')';
202
                } elseif (!preg_match('!\(!', $value) && !preg_match('![^0-9,\.\(\) ]!', $value))
203
                    $value = "({$value})";
204
                elseif (preg_match('!\(!', $value) && preg_match('![^0-9,\.\(\) ]!', $value))
205
                    $value = "\"{$value}\"";
206
            }
207
            elseif (!in_array($value, array('CURRENT_TIMESTAMP'))) {
208
                $this->params[] = $value;
209
                $value = "?";
210
            }
211
212
            if (substr($this->whereString, -1, 1) == '(' || substr($this->whereString, -2, 2) == 'E ')
213
                $this->whereString .= " {$where} {$operation} {$value} ";
214
            else
215
                $this->whereString .= "{$concatenation} {$where} {$operation} {$value} ";
216
        }
217
        else {
218
            $i = -1;
219
            while (isset($where[++$i])) {
220
                $item = $where[$i];
221
                if (isset($where[$i + 1]) && !isset($where[$i - 1]) && is_array($where[$i])) {
222
                    if ($this->whereString != NULL && substr($this->whereString, -1, 1) != '(' && $this->whereString != 'WHERE ') {
223
                        if (!isset($item[3])) {
224
                            $concatenation = 'AND';
225
                        } else {
226
                            $concatenation = $item[3];
227
                        }
228
229
                        $this->whereString .= "{$concatenation} ";
230
                    }
231
232
                    if ($this->whereString != NULL)
233
                        $this->whereString .= '(';
234
                    else
235
                        $this->whereString = 'WHERE (';
236
                }
237
238
                if (!is_array($item)) {
239
                    call_user_func_array(array($this, 'buildWhere'), $where);
240
                    break;
241
                } else {
242
                    if ($this->whereString != NULL && substr($this->whereString, -1, 1) != '(')
243
                        if (!isset($item[3]))
244
                            $concatenation = 'AND';
0 ignored issues
show
Unused Code introduced by
$concatenation is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
245
                        else
246
                            $concatenation = $item[3];
0 ignored issues
show
Unused Code introduced by
$concatenation is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
247
                    elseif (substr($this->whereString, -1, 1) != '(')
248
                        $this->whereString = 'WHERE ';
249
250
                    $this->buildWhere($item);
251
                }
252
                if (!isset($where[$i + 1]) && isset($where[$i - 1]))
253
                    $this->whereString .= ') ';
254
            }
255
        }
256
    }
257
258
    public function buildQuery()
259
    {
260
        $query = $this->operation;
261
        $this->operation = strtoupper($this->operation);
262
263
        switch ($this->operation) {
264
            case 'SELECT':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
265
                $query .= ' ' . ($this->distinct ? 'DISTINCT' : '');
266
                $query .= ' ' . (!$this->cols ? '*' : ((is_array($this->cols) ? implode(',', $this->cols) : $this->cols)));
267
            case 'DELETE':
268
                $query .= ' FROM';
269
                break;
270
            case 'INSERT':
271
                $query .= ' INTO';
272
                break;
273
        }
274
        $query .= " `{$this->curInstance->db_name}`.`{$this->curInstance->table_prefix}{$this->table}`";
275
        if ($this->join) {
276
            $query .= $this->buildJoin($this->join);
277
        }
278
        switch ($this->operation) {
279
            case 'INSERT':
280
                $this->params = array_merge($this->params, array_values($this->cols));
281
                $colsStr = '';
282
                if ($this->cols) {
283
                    $colsStr = '`' . implode('`,`', array_keys($this->cols)) . '`';
284
                }
285
                $query .= ' (' . $colsStr . ') VALUES (' . rtrim(str_repeat('?,', count($this->cols)), ',') . ')';
286
                break;
287
            case 'CREATE TABLE':
288
                $query .= " (";
289
                foreach ($this->cols as $col_name => $param) {
290
                    if ($param == 'pk') {
291
                        $param = "int(11) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (`{$col_name}`)";
292
                    }
293
                    $query .= " `{$col_name}` {$param},";
294
                }
295
                $query = rtrim($query, ',');
296
                if ($this->indexes) {
297
                    $query .= ', ' . implode(',', $this->indexes);
298
                }
299
                $query .= ") ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_general_ci";
300
                break;
301
            case 'UPDATE':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
302
                $updates = [];
303
                foreach ($this->cols as $key => $item) {
304
                    if (!in_array($item, array('CURRENT_TIMESTAMP'))) {
305
                        $this->params[] = $item;
306
                        $updates[] = "`{$key}` = ?";
307
                    } else {
308
                        $updates[] = "`{$key}` = {$item}";
309
                    }
310
                }
311
                $update = implode(',', $updates);
312
                $query .=" SET {$update}";
313
            case 'SELECT':
314
            case 'DELETE':
315
                $this->buildWhere($this->where);
316
                if ($this->whereString) {
317
                    $query .= ' ' . $this->whereString;
318
                }
319
                break;
320
        }
321
        if ($this->group) {
322
            $query .= ' GROUP BY ' . implode(',', $this->group);
323
        }
324
        if ($this->order) {
325
            $query .= ' ORDER BY ' . implode(',', $this->order);
326
        }
327
        if ($this->limit) {
328
            $query .= ' ' . $this->limit;
329
        }
330
        return ['query' => $query, 'params' => $this->params];
331
    }
332
333
    /**
334
     * Execute query
335
     * 
336
     * @param string|array $query
337
     * @return \Db\Mysql\Result
338
     */
339
    public function query($query = [])
340
    {
341
        if (!$query) {
342
            $this->params = [];
343
            $query = $this->buildQuery();
344
        }
345
346
        if (is_string($query)) {
347
            $query = ['query' => $query, 'params' => $this->params];
348
        }
349
        $prepare = $this->curInstance->pdo->prepare($query['query']);
350
        $prepare->execute($query['params']);
351
        $this->curInstance->lastQuery = $query;
352
        $result = new Result();
353
        $result->pdoResult = $prepare;
354
        if ($this->curInstance->dbInstance->curQuery && $this->curInstance->dbInstance->curQuery === $this) {
355
            $this->curInstance->dbInstance->curQuery = null;
356
        }
357
358
        return $result;
359
    }
360
361
}
362