QueryMaker   A
last analyzed

Complexity

Total Complexity 32

Size/Duplication

Total Lines 251
Duplicated Lines 0 %

Test Coverage

Coverage 78.26%

Importance

Changes 7
Bugs 3 Features 1
Metric Value
eloc 134
c 7
b 3
f 1
dl 0
loc 251
ccs 54
cts 69
cp 0.7826
rs 9.84
wmc 32

22 Methods

Rating   Name   Duplication   Size   Complexity  
A reset() 0 8 1
A select() 0 7 1
A __construct() 0 3 1
A insert() 0 12 1
A update() 0 7 1
A count() 0 28 5
A where() 0 8 1
A getQuery() 0 3 1
A and() 0 8 1
A join() 0 35 1
A delete() 0 6 1
A or() 0 8 1
A limit() 0 4 1
A offset() 0 4 1
A prepareParam() 0 3 1
A checkDirection() 0 5 2
A prepareParams() 0 23 3
A checkOperator() 0 5 2
A getParams() 0 3 1
A between() 0 8 1
A getStatement() 0 3 1
A orderBy() 0 8 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace midorikocak\querymaker;
6
7
use InvalidArgumentException;
8
9
use function array_keys;
10
use function array_map;
11
use function array_values;
12
use function implode;
13
use function in_array;
14
use function preg_replace;
15
use function uniqid;
16
17
class QueryMaker implements QueryInterface
18
{
19
    private string $query;
20 21
    private string $statement;
21
    private array $params;
22 21
    private string $offset;
0 ignored issues
show
introduced by
The private property $offset is not used, and could be removed.
Loading history...
23 21
    private string $limit;
24 21
    private string $orderBy;
25 21
26
    public function __construct()
27 18
    {
28
        $this->reset();
29 18
    }
30 18
31 18
    private function reset(): void
32 18
    {
33
        $this->query = '';
34
        $this->statement = '';
35 3
        $this->params = [];
36
37 3
        $this->limit = '';
38 3
        $this->orderBy = '';
39 3
    }
40 3
41
    public function select($table, array $columns = ['*']): QueryInterface
42
    {
43 15
        $this->reset();
44
        $columnsText = implode(', ', $columns);
45 15
        $this->statement = 'SELECT ' . $columnsText . ' FROM ' . $table;
46 15
        $this->query = 'SELECT ' . $columnsText . ' FROM ' . $table;
47
        return $this;
48
    }
49 15
50
    public function count($table = null, bool $resetLimit = false): QueryInterface
0 ignored issues
show
Unused Code introduced by
The parameter $resetLimit is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

50
    public function count($table = null, /** @scrutinizer ignore-unused */ bool $resetLimit = false): QueryInterface

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
51
    {
52 15
        if ($table && $this->query === '') {
53 15
            $this->reset();
54 15
            $this->statement = 'SELECT COUNT(*) FROM ' . $table;
55 15
            $this->query = 'SELECT COUNT(*) FROM ' . $table;
56
            return $this;
57
        }
58 6
59
        if (!$table && $this->query === '') {
60 6
            throw new InvalidArgumentException('Cannot count');
61 6
        }
62 6
63 6
        $query = $this->query;
64
        $statement = $this->statement;
65
        $limit = $this->limit;
66 6
67
        $this->query = preg_replace('/SELECT .*? FROM/', 'SELECT COUNT(*) FROM', $this->query);
68 6
        $this->statement = preg_replace('/SELECT .*? FROM/', 'SELECT COUNT(*) FROM', $this->statement);
69 6
        $this->limit = '';
70 6
71 6
        $toReturn = clone $this;
72
73
        $this->query = $query;
74
        $this->statement = $statement;
75
        $this->limit = $limit;
76
77
        return $toReturn;
78
    }
79
80
    public function update($table, array $values): QueryInterface
81
    {
82
        $this->reset();
83
        $this->statement = 'UPDATE ' . $table . ' SET ';
84 21
        $this->query = 'UPDATE ' . $table . ' SET ';
85
        $this->prepareParams($values, ', ');
86 21
        return $this;
87
    }
88
89 21
    public function insert($table, array $values): QueryInterface
90
    {
91 21
        $this->reset();
92
        $fields = implode(', ', array_keys($values));
93
        $params = implode(', ', array_map(fn($key) => ':' . $key, array_keys($values)));
94
        $queryValues = implode(', ', array_map(fn($value) => "'$value'", array_values($values)));
95
96
        $this->statement = "INSERT INTO $table ($fields) VALUES ($params)";
97
        $this->query = "INSERT INTO $table ($fields) VALUES ($queryValues)";
98
        $this->params = $values;
99 12
100
        return $this;
101 12
    }
102 12
103
    public function join(
104 12
        string $direction,
105 12
        string $remoteTable,
106 12
        string $leftField,
107
        string $rightField,
108
        string $operator = '='
109
    ): QueryInterface {
110 12
        $this->checkOperator($operator);
111
        $this->checkDirection($direction);
112
113 12
        $this->query .= ' '
114 12
            . $direction
115 12
            . ' JOIN '
116
            . $remoteTable
117 12
            . ' ON '
118
            . $leftField
119
            . ' '
120
            . $operator
121
            . ' '
122
            . $remoteTable
123
            . '.'
124
            . $rightField;
125
        $this->statement .= ' '
126
            . $direction
127 12
            . ' JOIN '
128 12
            . $remoteTable
129 12
            . ' ON '
130
            . $leftField
131 9
            . ' '
132
            . $operator
133 9
            . ' '
134 9
            . $remoteTable
135
            . '.'
136
            . $rightField;
137
        return $this;
138
    }
139
140
    public function delete($table): QueryInterface
141
    {
142
        $this->reset();
143
        $this->statement = 'DELETE FROM ' . $table;
144
        $this->query = 'DELETE FROM ' . $table;
145
        return $this;
146
    }
147
148
    public function where($key, $value, string $operator = '='): QueryInterface
149
    {
150
        $this->checkOperator($operator);
151
152
        $this->statement .= ' WHERE ' . $key . ' ' . $operator . ' :' . $key;
153
        $this->query .= ' WHERE ' . $key . ' ' . $operator . ' \'' . $value . '\'';
154
        $this->params[$key] = $value;
155
        return $this;
156
    }
157
158
    public function and($key, $value, string $operator = '='): QueryInterface
159
    {
160
        $this->checkOperator($operator);
161
162
        $this->query .= ' AND ';
163
        $this->statement .= ' AND ';
164
        $this->prepareParam($key, $value, 'AND', $operator);
165
        return $this;
166
    }
167
168
    public function orderBy($key, string $order = 'ASC'): QueryInterface
169
    {
170
        if ($order !== 'DESC' && $order !== 'ASC') {
171
            throw new InvalidArgumentException('Invalid order value');
172
        }
173
174
        $this->orderBy .= ' ORDER BY ' . $key . ' ' . $order;
175
        return $this;
176
    }
177
178
    public function limit(int $limit): QueryInterface
179
    {
180
        $this->limit .= ' LIMIT ' . $limit;
181
        return $this;
182
    }
183
184
    public function offset(int $offset): QueryInterface
185
    {
186
        $this->limit .= ' OFFSET ' . $offset;
187
        return $this;
188
    }
189
190
    public function or($key, $value, $operator = '='): QueryInterface
191
    {
192
        $this->checkOperator($operator);
193
194
        $this->query .= " OR ";
195
        $this->statement .= " OR ";
196
        $this->prepareParam($key, $value, 'OR', $operator);
197
        return $this;
198
    }
199
200
    public function between($key, $before, $after): QueryInterface
201
    {
202
        $this->query .= $key . " BETWEEN $before AND $after";
203
        $this->statement .= $key . ' BETWEEN :before AND :after';
204
205
        $this->params['before'] = $before;
206
        $this->params['after'] = $after;
207
        return $this;
208
    }
209
210
    public function getQuery(): string
211
    {
212
        return $this->query . $this->orderBy . $this->limit;
213
    }
214
215
    public function getStatement(): string
216
    {
217
        return $this->statement . $this->orderBy . $this->limit;
218
    }
219
220
    public function getParams(): array
221
    {
222
        return $this->params;
223
    }
224
225
    private function prepareParams(array $values, string $glue, string $operator = '=')
226
    {
227
        $this->checkOperator($operator);
228
        $params = [];
229
        $queryValues = [];
230
231
        foreach ($values as $key => $value) {
232
            if (!isset($this->params[$key])) {
233
                $queryValues[] = $key . ' ' . $operator . ' \'' . $value . '\'';
234
                $params [] = $key . ' ' . $operator . ' :' . $key;
235
236
                $this->params[$key] = $value;
237
            } else {
238
                $uniqid = uniqid('', true);
239
                $queryValues[] = $key . ' ' . $operator . ' \'' . $value . '\'';
240
                $params [] = $key . ' ' . $operator . ' :' . $key . $uniqid;
241
242
                $this->params[$key . $uniqid] = $value;
243
            }
244
        }
245
246
        $this->query .= implode($glue, $queryValues);
247
        $this->statement .= implode($glue, $params);
248
    }
249
250
    private function prepareParam(string $key, $value, string $glue, $operator = '='): void
251
    {
252
        $this->prepareParams([$key => $value], $glue, $operator);
253
    }
254
255
    private function checkOperator(string $operator): void
256
    {
257
        $operators = ['=', '>', '>=', '<', '<=', 'LIKE'];
258
        if (!in_array($operator, $operators, true)) {
259
            throw new InvalidArgumentException('Invalid Operator');
260
        }
261
    }
262
263
    private function checkDirection(string $direction): void
264
    {
265
        $directions = ['RIGHT', 'LEFT', 'INNER'];
266
        if (!in_array($direction, $directions, true)) {
267
            throw new InvalidArgumentException('Invalid Direction');
268
        }
269
    }
270
}
271