Passed
Push — master ( bab9dc...bf7b05 )
by Gabriel
02:36
created

AbstractQuery::assembleLimit()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

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