Completed
Push — master ( 5e98ad...5c516d )
by Alexey
04:03
created

Query::cols()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
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 $having = [];
20
  public $havingString = '';
21
  public $cols = [];
22
  public $order = NULL;
23
  public $join = [];
24
  public $group = [];
25
  public $limit = '';
26
  public $error = '';
27
  public $query = '';
28
  public $table = '';
29
  public $operation = '';
30
  public $indexes = [];
31
  public $params = [];
32
  public $distinct = false;
33
34
  public function __construct($instance = null) {
35
    if (!$instance) {
36
      $this->curInstance = \App::$cur->db->connection;
37
    } else {
38
      $this->curInstance = $instance;
39
    }
40
  }
41
42
  public function insert($table, $data) {
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
    $this->operation = 'SELECT';
52
    $this->table = $table;
53
    return $this->query();
54
  }
55
56 View Code Duplication
  public function update($table, $data) {
57
    $this->operation = 'UPDATE';
58
    $this->table = $table;
59
    $this->cols = $data;
60
    $result = $this->query();
61
    return $result->pdoResult->rowCount();
62
  }
63
64 View Code Duplication
  public function delete($table) {
65
    $this->operation = 'DELETE';
66
    $this->table = $table;
67
    $result = $this->query();
68
    return $result->pdoResult->rowCount();
69
  }
70
71
  public function createTable($table_name, $cols, $indexes = []) {
72
    $this->operation = 'CREATE TABLE';
73
    $this->table = $table_name;
74
    $this->cols = $cols;
75
    $this->indexes = $indexes;
76
    return $this->query();
77
  }
78
79
  public function cols($cols) {
80
    if (is_array($cols)) {
81
      $this->cols = array_merge($this->cols, array_values($cols));
82
    } else {
83
      $this->cols[] = $cols;
84
    }
85
  }
86
87
  public function join($table, $where = false, $type = 'LEFT', $alias = '') {
88
    if (is_array($table)) {
89 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...
90
        if (!is_array($item)) {
91
          call_user_func_array(array($this, 'join'), $table);
92
          break;
93
        } else {
94
          $this->join($item);
95
        }
96
      }
97
    } else {
98
      $this->join[] = [$table, $where, $type, $alias];
99
    }
100
  }
101
102 View Code Duplication
  public function where($where = '', $value = '', $operation = false, $concatenation = 'AND') {
103
    if (!is_array($where)) {
104
      $this->where[] = [$where, $value, $operation, $concatenation];
105
    } else {
106
      $this->where[] = $where;
107
    }
108
  }
109
110 View Code Duplication
  public function having($where = '', $value = '', $operation = false, $concatenation = 'AND') {
111
    if (!is_array($where)) {
112
      $this->having[] = [$where, $value, $operation, $concatenation];
113
    } else {
114
      $this->having[] = $where;
115
    }
116
  }
117
118
  public function group($colname) {
119
    $this->group[] = $colname;
120
  }
121
122
  public function order($order, $type = 'ASC') {
123
124
125
    if (!is_array($order)) {
126
      $this->order[] = "{$order} {$type}";
127
    } else {
128 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...
129
        if (!is_array($item)) {
130
          call_user_func_array(array($this, 'order'), $order);
131
          break;
132
        } else
133
          $this->order($item);
134
    }
135
  }
136
137
  public function limit($start = 0, $len = 0) {
138
    $start = intval($start);
139
    $len = intval($len);
140
    $this->limit = "LIMIT {$start}";
141
    if ($len !== 0)
142
      $this->limit .= ",{$len}";
143
  }
144
145
  public function buildJoin($table, $where = false, $type = 'LEFT', $alias = '') {
146
    $join = '';
147
    if (is_array($table)) {
148
      $joins = func_get_args();
149
      foreach ($joins as $joinAr) {
150
        $join .= call_user_func_array([$this, 'buildJoin'], $joinAr);
151
      }
152
    } else {
153
      $join .= " {$type} JOIN {$this->curInstance->table_prefix}{$table}";
154
      if ($alias)
155
        $join .= " AS `{$alias}`";
156
      if ($where)
157
        $join .= " ON {$where}";
158
    }
159
    return $join;
160
  }
161
162
  /**
163
   * Build where string
164
   * 
165
   * @param string|array $where
166
   * @param mixed $value
167
   * @param string $operation
168
   * @param string $concatenation
169
   */
170 View Code Duplication
  public function buildWhere($where = '', $value = '', $operation = '=', $concatenation = 'AND') {
171
    if (!is_array($where)) {
172
      if (empty($operation)) {
173
        $operation = '=';
174
      }
175
176
      if ($concatenation === false)
177
        $concatenation = 'AND';
178
      elseif ($concatenation === true)
179
        $concatenation = '';
180
181
      if ($this->whereString == NULL)
182
        $this->whereString = ' WHERE ';
183
184
      if (stristr($operation, 'IN') || stristr($operation, 'NOT IN')) {
185
        if (is_array($value)) {
186
          $newValue = '';
187
          foreach ($value as $item) {
188
            if ($newValue) {
189
              $newValue.=',';
190
            }
191
            if (is_string($item)) {
192
              $newValue .='"' . $item . '"';
193
            } else {
194
              $newValue .=$item;
195
            }
196
          }
197
          $value = '(' . $newValue . ')';
198
        } elseif (!preg_match('!\(!', $value) && !preg_match('![^0-9,\.\(\) ]!', $value)) {
199
          $value = "({$value})";
200
        } elseif (preg_match('!\(!', $value) && preg_match('![^0-9,\.\(\) ]!', $value)) {
201
          $value = "\"{$value}\"";
202
        }
203
      } elseif (!in_array($value, array('CURRENT_TIMESTAMP'))) {
204
        $this->params[] = $value;
205
        $value = "?";
206
      }
207
208
      if (substr($this->whereString, -1, 1) == '(' || substr($this->whereString, -2, 2) == 'E ')
209
        $this->whereString .= " {$where} {$operation} {$value} ";
210
      else
211
        $this->whereString .= "{$concatenation} {$where} {$operation} {$value} ";
212
    }
213
    else {
214
      $i = -1;
215
      while (isset($where[++$i])) {
216
        $item = $where[$i];
217
        if (isset($where[$i + 1]) && !isset($where[$i - 1]) && is_array($where[$i])) {
218
          if ($this->whereString != NULL && substr($this->whereString, -1, 1) != '(' && $this->whereString != 'WHERE ') {
219
            if (!isset($item[3])) {
220
              $concatenation = 'AND';
221
            } else {
222
              $concatenation = $item[3];
223
            }
224
225
            $this->whereString .= "{$concatenation} ";
226
          }
227
228
          if ($this->whereString != NULL)
229
            $this->whereString .= '(';
230
          else
231
            $this->whereString = 'WHERE (';
232
        }
233
234
        if (!is_array($item)) {
235
          call_user_func_array(array($this, 'buildWhere'), $where);
236
          break;
237
        } else {
238
          $this->buildWhere($item);
239
        }
240
        if (!isset($where[$i + 1]) && isset($where[$i - 1])) {
241
          $this->whereString .= ') ';
242
        }
243
      }
244
    }
245
  }
246
247
  /**
248
   * Build having string
249
   * 
250
   * @param string|array $where
251
   * @param mixed $value
252
   * @param string $operation
253
   * @param string $concatenation
254
   */
255 View Code Duplication
  public function buildHaving($where = '', $value = '', $operation = '=', $concatenation = 'AND') {
256
    if (!is_array($where)) {
257
      if (empty($operation)) {
258
        $operation = '=';
259
      }
260
      if ($concatenation === false)
261
        $concatenation = 'AND';
262
      elseif ($concatenation === true)
263
        $concatenation = '';
264
265
      if ($this->havingString == NULL)
266
        $this->havingString = ' HAVING ';
267
268
      if (stristr($operation, 'IN') || stristr($operation, 'NOT IN')) {
269
        if (is_array($value)) {
270
          $newValue = '';
271
          foreach ($value as $item) {
272
            if ($newValue) {
273
              $newValue.=',';
274
            }
275
            if (is_string($item)) {
276
              $newValue .='"' . $item . '"';
277
            } else {
278
              $newValue .=$item;
279
            }
280
          }
281
          $value = '(' . $newValue . ')';
282
        } elseif (!preg_match('!\(!', $value) && !preg_match('![^0-9,\.\(\) ]!', $value)) {
283
          $value = "({$value})";
284
        } elseif (preg_match('!\(!', $value) && preg_match('![^0-9,\.\(\) ]!', $value)) {
285
          $value = "\"{$value}\"";
286
        }
287
      } elseif (!in_array($value, array('CURRENT_TIMESTAMP'))) {
288
        $this->params[] = $value;
289
        $value = "?";
290
      }
291
292
      if (substr($this->havingString, -1, 1) == '(' || substr($this->havingString, -2, 2) == 'E ')
293
        $this->havingString .= " {$where} {$operation} {$value} ";
294
      else
295
        $this->havingString .= "{$concatenation} {$where} {$operation} {$value} ";
296
    }
297
    else {
298
      $i = -1;
299
      while (isset($where[++$i])) {
300
        $item = $where[$i];
301
        if (isset($where[$i + 1]) && !isset($where[$i - 1]) && is_array($where[$i])) {
302
          if ($this->havingString != NULL && substr($this->havingString, -1, 1) != '(' && $this->havingString != 'HAVING ') {
303
            if (!isset($item[3])) {
304
              $concatenation = 'AND';
305
            } else {
306
              $concatenation = $item[3];
307
            }
308
309
            $this->havingString .= "{$concatenation} ";
310
          }
311
312
          if ($this->havingString != NULL)
313
            $this->havingString .= '(';
314
          else
315
            $this->havingString = 'HAVING (';
316
        }
317
318
        if (!is_array($item)) {
319
          call_user_func_array(array($this, 'buildHaving'), $where);
320
          break;
321
        } else {
322
          $this->buildHaving($item);
323
        }
324
        if (!isset($where[$i + 1]) && isset($where[$i - 1])) {
325
          $this->havingString .= ') ';
326
        }
327
      }
328
    }
329
  }
330
331
  public function buildQuery() {
332
    $query = $this->operation;
333
    $this->operation = strtoupper($this->operation);
334
335
    switch ($this->operation) {
336
      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...
337
        $query .= ' ' . ($this->distinct ? 'DISTINCT' : '');
338
        $query .= ' ' . (!$this->cols ? '*' : ((is_array($this->cols) ? implode(',', $this->cols) : $this->cols)));
339
      case 'DELETE':
340
        $query .= ' FROM';
341
        break;
342
      case 'INSERT':
343
        $query .= ' INTO';
344
        break;
345
    }
346
    $query .= " `{$this->curInstance->db_name}`.`{$this->curInstance->table_prefix}{$this->table}`";
347
    if ($this->join) {
348
      $query .= $this->buildJoin($this->join);
349
    }
350
    switch ($this->operation) {
351
      case 'INSERT':
352
        $this->params = array_merge($this->params, array_values($this->cols));
353
        $colsStr = '';
354
        if ($this->cols) {
355
          $colsStr = '`' . implode('`,`', array_keys($this->cols)) . '`';
356
        }
357
        $query .= ' (' . $colsStr . ') VALUES (' . rtrim(str_repeat('?,', count($this->cols)), ',') . ')';
358
        break;
359
      case 'CREATE TABLE':
360
        $query .= " (";
361
        foreach ($this->cols as $col_name => $param) {
362
          if ($param == 'pk') {
363
            $param = "int(11) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (`{$col_name}`)";
364
          }
365
          $query .= " `{$col_name}` {$param},";
366
        }
367
        $query = rtrim($query, ',');
368
        if ($this->indexes) {
369
          $query .= ', ' . implode(',', $this->indexes);
370
        }
371
        $query .= ") ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_general_ci";
372
        break;
373
      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...
374
        $updates = [];
375
        foreach ($this->cols as $key => $item) {
376
          if (!in_array($item, array('CURRENT_TIMESTAMP'))) {
377
            $this->params[] = $item;
378
            $updates[] = "`{$key}` = ?";
379
          } else {
380
            $updates[] = "`{$key}` = {$item}";
381
          }
382
        }
383
        $update = implode(',', $updates);
384
        $query .=" SET {$update}";
385
      case 'SELECT':
386
      case 'DELETE':
387
        $this->buildWhere($this->where);
388
        if ($this->whereString) {
389
          $query .= ' ' . $this->whereString;
390
        }
391
        break;
392
    }
393
    if ($this->group) {
394
      $query .= ' GROUP BY ' . implode(',', $this->group);
395
    }
396
    $this->buildHaving($this->having);
397
    if ($this->havingString) {
398
      $query .= ' ' . $this->havingString;
399
    }
400
    if ($this->order) {
401
      $query .= ' ORDER BY ' . implode(',', $this->order);
402
    }
403
    if ($this->limit) {
404
      $query .= ' ' . $this->limit;
405
    }
406
    return ['query' => $query, 'params' => $this->params];
407
  }
408
409
  /**
410
   * Execute query
411
   * 
412
   * @param string|array $query
413
   * @return \Db\Mysql\Result
414
   */
415
  public function query($query = []) {
416
    if (!$query) {
417
      $this->params = [];
418
      $query = $this->buildQuery();
419
    }
420
421
    if (is_string($query)) {
422
      $query = ['query' => $query, 'params' => $this->params];
423
    }
424
425
    $prepare = $this->curInstance->pdo->prepare($query['query']);
426
    $prepare->execute($query['params']);
427
428
    $this->curInstance->lastQuery = $query;
429
    $result = new Result();
430
    $result->pdoResult = $prepare;
431
    if ($this->curInstance->dbInstance && $this->curInstance->dbInstance->curQuery && $this->curInstance->dbInstance->curQuery === $this) {
432
      $this->curInstance->dbInstance->curQuery = null;
433
    }
434
435
    return $result;
436
  }
437
438
}
439