Completed
Push — work-fleets ( 961997...006942 )
by SuperNova.WS
06:22
created

DbQuery::select()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 8
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 11
ccs 7
cts 7
cp 1
crap 1
rs 9.4285
1
<?php
2
/**
3
 * Created by Gorlum 07.08.2016 2:36
4
 */
5
6
namespace DBAL;
7
8
use \HelperArray;
9
use \db_mysql;
10
use \classSupernova;
11
12
/**
13
 * Class DbQuery
14
 *
15
 * New replacement for DbQueryConstructor
16
 * Simplified version
17
 * Chained calls - "Fluid interface"
18
 *
19
 * @package DBAL
20
 */
21
class DbQuery {
22
23
  const SELECT = 'SELECT';
24
  const REPLACE = 'REPLACE';
25
  const INSERT = 'INSERT';
26
  const INSERT_IGNORE = 'INSERT IGNORE';
27
  const UPDATE = 'UPDATE';
28
  const DELETE = 'DELETE';
29
30
  /**
31
   * @var db_mysql
32
   */
33
  protected $db;
34
35
  /**
36
   * Which command would be performed
37
   *
38
   * @var string $command
39
   */
40
  protected $command;
41
42
  protected $table = '';
43
44
  /**
45
   * Contains field names integer keyed
46
   *
47
   * For SELECT {fields} FROM
48
   * For INSERT/REPLACE {fields} UPDATE ...
49
   *
50
   * @var array $fields
51
   */
52
  protected $fields = array();
53
  protected $where = array();
54
  protected $whereDanger = array();
55
56
  /**
57
   * Contain array of values - fielded or not
58
   *
59
   * For INSERT/REPLACE ... SET, UPDATE ... SET contains fieldName => value
60
   * For INSERT/REPLACE ... VALUES contains values[][]
61
   *
62
   * @var array
63
   */
64
  protected $values = array();
65
  /**
66
   * Contain array of DANGER values for batch INSERT/REPLACE
67
   *
68
   * @var string[]
69
   */
70
  protected $valuesDanger = array();
71
  protected $adjust = array();
72
  protected $adjustDanger = array();
73
74
75
  /**
76
   * Variable for incremental query build
77
   *
78
   * @var string[] $build
79
   */
80
  protected $build = array();
81
82
  protected $isOneRow = false;
83
84
  /**
85
   * DbQuery constructor.
86
   *
87
   * @param  null|\db_mysql $db
88
   */
89
  // TODO - $db should be supplied externally
90 1
  public function __construct($db = null) {
91 1
    $this->db = empty($db) ? classSupernova::$gc->db : $db;
92 1
  }
93
94
  /**
95
   * @param null|db_mysql $db
96
   *
97
   * @return static
98
   */
99 1
  public static function build($db = null) {
100 1
    return new static($db);
101
  }
102
103
104 1
  public function select() {
105 1
    $this->build = array();
106
107 1
    $this->buildCommand(static::SELECT);
108 1
    $this->build[] = ' *';
109 1
    $this->build[] = " FROM " . $this->quoteTable($this->table);
110 1
    $this->buildWhere();
111
    $this->buildLimit();
112 1
113
    return $this->__toString();
114
  }
115 1
116 1
  public function delete() {
117
    $this->build = array();
118 1
119 1
    $this->buildCommand(static::DELETE);
120 1
    $this->buildWhere();
121 1
    $this->buildLimit();
122 1
123
    return $this->__toString();
124 1
  }
125
126
  public function update() {
127 1
    $this->build = array();
128 1
129
    $this->buildCommand(static::UPDATE);
130
    $this->buildSetFields();
131 1
    $this->buildWhere();
132 1
    $this->buildLimit();
133 1
134 1
    return $this->__toString();
135 1
  }
136 1
137 1
  /**
138 1
   * @param int $replace
139 1
   *
140 1
   * @return string
141
   */
142 1
  protected function setInsertCommand($replace) {
143 1
    switch($replace) {
144
      case DB_INSERT_IGNORE:
145 1
        $result = static::INSERT_IGNORE;
146
      break;
147
      case DB_INSERT_REPLACE:
148 1
        $result = static::REPLACE;
149 1
      break;
150
      default:
151
        $result = static::INSERT;
152 1
      break;
153 1
    }
154 1
155 1
    return $result;
156 1
  }
157 1
158 1
  public function insertSet($replace = DB_INSERT_PLAIN) {
159 1
    $this->build = array();
160 1
    $this->buildCommand($this->setInsertCommand($replace));
161 1
    $this->buildSetFields();
162
163 1
    return $this->__toString();
164 1
  }
165 1
166 1
  public function insertBatch($replace = DB_INSERT_PLAIN) {
167 1
    $this->build = array();
168
169 1
    $this->buildCommand($this->setInsertCommand($replace));
170
    $this->build[] = " (";
171
    $this->buildFieldNames();
172
    $this->build[] = ") VALUES ";
173
    $this->buildValuesVector();
174
175
    return $this->__toString();
176
  }
177
178 1
179 1
  /**
180
   * @param $table
181 1
   *
182
   * @return $this
183
   */
184
  public function setTable($table) {
185
    $this->table = $table;
186
187
    return $this;
188
  }
189 1
190 1
  /**
191
   * @param bool $oneRow - DB_RECORDS_ALL || DB_RECORD_ONE
192 1
   *
193
   * @return $this
194
   */
195
  public function setOneRow($oneRow = DB_RECORDS_ALL) {
196
    $this->isOneRow = $oneRow;
197
198
    return $this;
199
  }
200 1
201 1
  /**
202
   * @param array $values
203 1
   *
204
   * @return $this
205
   */
206
  public function setValues($values = array()) {
207
    HelperArray::merge($this->values, $values, HelperArray::MERGE_PHP);
208
209
    return $this;
210
  }
211 1
212 1
  /**
213
   * @param array $values
214 1
   *
215
   * @return $this
216
   */
217
  public function setValuesDanger($values = array()) {
218
    HelperArray::merge($this->valuesDanger, $values, HelperArray::MERGE_PHP);
219
220
    return $this;
221
  }
222 1
223 1
  /**
224
   * @param array $values
225 1
   *
226
   * @return $this
227
   */
228
  public function setAdjust($values = array()) {
229
    HelperArray::merge($this->adjust, $values, HelperArray::MERGE_PHP);
230
231
    return $this;
232
  }
233 1
234 1
  /**
235
   * @param array $values
236 1
   *
237
   * @return $this
238
   */
239
  public function setAdjustDanger($values = array()) {
240
    HelperArray::merge($this->adjustDanger, $values, HelperArray::MERGE_PHP);
241
242
    return $this;
243
  }
244 1
245 1
  /**
246
   * @param array $fields
247 1
   *
248
   * @return $this
249
   */
250
  public function setFields($fields = array()) {
251
    HelperArray::merge($this->fields, $fields, HelperArray::MERGE_PHP);
252
253
    return $this;
254
  }
255
256
  /**
257 1
   * Merges WHERE array as array_merge()
258 1
   *
259
   * @param array $whereArray
260 1
   *
261
   * @return $this
262
   */
263
  public function setWhereArray($whereArray = array()) {
264
    HelperArray::merge($this->where, $whereArray, HelperArray::MERGE_PHP);
265
266
    return $this;
267
  }
268
269
  /**
270
   * Sets DANGER array - where values should be escaped BEFORE entering DBAL
271
   *
272 1
   * Deprecated - all values should pass through DBAL
273 1
   *
274
   * @param array $whereArrayDanger
275 1
   *
276
   * @return $this
277
   */
278
  public function setWhereArrayDanger($whereArrayDanger = array()) {
279
    HelperArray::merge($this->whereDanger, $whereArrayDanger, HelperArray::MERGE_PHP);
280
281
    return $this;
282
  }
283
284
285
  /**
286 1
   * Wrapper for db_escape()
287 1
   *
288
   * @param $string
289
   *
290 1
   * @return string
291
   */
292 1
  protected function escape($string) {
293 1
    return $this->db->db_escape($string);
294 1
  }
295
296 1
  protected function escapeEmulator($value) {
297
    // Characters encoded are NUL (ASCII 0), \n, \r, \, ', ", and Control-Z.
298
    return str_replace(
299
      array("\\", "\0", "\n", "\r", "'", "\"", "\z",),
300
      array('\\\\', '\0', '\n', '\r', '\\\'', '\"', '\z',),
301
      $value
302
    );
303
  }
304
305
  /**
306 1
   * Escaping string value and quoting it
307 1
   *
308
   * @param mixed $value
309
   *
310
   * @return string
311
   */
312
  protected function stringValue($value) {
313
    return "'" . $this->escape((string)$value) . "'";
314
  }
315
316
  /**
317 1
   * Quote mysql DB identifier
318 1
   *
319
   * @param mixed $fieldName
320
   *
321 1
   * @return string
322 1
   */
323 1
  public function quote($fieldName) {
324 1
    return "`" . $this->escape((string)$fieldName) . "`";
325 1
  }
326
327
  public function makeAdjustString($fieldValue, $fieldName) {
328 1
    return is_int($fieldName)
329 1
      ? $fieldValue
330 1
      : (($fieldNameQuoted = $this->quote($fieldName)) . " = " .
331 1
        $fieldNameQuoted . " + (" . $this->castAsDbValue($fieldValue) . ")");
332
  }
333
334
  public function makeFieldEqualValue($fieldValue, $fieldName) {
335
    return is_int($fieldName)
336
      ? $fieldValue
337
      : ($this->quote($fieldName) . " = " . $this->castAsDbValue($fieldValue));
338
  }
339
340
  /**
341 1
   * Quote table name with `{{ }}`
342 1
   *
343
   * @param mixed $tableName
344
   *
345 13
   * @return string
346 13
   */
347 13
  protected function quoteTable($tableName) {
348 13
    return "`{{" . $this->escape((string)$tableName) . "}}`";
349
  }
350 4
351
  public function castAsDbValue($value) {
352 9
    switch(gettype($value)) {
353 2
      case TYPE_INTEGER:
354 2
      case TYPE_DOUBLE:
355
        // do nothing
356 7
      break;
357 1
358 1
      case TYPE_BOOLEAN:
359
        $value = $value ? 1 : 0;
360 6
      break;
361
362
      case TYPE_NULL:
363 6
        $value = 'NULL';
364 2
      break;
365
366 6
      case TYPE_EMPTY:
367 6
        // No-type defaults to string
368 6
        /** @noinspection PhpMissingBreakStatementInspection */
369 6
      case TYPE_ARRAY:
370 13
        $value = serialize($value);
371
      // Continuing with serialized array value
372 13
      case TYPE_STRING:
373
      default:
374
        $value = $this->stringValue($value);
375
      break;
376 7
    }
377 7
378 7
    return $value;
379 1
  }
380 1
381
382 6
  protected function buildCommand($command) {
383 1
    switch($this->command = $command) {
384 1 View Code Duplication
      case static::UPDATE:
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...
385
        $this->build[] = $this->command . " " . $this->quoteTable($this->table);
386 5
      break;
387 5
388 5 View Code Duplication
      case static::DELETE:
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...
389 3
        $this->build[] = $this->command . " FROM " . $this->quoteTable($this->table);
390 3
      break;
391
392 2
      case static::REPLACE:
393 1
      case static::INSERT_IGNORE:
394 1
      case static::INSERT:
395 7
        $this->build[] = $this->command . " INTO " . $this->quoteTable($this->table);
396 7
      break;
397
398
      case static::SELECT:
399 1
        $this->build[] = $this->command;
400 1
      break;
401
    }
402 1
  }
403 1
404 1
  // UPDATE and INSERT ... SET
405 1
  protected function buildSetFields() {
406 1
    $safeFields = array();
407 1
    // Sets overwritten by Adjusts
408 1
    if ($safeValuesDanger = implode(',', $this->valuesDanger)) {
409 1
      $safeFields[] = &$safeValuesDanger;
410 1
    }
411 1
    if ($safeFieldsEqualValues = implode(',', HelperArray::map($this->values, array($this, 'makeFieldEqualValue'), true))) {
412 1
      $safeFields[] = &$safeFieldsEqualValues;
413 1
    }
414 1
    if ($safeAdjustDanger = implode(',', $this->adjustDanger)) {
415
      $safeFields[] = &$safeAdjustDanger;
416 1
    }
417 1
    if ($safeAdjust = implode(',', HelperArray::map($this->adjust, array($this, 'makeAdjustString'), true))) {
418 1
      $safeFields[] = &$safeAdjust;
419 1
    }
420 1
    $safeFieldsString = implode(',', $safeFields);
421
422
    if (!empty($safeFieldsString)) {
423 1
      $this->build[] = ' SET ';
424 1
      $this->build[] = $safeFieldsString;
425 1
    }
426
  }
427
428
  // INSERT ... VALUES
429
  protected function buildFieldNames() {
430
    $this->build[] = implode(',', HelperArray::map($this->fields, array($this, 'quote')));
431 1
  }
432 1
433
  /**
434 1
   * Vector values is for batch INSERT/REPLACE
435 1
   */
436 1
  // TODO - CHECK!
437
  protected function buildValuesVector() {
438 1
    $compiled = array();
439 1
440 1
    if (!empty($this->valuesDanger)) {
441
      $compiled = $this->valuesDanger;
442 1
    }
443 1
444
    foreach ($this->values as $valuesVector) {
445
      $compiled[] = '(' . implode(',', HelperArray::map($valuesVector, array($this, 'castAsDbValue'))) . ')';
446 1
    }
447 1
448 1
    $this->build[] = implode(',', $compiled);
449 1
  }
450 1
451 1
452
  protected function buildWhere() {
453 1
    $safeWhere = implode(
454 1
      ' AND ',
455 1
      $this->whereDanger +
456 1
      HelperArray::map($this->where, array($this, 'makeFieldEqualValue'), true)
457
    );
458 1
459 1
    if (!empty($safeWhere)) {
460 1
      $this->build[] = " WHERE {$safeWhere}";
461 1
    }
462 1
  }
463
464
  protected function buildLimit() {
465 7
    if ($this->isOneRow == DB_RECORD_ONE) {
466 7
      $this->build[] = ' LIMIT 1';
467
    }
468
  }
469
470
471
  public function __toString() {
472
    return implode('', $this->build);
473
  }
474
475
}
476