Completed
Push — work-fleets ( 006942...3604bd )
by SuperNova.WS
06:54
created

DbQuery::insert()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 11
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 18
rs 9.2
ccs 11
cts 11
cp 1
crap 4
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 1
    $this->buildLimit();
112
113 1
    return $this->__toString();
114
  }
115
116 1
  public function delete() {
117 1
    $this->build = array();
118
119 1
    $this->buildCommand(static::DELETE);
120 1
    $this->buildWhere();
121 1
    $this->buildLimit();
122
123 1
    return $this->__toString();
124
  }
125
126 1
  public function update() {
127 1
    $this->build = array();
128
129 1
    $this->buildCommand(static::UPDATE);
130 1
    $this->buildSetFields();
131 1
    $this->buildWhere();
132 1
    $this->buildLimit();
133
134 1
    return $this->__toString();
135
  }
136
137
  /**
138
   * @param int $replace
139
   *
140
   * @return string
141
   */
142 2
  protected function setInsertCommand($replace) {
143
    switch($replace) {
144 2
      case DB_INSERT_IGNORE:
145 2
        $result = static::INSERT_IGNORE;
146 2
      break;
147 2
      case DB_INSERT_REPLACE:
148 2
        $result = static::REPLACE;
149 2
      break;
150 2
      default:
151 2
        $result = static::INSERT;
152 2
      break;
153 2
    }
154
155 2
    return $result;
156
  }
157
158
159 2
  public function insert($replace = DB_INSERT_PLAIN, $forceSingleInsert = false) {
160 2
    $this->build = array();
161 2
    $this->buildCommand($this->setInsertCommand($replace));
162
163 2
    if(!$forceSingleInsert && is_array($this->fields) && !empty($this->fields)) {
164
      // If there are fields - it's batch insert... unless it forced single insert
165 1
      $this->build[] = " (";
166 1
      $this->buildFieldNames(); // used $this->fields
167 1
      $this->build[] = ") VALUES ";
168 1
      $this->buildValuesVector(); // $this->valuesDanger + $this->values
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% 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...
169 1
    } else {
170
      // Otherwise - it's single field insert
171 1
      $this->buildSetFields();
172
    }
173
174
175 2
    return $this->__toString();
176
  }
177
178
179
  /**
180
   * @param $table
181
   *
182
   * @return $this
183
   */
184 1
  public function setTable($table) {
185 1
    $this->table = $table;
186
187 1
    return $this;
188
  }
189
190
  /**
191
   * @param bool $oneRow - DB_RECORDS_ALL || DB_RECORD_ONE
192
   *
193
   * @return $this
194
   */
195 1
  public function setOneRow($oneRow = DB_RECORDS_ALL) {
196 1
    $this->isOneRow = $oneRow;
197
198 1
    return $this;
199
  }
200
201
  /**
202
   * @param array|array[] $values
203
   *
204
   * @return $this
205
   */
206 1
  public function setValues($values = array()) {
207 1
    HelperArray::merge($this->values, $values, HelperArray::MERGE_PHP);
208
209 1
    return $this;
210
  }
211
212
  /**
213
   * @param array $values
214
   *
215
   * @return $this
216
   */
217 1
  public function setValuesDanger($values = array()) {
218 1
    HelperArray::merge($this->valuesDanger, $values, HelperArray::MERGE_PHP);
219
220 1
    return $this;
221
  }
222
223
  /**
224
   * @param array $values
225
   *
226
   * @return $this
227
   */
228 1
  public function setAdjust($values = array()) {
229 1
    HelperArray::merge($this->adjust, $values, HelperArray::MERGE_PHP);
230
231 1
    return $this;
232
  }
233
234
  /**
235
   * @param array $values
236
   *
237
   * @return $this
238
   */
239 1
  public function setAdjustDanger($values = array()) {
240 1
    HelperArray::merge($this->adjustDanger, $values, HelperArray::MERGE_PHP);
241
242 1
    return $this;
243
  }
244
245
  /**
246
   * @param array $fields
247
   *
248
   * @return $this
249
   */
250 1
  public function setFields($fields = array()) {
251 1
    HelperArray::merge($this->fields, $fields, HelperArray::MERGE_PHP);
252
253 1
    return $this;
254
  }
255
256
  /**
257
   * Merges WHERE array as array_merge()
258
   *
259
   * @param array $whereArray
260
   *
261
   * @return $this
262
   */
263 1
  public function setWhereArray($whereArray = array()) {
264 1
    HelperArray::merge($this->where, $whereArray, HelperArray::MERGE_PHP);
265
266 1
    return $this;
267
  }
268
269
  /**
270
   * Sets DANGER array - where values should be escaped BEFORE entering DBAL
271
   *
272
   * Deprecated - all values should pass through DBAL
273
   *
274
   * @param array $whereArrayDanger
275
   *
276
   * @return $this
277
   */
278 1
  public function setWhereArrayDanger($whereArrayDanger = array()) {
279 1
    HelperArray::merge($this->whereDanger, $whereArrayDanger, HelperArray::MERGE_PHP);
280
281 1
    return $this;
282
  }
283
284
285
  /**
286
   * Wrapper for db_escape()
287
   *
288
   * @param $string
289
   *
290
   * @return string
291
   */
292 1
  protected function escape($string) {
293 1
    return $this->db->db_escape($string);
294
  }
295
296 1
  protected function escapeEmulator($value) {
297
    // Characters encoded are NUL (ASCII 0), \n, \r, \, ', ", and Control-Z.
298 1
    return str_replace(
299 1
      array("\\", "\0", "\n", "\r", "'", "\"", "\z",),
300 1
      array('\\\\', '\0', '\n', '\r', '\\\'', '\"', '\z',),
301
      $value
302 1
    );
303
  }
304
305
  /**
306
   * Escaping string value and quoting it
307
   *
308
   * @param mixed $value
309
   *
310
   * @return string
311
   */
312 1
  protected function stringValue($value) {
313 1
    return "'" . $this->escape((string)$value) . "'";
314
  }
315
316
  /**
317
   * Quote mysql DB identifier
318
   *
319
   * @param mixed $fieldName
320
   *
321
   * @return string
322
   */
323 1
  public function quote($fieldName) {
324 1
    return "`" . $this->escape((string)$fieldName) . "`";
325
  }
326
327 1
  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 1
  public function makeFieldEqualValue($fieldValue, $fieldName) {
335 1
    return is_int($fieldName)
336 1
      ? $fieldValue
337 1
      : ($this->quote($fieldName) . " = " . $this->castAsDbValue($fieldValue));
338
  }
339
340
  /**
341
   * Quote table name with `{{ }}`
342
   *
343
   * @param mixed $tableName
344
   *
345
   * @return string
346
   */
347 1
  protected function quoteTable($tableName) {
348 1
    return "`{{" . $this->escape((string)$tableName) . "}}`";
349
  }
350
351 13
  public function castAsDbValue($value) {
352 13
    switch(gettype($value)) {
353 13
      case TYPE_INTEGER:
354 13
      case TYPE_DOUBLE:
355
        // do nothing
356 4
      break;
357
358 9
      case TYPE_BOOLEAN:
359 2
        $value = $value ? 1 : 0;
360 2
      break;
361
362 7
      case TYPE_NULL:
363 1
        $value = 'NULL';
364 1
      break;
365
366 6
      case TYPE_EMPTY:
367
        // No-type defaults to string
368
        /** @noinspection PhpMissingBreakStatementInspection */
369 6
      case TYPE_ARRAY:
370 2
        $value = serialize($value);
371
      // Continuing with serialized array value
372 6
      case TYPE_STRING:
373 6
      default:
374 6
        $value = $this->stringValue($value);
375 6
      break;
376 13
    }
377
378 13
    return $value;
379
  }
380
381
382 7
  protected function buildCommand($command) {
383 7
    switch($this->command = $command) {
384 7 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 1
        $this->build[] = $this->command . " " . $this->quoteTable($this->table);
386 1
      break;
387
388 6 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 1
        $this->build[] = $this->command . " FROM " . $this->quoteTable($this->table);
390 1
      break;
391
392 5
      case static::REPLACE:
393 5
      case static::INSERT_IGNORE:
394 5
      case static::INSERT:
395 3
        $this->build[] = $this->command . " INTO " . $this->quoteTable($this->table);
396 3
      break;
397
398 2
      case static::SELECT:
399 1
        $this->build[] = $this->command;
400 1
      break;
401 7
    }
402 7
  }
403
404
  // UPDATE and INSERT ... SET
405 1
  protected function buildSetFields() {
406 1
    $safeFields = array();
407
    // 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 1
      $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 1
    if (!empty($safeFieldsString)) {
423 1
      $this->build[] = ' SET ';
424 1
      $this->build[] = $safeFieldsString;
425 1
    }
426 1
  }
427
428
  // INSERT ... VALUES
429 1
  protected function buildFieldNames() {
430 1
    $this->build[] = implode(',', HelperArray::map($this->fields, array($this, 'quote')));
431 1
  }
432
433
  /**
434
   * Vector values is for batch INSERT/REPLACE
435
   */
436
  // TODO - CHECK!
437 1
  protected function buildValuesVector() {
438 1
    $compiled = array();
439
440 1
    if (!empty($this->valuesDanger)) {
441 1
      $compiled = $this->valuesDanger;
442 1
    }
443
444 1
    foreach ($this->values as $valuesVector) {
445 1
      $compiled[] = '(' . implode(',', HelperArray::map($valuesVector, array($this, 'castAsDbValue'))) . ')';
446 1
    }
447
448 1
    $this->build[] = implode(',', $compiled);
449 1
  }
450
451
452 1
  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 1
    );
458
459 1
    if (!empty($safeWhere)) {
460 1
      $this->build[] = " WHERE {$safeWhere}";
461 1
    }
462 1
  }
463
464 1
  protected function buildLimit() {
465 1
    if ($this->isOneRow == DB_RECORD_ONE) {
466 1
      $this->build[] = ' LIMIT 1';
467 1
    }
468 1
  }
469
470
471 7
  public function __toString() {
472 7
    return implode('', $this->build);
473
  }
474
475
}
476