Completed
Push — work-fleets ( d64c53...5442ac )
by SuperNova.WS
05:10
created

DbSqlStatement::__construct()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 2
nc 6
nop 1
dl 0
loc 3
rs 9.2
c 1
b 0
f 0
ccs 3
cts 3
cp 1
crap 4
1
<?php
2
3
//pdump(DBStaticUser::getMaxId());
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% 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...
4
//pdump(DBStaticUser::getRecordById(67));
5
//pdump(DBStaticUser::filterIdListStringRepack('2,3,5,67'));
6
7
8
/**
9
 * Class DbSqlStatement
10
 *
11
 * @method static DbSqlStatement where(array $value, int $mergeStrategy = HelperArray::ARRAY_REPLACE)
12
 * @method static DbSqlStatement fields(array $value, int $mergeStrategy = HelperArray::ARRAY_REPLACE)
13
 * @method static DbSqlStatement group(array $value, int $mergeStrategy = HelperArray::ARRAY_REPLACE)
14
 * @method static DbSqlStatement order(array $value, int $mergeStrategy = HelperArray::ARRAY_REPLACE)
15
 * @method static DbSqlStatement having(array $value, int $mergeStrategy = HelperArray::ARRAY_REPLACE)
16
 *
17
 */
18
class DbSqlStatement {
19
20
  const SELECT = 'SELECT';
21
22
  protected static $allowedOperations = array(
23
    self::SELECT,
24
  );
25
26
  /**
27
   * @var db_mysql $db
28
   */
29
  protected $db;
30
31
  public $operation = '';
32
33
  public $table = '';
34
  public $alias = '';
35
36
  public $idField = '';
37
38
  /**
39
   * @var array
40
   */
41
  public $fields = array();
42
43
  public $where = array();
44
  public $group = array();
45
  public $order = array();
46
47
  public $having = array();
48
49
50
  /**
51
   * @var array
52
   *  [0] - row_count
53
   *  [1] - offset
54 1
   *    Used {LIMIT row_count [OFFSET offset]} syntax
55 1
   */
56 1
  // TODO - separate offset and row_count
57 1
  public $limit = 0;
58 1
  public $offset = 0;
59
60 1
  public $fetchOne = false;
61
  public $forUpdate = false;
62
  public $skipLock = false;
63
64
  /**
65
   * @param db_mysql|null $db
66
   * @param string        $className
67
   *
68 3
   * @return DbSqlStatement
69 3
   */
70 3
  public static function build($db = null, $className = '') {
71
    $result = new self($db);
72
    if (!empty($className) && is_string($className)) {
73
      $result->getParamsFromStaticClass($className);
74
    }
75
76
    return $result;
77
  }
78
79
  /**
80 1
   * DbSqlStatement constructor.
81 1
   *
82 1
   * @param db_mysql|null $db
83 1
   */
84 1
  public function __construct($db = null) {
85 1
    $this->db = (!empty($db) && $db instanceof db_mysql) || !class_exists('classSupernova', false) ? $db : classSupernova::$db;
86 1
  }
87
88 1
  /**
89 1
   * Resets statement
90 1
   *
91 1
   * @param bool $full
92 1
   *
93 1
   * @return $this
94
   */
95 1
  // TODO - UNITTEST
96
  protected function _reset($full = true) {
97
    if ($full) {
98
      $this->operation = '';
99
      $this->table = '';
100
      $this->alias = '';
101
      $this->idField = '';
102
    }
103 1
104 1
    $this->fields = array();
105
    $this->where = array();
106 1
    $this->group = array();
107
    $this->order = array();
108
    $this->having = array();
109
110
    $this->limit = 0;
111
    $this->offset = 0;
112
113
    $this->fetchOne = false;
114 1
    $this->forUpdate = false;
115 1
    $this->skipLock = false;
116
117 1
    return $this;
118
  }
119
120
  /**
121
   * @param string $fieldName
122
   *
123
   * @return $this
124
   */
125
  public function setIdField($fieldName) {
126 1
    $this->idField = $fieldName;
127 1
128 1
    return $this;
129
  }
130 1
131
  /**
132
   * @param string $alias
133
   *
134
   * @return $this
135
   */
136
  public function fromAlias($alias) {
137
    $this->alias = $alias;
138 2
139 2
    return $this;
140 2
  }
141 2
142 2
  /**
143
   * @param int $limit
144 2
   *
145
   * @return $this
146
   */
147
  public function limit($limit) {
148
    $this->limit = $limit;
149
150
    return $this;
151 2
  }
152 2
153 2
  /**
154 2
   * @param int $offset
155
   *
156 2
   * @return $this
157
   */
158
  public function offset($offset) {
159
    $this->offset = $offset;
160
161
    return $this;
162
  }
163
164 1
165 1
  /**
166
   * @param string $tableName
167 1
   * @param string $alias
168
   *
169
   * @return $this
170
   */
171
  public function from($tableName, $alias = '') {
172
    $this->table = $tableName;
173
    $this->fromAlias($alias);
174
175
    return $this;
176
  }
177
178
  /**
179 1
   * @param string $params
180 1
   *
181
   * @return $this
182
   */
183
  public function getParamsFromStaticClass($params) {
184 1
    if (is_string($params) && $params && class_exists($params)) {
185 1
      $this->from($params::$_table);
186 1
      $this->setIdField($params::$_idField);
187
    }
188
189
    return $this;
190 1
  }
191
192
193
  /**
194
   * @return self
195
   */
196
  public function select() {
197
    $this->operation = DbSqlStatement::SELECT;
198
    if (empty($this->fields)) {
199
      $this->fields = array('*');
200
    }
201
202
    return $this;
203
  }
204
205
  public function __call($name, $arguments) {
206
    // TODO: Implement __call() method.
207
    if (in_array($name, array('fields', 'where', 'group', 'order', 'having'))) {
208
      array_unshift($arguments, '');
209
      $arguments[0] = &$this->$name;
210
      call_user_func_array('HelperArray::merge', $arguments);
211
    }
212
213
    return $this;
214
  }
215
216
  /**
217
   * Make statement fetch only one record
218
   *
219
   * @return $this
220
   */
221
  public function fetchOne($fetchOne = true) {
222
    $this->fetchOne = $fetchOne;
223
224
    return $this;
225
  }
226
227
  /**
228
   * @return $this
229
   */
230
  public function forUpdate($forUpdate = true) {
231
    $this->forUpdate = $forUpdate;
232
233
    return $this;
234
  }
235 2
236 2
  /**
237 1
   * @return $this
238
   */
239
  public function skipLock($skipLock = true) {
240 1
    $this->skipLock = $skipLock;
241 1
242
    return $this;
243
  }
244
245
246
  /**
247
   * @return string
248
   * @throws ExceptionDbOperationEmpty
249
   * @throws ExceptionDbOperationRestricted
250
   */
251
  public function __toString() {
252
    if (empty($this->operation)) {
253
      throw new ExceptionDbOperationEmpty();
254
    }
255
256
    if (!in_array($this->operation, self::$allowedOperations)) {
257
      throw new ExceptionDbOperationRestricted();
258
    }
259
260
    $result = '';
261
    $result .= $this->stringEscape($this->operation);
262
263
    $result .= ' ' . $this->selectFieldsToString($this->fields);
264
265
    $result .= ' FROM';
266
    $result .= ' `{{' . $this->stringEscape($this->table) . '}}`';
267
    $result .= !empty($this->alias) ? ' AS `' . $this->stringEscape($this->alias) . '`' : '';
268
269
    // TODO - fields should be escaped !!
270
    $result .= !empty($this->where) ? ' WHERE ' . implode(' AND ', $this->where) : '';
271
272
    // TODO - fields should be escaped !!
273
    $result .= !empty($this->group) ? ' GROUP BY ' . implode(',', $this->group) : '';
274
275
    // TODO - fields should be escaped !!
276
    $result .= !empty($this->order) ? ' ORDER BY ' . implode(',', $this->order) : '';
277
278
    // TODO - fields should be escaped !!
279 16
    $result .= !empty($this->having) ? ' HAVING ' . implode(' AND ', $this->having) : '';
280 16
281
    // TODO - fields should be escaped !!
282 16
    $limit = $this->fetchOne ? 1 : $this->limit;
283 16
    $result .= !empty($limit)
284 15
      ? ' LIMIT ' . $limit . (!empty($this->offset) ? ' OFFSET ' . $this->offset : '')
285 15
      : '';
286 13
287 13
    $result .=
288 16
      // forUpdate flag forces select with row locking - didn't look at skipLock flag
289
      $this->forUpdate
290 16
      ||
291 3
      // Also row locked when transaction is up and skipLock flag is not set
292
      (classSupernova::db_transaction_check(false) && !$this->skipLock) ? ' FOR UPDATE' : '';
293
294 13
    // TODO - protect from double escape!
295
296
    return $result;
297
  }
298
299
  /**
300
   * @param array|mixed $fields
301
   *
302 13
   * @return string
303 13
   * @throws ExceptionDBFieldEmpty
304 4
   */
305 13
  protected function selectFieldsToString($fields) {
306 2
    HelperArray::makeArrayRef($fields);
307 11
308 2
    $result = array();
309 2
    foreach ($fields as $fieldName) {
310 9
      $string = $this->processField($fieldName);
311
      if ($string !== '') {
312
        $result[] = $string;
313 13
      }
314
    }
315
316
    if (empty($result)) {
317
      throw new ExceptionDBFieldEmpty();
318
    }
319
320
    return implode(',', $result);
321 9
  }
322 9
323
  /**
324
   * @param mixed $fieldName
325 9
   *
326
   * @return string
327 8
   */
328 9
  protected function processField($fieldName) {
329
    if (is_bool($fieldName)) {
330 7
      $result = (string)intval($fieldName);
331 9
    } elseif (is_null($fieldName)) {
332
      $result = 'NULL';
333 3
    } elseif ($fieldName === '*') {
334 3
      $result = '*';
335
    } else {
336 9
      $result = $this->processFieldDefault($fieldName);
337
    }
338
339
    return $result;
340
  }
341
342
  /**
343
   * @param mixed $fieldName
344
   *
345
   * @return string
346
   */
347
  protected function processFieldDefault($fieldName) {
348
    $result = (string)$fieldName;
349
    if (
350
      $result != ''
351
      &&
352
      // Literals plays as they are - they do properly format by itself
353
      !($fieldName instanceof DbSqlLiteral)
354
      &&
355
      // Numeric need no escaping
356
      !is_numeric($fieldName)
357
    ) {
358
      // Other should be formatted
359
      $result = '`' . $this->stringEscape($result) . '`';
360
    }
361
362
    return $result;
363
  }
364
365
  /**
366
   * @param $string
367
   *
368
   * @return mixed|string
369
   */
370
  protected function stringEscape($string) {
371
    return
372
      method_exists($this->db, 'db_escape')
373
        ? $this->db->db_escape($string)
374
        : str_replace('`', '\`', addslashes($string));
375
  }
376
377
}
378