Test Failed
Push — master ( b6dff7...455f41 )
by Gabriel
12:43 queued 11s
created

AbstractQuery::hasPart()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 13.125

Importance

Changes 0
Metric Value
dl 0
loc 17
c 0
b 0
f 0
rs 8.8333
ccs 3
cts 6
cp 0.5
cc 7
nc 5
nop 1
crap 13.125
1
<?php
2
3
namespace Nip\Database\Query;
4
5
use Nip\Database\Connections\Connection;
6
use Nip\Database\Query\Condition\Condition;
7
use Nip\Database\Result;
8
9
/**
10
 * Class AbstractQuery
11
 * @package Nip\Database\Query
12
 *
13
 * @method $this setCols() setCols(array | string $cols = null)
14
 * @method $this setWhere() setWhere(array | string $cols = null)
15
 *
16
 * @method $this cols() cols(array | string $cols)
17
 * @method $this count() count(string $col, string $alias = null)
18
 * @method $this sum() sum(array | string $cols)
19
 * @method $this from() from(array | string $from)
20
 * @method $this data() data(array $data)
21
 * @method $this table() table(array | string $table)
22
 * @method $this order() order(array | string $order)\
23
 * @method $this group() group(array | string $group, $rollup = false)\
24
 */
25
abstract class AbstractQuery
26
{
27
28
    /**
29
     * @var Connection
30
     */
31
    protected $db;
32
33
    protected $parts = [
34
        'where' => null,
35
    ];
36
37
    protected $string = null;
38
39
    /**
40
     * @param Connection $manager
41
     * @return $this
42
     */
43 23
    public function setManager(Connection $manager)
44
    {
45 23
        $this->db = $manager;
46
47 23
        return $this;
48
    }
49
50
    /**
51
     * @param $name
52
     * @param $arguments
53
     * @return $this
54
     */
55 13
    public function __call($name, $arguments)
56
    {
57 13
        if (strpos($name, 'set') === 0) {
58 1
            $name = str_replace('set', '', $name);
59 1
            $name[0] = strtolower($name[0]);
60 1
            $this->initPart($name);
61
        }
62
63 13
        foreach ($arguments as $argument) {
64 13
            $this->addPart($name, $argument);
65
        }
66
67 13
        return $this;
68
    }
69
70
    /**
71
     * @param $name
72
     * @return $this
73
     */
74 13
    protected function initPart($name)
75
    {
76 13
        $this->isGenerated(false);
77 13
        $this->parts[$name] = [];
78
79 13
        return $this;
80
    }
81
82
    /**
83
     * @param boolean $generated
84
     * @return bool
85
     */
86 13
    public function isGenerated($generated = null)
87
    {
88 13
        if ($generated === false) {
89 13
            $this->string = null;
90
        }
91
92 13
        return $this->string !== null;
93
    }
94
95
    /**
96
     * @param $name
97
     * @param $value
98
     * @return $this
99
     */
100 13
    protected function addPart($name, $value)
101
    {
102 13
        if (!isset($this->parts[$name])) {
103 13
            $this->initPart($name);
104
        }
105
106 13
        $this->isGenerated(false);
107 13
        $this->parts[$name][] = $value;
108
109 13
        return $this;
110
    }
111
112
    /**
113
     * @param $params
114
     */
115
    public function addParams($params)
116
    {
117
        $this->checkParamSelect($params);
118
        $this->checkParamFrom($params);
119
        $this->checkParamWhere($params);
120
        $this->checkParamOrder($params);
121
        $this->checkParamGroup($params);
122
        $this->checkParamHaving($params);
123
        $this->checkParamLimit($params);
124
    }
125
126
    /**
127
     * @param $params
128
     */
129
    protected function checkParamSelect($params)
130
    {
131 View Code Duplication
        if (isset($params['select']) && is_array($params['select'])) {
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...
132
            call_user_func_array([$this, 'cols'], $params['select']);
133
        }
134
    }
135
136
    /**
137
     * @param $params
138
     */
139
    protected function checkParamFrom($params)
140
    {
141
        if (isset($params['from']) && !empty($params['from'])) {
142
            $this->from($params['from']);
0 ignored issues
show
Unused Code introduced by
The call to AbstractQuery::from() has too many arguments starting with $params['from'].

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
143
        }
144
    }
145
146
    /**
147
     * @param $params
148
     */
149
    protected function checkParamWhere($params)
150
    {
151
        if (isset($params['where']) && is_array($params['where'])) {
152
            foreach ($params['where'] as $condition) {
153
                $condition = (array)$condition;
154
                $this->where(
155
                    $condition[0],
156
                    isset($condition[1]) ? $condition[1] : null
157
                );
158
            }
159
        }
160
    }
161
162
    /**
163
     * @param $string
164
     * @param array $values
165
     * @return $this
166
     */
167 6 View Code Duplication
    public function where($string, $values = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
168
    {
169
        /** @var Condition $this ->_parts[] */
170 6
        if ($string) {
171 6
            if (isset($this->parts['where']) && $this->parts['where'] instanceof Condition) {
172 2
                $this->parts['where'] = $this->parts['where']->and_($this->getCondition($string, $values));
173
            } else {
174 6
                $this->parts['where'] = $this->getCondition($string, $values);
175
            }
176
        }
177
178 6
        return $this;
179
    }
180
181
    /**
182
     * @param string $string
183
     * @param array $values
184
     *
185
     * @return Condition
186 13
     */
187
    public function getCondition($string, $values = [])
188 13
    {
189 13
        if (!is_object($string)) {
190 13
            $condition = new Condition($string, $values);
191
            $condition->setQuery($this);
192
        } else {
193
            $condition = $string;
194
        }
195 13
196
        return $condition;
197
    }
198
199
    /**
200
     * @param $params
201
     */
202
    protected function checkParamOrder($params)
203
    {
204 View Code Duplication
        if (isset($params['order']) && !empty($params['order'])) {
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...
205
            call_user_func_array([$this, 'order'], $params['order']);
206
        }
207
    }
208
209
    /**
210
     * @param $params
211
     */
212
    protected function checkParamGroup($params)
213
    {
214 View Code Duplication
        if (isset($params['group']) && !empty($params['group'])) {
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...
215
            call_user_func_array([$this, 'group'], [$params['group']]);
216
        }
217
    }
218
219
    /**
220
     * @param $params
221
     */
222
    protected function checkParamHaving($params)
223
    {
224 View Code Duplication
        if (isset($params['having']) && !empty($params['having'])) {
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...
225
            call_user_func_array([$this, 'having'], [$params['having']]);
226
        }
227
    }
228
229
    /**
230
     * @param $params
231
     */
232
    protected function checkParamLimit($params)
233
    {
234 View Code Duplication
        if (isset($params['limit']) && !empty($params['limit'])) {
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...
235
            call_user_func_array([$this, 'limit'], [$params['limit']]);
236
        }
237
    }
238
239
    /**
240
     * @param integer $start
241
     * @param bool $offset
242
     * @return $this
243 2
     */
244
    public function limit($start, $offset = false)
245 2
    {
246 2
        $this->parts['limit'] = $start;
247 1
        if ($offset) {
248
            $this->parts['limit'] .= ','.$offset;
249
        }
250 2
251
        return $this;
252
    }
253
254
    /**
255
     * @param $string
256
     * @param array $values
257
     *
258 1
     * @return $this
259
     */
260 1 View Code Duplication
    public function orWhere($string, $values = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
261 1
    {
262 1
        if ($string) {
263
            if ($this->parts['where'] instanceof Condition) {
264
                $this->parts['where'] = $this->parts['where']->or_($this->getCondition($string, $values));
265
            } else {
266
                $this->parts['where'] = $this->getCondition($string, $values);
267
            }
268 1
        }
269
270
        return $this;
271
    }
272
273
    /**
274
     * @param $string
275
     * @param array $values
276
     *
277
     * @return $this
278
     */
279
    public function having($string, $values = [])
280
    {
281
        if (empty($string)) {
282
            return $this;
283
        }
284
285
        $condition =  $this->getCondition($string, $values);
286
        $having = $this->getPart('having');
287
288
        if ($having instanceof Condition) {
289
            $having = $having->and_($this->getCondition($string, $values));
290
        } else {
291
            $having = $condition;
292
        }
293
        $this->parts['having'] = $having;
294
        return $this;
295
    }
296
297
    /**
298
     * Escapes data for safe use in SQL queries
299
     *
300
     * @param string $data
301
     * @return string
302
     */
303 3
    public function cleanData($data)
304
    {
305 3
        return $this->getManager()->getAdapter()->cleanData($data);
306
    }
307
308
    /**
309
     * @return Connection
310
     */
311
    public function getManager()
312
    {
313
        return $this->db;
314
    }
315
316
    /**
317
     * @return Result
318
     */
319
    public function execute()
320
    {
321 2
        return $this->getManager()->execute($this);
322
    }
323 2
324
    /**
325
     * Implements magic method.
326
     *
327
     * @return string This object as a Query string.
328
     */
329 2
    public function __toString()
330
    {
331 2
        return $this->getString();
332 2
    }
333
334
    /**
335 2
     * @return string
336
     */
337
    public function getString()
338
    {
339
        if ($this->string === null) {
340
            $this->string = (string)$this->assemble();
341
        }
342
343
        return $this->string;
344
    }
345
346
    /**
347
     * @return null
348
     */
349
    abstract public function assemble();
350
351
    /**
352
     * @return array
353
     */
354 10
    public function getParts()
355
    {
356 10
        return $this->parts;
357
    }
358 10
359 6
    /**
360
     * @return null|string
361
     */
362 4
    protected function assembleWhere()
363
    {
364
        $where = $this->parseWhere();
365
366
        if (!empty($where)) {
367
            return " WHERE $where";
368 10
        }
369
370 10
        return null;
371
    }
372
373
    /**
374
     * @return string
375
     */
376 10
    protected function parseWhere()
377
    {
378 10
        return is_object($this->parts['where']) ? (string)$this->parts['where'] : '';
379 10
    }
380 1
381
    /**
382
     * @return null|string
383 9
     */
384
    protected function assembleLimit()
385
    {
386
        $limit = $this->getPart('limit');
387
        if (!empty($limit)) {
388
            return " LIMIT {$this->parts['limit']}";
389
        }
390 11
391
        return null;
392 11
    }
393
394
    /**
395
     * @param string $name
396
     * @return mixed|null
397
     */
398
    public function getPart($name)
399 13
    {
400
        return $this->hasPart($name) ? $this->parts[$name] : null;
401 13
    }
402 11
403
    /**
404 3
     * @param $name
405
     * @return bool
406
     */
407 3
    public function hasPart($name)
408 1
    {
409
        if (!isset($this->parts[$name])) {
410
            return false;
411 3
        }
412
        if ($this->parts[$name] === null) {
413
            return false;
414
        }
415
        if (is_array($this->parts[$name]) && count($this->parts[$name]) < 1) {
416
            return false;
417
        }
418
        if (is_string($this->parts[$name]) && empty($this->parts[$name])) {
419
            return false;
420
        }
421
422
        return true;
423
    }
424
425
    /**
426
     * @param $name
427
     * @param $value
428
     *
429
     * @return $this
430 2
     */
431
    protected function setPart($name, $value)
432 2
    {
433
        $this->initPart($name);
434
        $this->addPart($name, $value);
435
436 2
        return $this;
437
    }
438
439
    /**
440
     * @return string
441
     * @return mixed
442 10
     */
443
    protected function getTable()
444 10
    {
445
        if (!is_array($this->parts['table']) && count($this->parts['table']) < 1) {
446
            trigger_error('No Table defined', E_USER_WARNING);
447
        }
448 10
449
        return reset($this->parts['table']);
450
    }
451
452
    /**
453
     * @return string
454
     */
455
    protected function parseHaving()
456 10
    {
457
        if (isset($this->parts['having'])) {
458 10
            return (string)$this->parts['having'];
459 10
        }
460
461
        return '';
462
    }
463
464
    /**
465
     * Parses ORDER BY entries.
466
     * Parses ORDER BY entries
467
     *
468
     * @return string
469
     */
470
    protected function parseOrder()
471
    {
472
        if (!isset($this->parts['order']) || !is_array($this->parts['order']) || count($this->parts['order']) < 1) {
473
            return false;
474
        }
475
476
        $orderParts = [];
477
478
        foreach ($this->parts['order'] as $itemOrder) {
479
            if ($itemOrder) {
480
                if (!is_array($itemOrder)) {
481
                    $itemOrder = [$itemOrder];
482
                }
483
484
                $column = isset($itemOrder[0]) ? $itemOrder[0] : false;
485
                $type = isset($itemOrder[1]) ? $itemOrder[1] : '';
486
                $protected = isset($itemOrder[2]) ? $itemOrder[2] : true;
487
488
                $column = ($protected ? $this->protect($column) : $column).' '.strtoupper($type);
489 7
490
                $orderParts[] = trim($column);
491 7
            }
492 7
        }
493
494
        return implode(', ', $orderParts);
495
    }
496
497
    /**
498
     * Adds backticks to input.
499
     *
500
     * @param string $input
501
     *
502
     * @return string
503
     */
504
    protected function protect($input)
505
    {
506
        return strpos($input, '(') !== false ? $input : str_replace("`*`", "*",
507
            '`'.str_replace('.', '`.`', $input).'`');
508
    }
509
510
    /**
511
     * Prefixes table names
512
     *
513
     * @param string $table
514
     * @return string
515
     */
516
    protected function tableName($table = '')
517
    {
518
        return $this->getManager()->tableName($table);
519
    }
520
521
    /**
522
     * Removes backticks from input
523
     *
524
     * @param string $input
525
     * @return string
526
     */
527
    protected function cleanProtected($input)
528
    {
529
        return str_replace('`', '', $input);
530
    }
531
}
532