Completed
Push — work-fleets ( 1c4183...d64c53 )
by SuperNova.WS
05:36
created

DbSqlStatement::stringEscape()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
eloc 5
c 2
b 0
f 0
nc 2
nop 1
dl 0
loc 6
ccs 0
cts 4
cp 0
crap 6
rs 9.4285
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
class DbSqlStatement {
9
10
  const SELECT = 'SELECT';
11
12
  protected static $allowedOperations = array(
13
    self::SELECT,
14
  );
15
16
  /**
17
   * @var db_mysql $db
18
   */
19
  protected $db;
20
21
  public $operation = '';
22
23
  public $table = '';
24
  public $alias = '';
25
26
  public $idField = '';
27
28
  /**
29
   * @var array
30
   */
31
  public $fields = array();
32
33
  public $where = array();
34
  public $group = array();
35
  public $order = array();
36
  /**
37
   * @var array
38
   *  [0] - row_count
39
   *  [1] - offset
40
   *    Used {LIMIT row_count [OFFSET offset]} syntax
41
   */
42
  // TODO - separate offset and row_count
43
  public $limit = array();
44
45
  public $fetchOne = false;
46
  public $forUpdate = false;
47
48
  /**
49
   * @param db_mysql|null $db
50
   * @param string        $className
51
   *
52
   * @return DbSqlStatement
53
   */
54 1
  public static function build($db = null, $className = '') {
55 1
    $result = new self($db);
56 1
    if (!empty($className) && is_string($className)) {
57 1
      $result->getParamsFromStaticClass($className);
58 1
    }
59
60 1
    return $result;
61
  }
62
63
  /**
64
   * DbSqlStatement constructor.
65
   *
66
   * @param db_mysql|null $db
67
   */
68 3
  public function __construct($db = null) {
69 3
    $this->db = (!empty($db) && $db instanceof db_mysql) || !class_exists('classSupernova', false) ? $db : classSupernova::$db;
70 3
  }
71
72
  /**
73
   * Resets statement
74
   *
75
   * @param bool $full
76
   *
77
   * @return $this
78
   */
79
  // TODO - UNITTEST
80 1
  protected function _reset($full = true) {
81 1
    if ($full) {
82 1
      $this->operation = '';
83 1
      $this->table = '';
84 1
      $this->alias = '';
85 1
      $this->idField = '';
86 1
    }
87
88 1
    $this->fields = array();
89 1
    $this->where = array();
90 1
    $this->group = array();
91 1
    $this->order = array();
92 1
    $this->limit = array();
93 1
    $this->fetchOne = false;
94
95 1
    return $this;
96
  }
97
98
  /**
99
   * @param string $fieldName
100
   *
101
   * @return $this
102
   */
103 1
  public function setIdField($fieldName) {
104 1
    $this->idField = $fieldName;
105
106 1
    return $this;
107
  }
108
109
  /**
110
   * @param string $alias
111
   *
112
   * @return $this
113
   */
114 1
  public function fromAlias($alias) {
115 1
    $this->alias = $alias;
116
117 1
    return $this;
118
  }
119
120
  /**
121
   * @param string $tableName
122
   * @param string $alias
123
   *
124
   * @return $this
125
   */
126 1
  public function from($tableName, $alias = '') {
127 1
    $this->table = $tableName;
128 1
    $this->fromAlias($alias);
129
130 1
    return $this;
131
  }
132
133
  /**
134
   * @param string $params
135
   *
136
   * @return $this
137
   */
138 2
  public function getParamsFromStaticClass($params) {
139 2
    if (is_string($params) && $params && class_exists($params)) {
140 2
      $this->from($params::$_table);
141 2
      $this->setIdField($params::$_idField);
142 2
    }
143
144 2
    return $this;
145
  }
146
147
148
  /**
149
   * @return self
150
   */
151 2
  public function select() {
152 2
    $this->_reset(false);
153 2
    $this->operation = DbSqlStatement::SELECT;
154 2
    $this->fields = array('*');
155
156 2
    return $this;
157
  }
158
159
  /**
160
   * @param mixed|array $fields
161
   *
162
   * @return $this
163
   */
164 1
  public function fields($fields = array()) {
165 1
    $this->fields = $fields;
0 ignored issues
show
Documentation Bug introduced by
It seems like $fields of type * is incompatible with the declared type array of property $fields.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
166
167 1
    return $this;
168
  }
169
170
  /**
171
   * @param array $where
172
   * @param bool  $replace
173
   *
174
   * @return $this
175
   * @throws ExceptionDbSqlWhereNotAnArray
176
   */
177
  // TODO - fields should be escaped !!
178
  // TODO - $where should be validated and checked!
179 1
  public function where($where = array(), $replace = true) {
180 1
    if (!is_array($where)) {
181
      throw new ExceptionDbSqlWhereNotAnArray();
182
    }
183
184 1
    if ($replace) {
185 1
      $this->where = $where;
186 1
    } else {
187
      $this->where = array_merge($this->where, $where);
188
    }
189
190 1
    return $this;
191
  }
192
193
  /**
194
   * @param array $order
195
   *
196
   * @return $this
197
   * @throws ExceptionDbSqlWhereNotAnArray
198
   */
199
  // TODO - fields should be escaped !!
200
  // TODO - $where should be validated and checked!
201
  public function order($order = array()) {
202
    if (!is_array($order)) {
203
      // TODO - separate exception
204
      throw new ExceptionDbSqlWhereNotAnArray();
205
    }
206
    $this->order = $order;
207
208
    return $this;
209
  }
210
211
  /**
212
   * @return $this
213
   */
214
  public function fetchOne() {
215
    $this->fetchOne = true;
216
    $this->limit[0] = 1;
217
218
    return $this;
219
  }
220
221
  /**
222
   * @return $this
223
   */
224
  public function forUpdate($forUpdate = true) {
225
    $this->forUpdate = $forUpdate;
226
227
    return $this;
228
  }
229
230
  /**
231
   * @return string
232
   * @throws ExceptionDbOperationEmpty
233
   * @throws ExceptionDbOperationRestricted
234
   */
235 2
  public function __toString() {
236 2
    if (empty($this->operation)) {
237 1
      throw new ExceptionDbOperationEmpty();
238
    }
239
240 1
    if (!in_array($this->operation, self::$allowedOperations)) {
241 1
      throw new ExceptionDbOperationRestricted();
242
    }
243
244
    $result = '';
245
    $result .= $this->stringEscape($this->operation);
246
247
    $result .= ' ' . $this->selectFieldsToString($this->fields);
248
249
    $result .= ' FROM';
250
    $result .= ' `{{' . $this->stringEscape($this->table) . '}}`';
251
    $result .= !empty($this->alias) ? ' AS `' . $this->stringEscape($this->alias) . '`' : '';
252
253
    // TODO - fields should be escaped !!
254
    $result .= !empty($this->where) ? ' WHERE ' . implode(' AND ', $this->where) : '';
255
256
    // TODO - fields should be escaped !!
257
    $result .= !empty($this->group) ? ' GROUP BY ' . implode(',', $this->group) : '';
258
259
    // TODO - fields should be escaped !!
260
    $result .= !empty($this->order) ? ' ORDER BY ' . implode(',', $this->order) : '';
261
262
    // TODO - fields should be escaped !!
263
    // TODO - separate offset and row_count
264
    $result .= !empty($this->limit) ? ' LIMIT ' . implode(' OFFSET ', $this->limit) : '';
265
266
    $result .= $this->forUpdate ? ' FOR UPDATE' : '';
267
268
    // TODO - protect from double escape!
269
270
    return $result;
271
  }
272
273
  /**
274
   * @param array|mixed $fields
275
   *
276
   * @return string
277
   * @throws ExceptionDBFieldEmpty
278
   */
279 16
  protected function selectFieldsToString($fields) {
280 16
    $fields = HelperArray::makeArray($fields);
281
282 16
    $result = array();
283 16
    foreach ($fields as $fieldName) {
284 15
      $string = $this->processField($fieldName);
285 15
      if ($string !== '') {
286 13
        $result[] = $string;
287 13
      }
288 16
    }
289
290 16
    if (empty($result)) {
291 3
      throw new ExceptionDBFieldEmpty();
292
    }
293
294 13
    return implode(',', $result);
295
  }
296
297
  /**
298
   * @param mixed $fieldName
299
   *
300
   * @return string
301
   */
302 13
  protected function processField($fieldName) {
303 13
    if (is_bool($fieldName)) {
304 4
      $result = (string)intval($fieldName);
305 13
    } elseif (is_null($fieldName)) {
306 2
      $result = 'NULL';
307 11
    } elseif ($fieldName === '*') {
308 2
      $result = '*';
309 2
    } else {
310 9
      $result = $this->processFieldDefault($fieldName);
311
    }
312
313 13
    return $result;
314
  }
315
316
  /**
317
   * @param mixed $fieldName
318
   *
319
   * @return string
320
   */
321 9
  protected function processFieldDefault($fieldName) {
322 9
    $result = (string)$fieldName;
323
    if (
324
      $result != ''
325 9
      &&
326
      // Literals plays as they are - they do properly format by itself
327 8
      !($fieldName instanceof DbSqlLiteral)
328 9
      &&
329
      // Numeric need no escaping
330 7
      !is_numeric($fieldName)
331 9
    ) {
332
      // Other should be formatted
333 3
      $result = '`' . $this->stringEscape($result) . '`';
334 3
    }
335
336 9
    return $result;
337
  }
338
339
  /**
340
   * @param $string
341
   *
342
   * @return mixed|string
343
   */
344
  protected function stringEscape($string) {
345
    return
346
      method_exists($this->db, 'db_escape')
347
        ? $this->db->db_escape($string)
348
        : str_replace('`', '\`', addslashes($string));
349
  }
350
351
}
352