Passed
Push — master ( 9b7912...982aac )
by Janis
02:15
created

QueryBuilder   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 271
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 101
dl 0
loc 271
rs 10
c 0
b 0
f 0
wmc 30

14 Methods

Rating   Name   Duplication   Size   Complexity  
A count() 0 5 1
A __construct() 0 4 1
A updateIgnore() 0 5 1
A toString() 0 3 1
A insert() 0 5 1
A find() 0 5 1
A replace() 0 5 1
A generateSqlExecuteString() 0 19 5
A findOne() 0 5 1
A delete() 0 5 1
A getEntity() 0 3 1
A insertIgnore() 0 5 1
C buildQuery() 0 93 13
A update() 0 5 1
1
<?php declare(strict_types=1);
2
3
namespace Janisbiz\LightOrm\Dms\MySQL\QueryBuilder;
4
5
use Janisbiz\LightOrm\Entity\EntityInterface;
6
use Janisbiz\LightOrm\Dms\MySQL\Enum\CommandEnum;
7
8
class QueryBuilder implements QueryBuilderInterface
9
{
10
    use Traits;
11
12
    /**
13
     * @var \Closure
14
     */
15
    protected $repositoryCallback;
16
17
    /**
18
     * @var null|EntityInterface
19
     */
20
    protected $entity;
21
22
    /**
23
     * @param \Closure $repositoryCallback
24
     * @param EntityInterface|null $entity
25
     */
26
    public function __construct(\Closure $repositoryCallback, EntityInterface $entity = null)
27
    {
28
        $this->repositoryCallback = $repositoryCallback;
29
        $this->entity = $entity;
30
    }
31
32
    /**
33
     * @param bool $toString
34
     *
35
     * @return string|EntityInterface
36
     */
37
    public function insert(bool $toString = false)
38
    {
39
        $this->command(CommandEnum::INSERT_INTO);
40
41
        return \call_user_func($this->repositoryCallback, 'insert', $this, $toString);
42
    }
43
44
    /**
45
     * @param bool $toString
46
     *
47
     * @return string|EntityInterface
48
     */
49
    public function insertIgnore(bool $toString = false)
50
    {
51
        $this->command(CommandEnum::INSERT_IGNORE_INTO);
52
53
        return \call_user_func($this->repositoryCallback, 'insertIgnore', $this, $toString);
54
    }
55
56
    /**
57
     * @param bool $toString
58
     *
59
     * @return string|EntityInterface
60
     */
61
    public function replace(bool $toString = false)
62
    {
63
        $this->command(CommandEnum::REPLACE_INTO);
64
65
        return \call_user_func($this->repositoryCallback, 'replace', $this, $toString);
66
    }
67
68
    /**
69
     * @param bool $toString
70
     *
71
     * @return string|EntityInterface[]
72
     */
73
    public function find(bool $toString = false)
74
    {
75
        $this->command(CommandEnum::SELECT);
76
77
        return \call_user_func($this->repositoryCallback, 'find', $this, $toString);
78
    }
79
80
    /**
81
     * @param bool $toString
82
     *
83
     * @return null|string|EntityInterface
84
     */
85
    public function findOne(bool $toString = false)
86
    {
87
        $this->command(CommandEnum::SELECT);
88
89
        return \call_user_func($this->repositoryCallback, 'findOne', $this, $toString);
90
    }
91
92
    /**
93
     * @param bool $toString
94
     *
95
     * @return null|string|bool|EntityInterface
96
     */
97
    public function update(bool $toString = false)
98
    {
99
        $this->command(CommandEnum::UPDATE);
100
101
        return \call_user_func($this->repositoryCallback, 'update', $this, $toString);
102
    }
103
104
    /**
105
     * @param bool $toString
106
     *
107
     * @return null|string|bool|EntityInterface
108
     */
109
    public function updateIgnore(bool $toString = false)
110
    {
111
        $this->command(CommandEnum::UPDATE_IGNORE);
112
113
        return \call_user_func($this->repositoryCallback, 'updateIgnore', $this, $toString);
114
    }
115
116
    /**
117
     * @param bool $toString
118
     *
119
     * @return string|bool
120
     */
121
    public function delete(bool $toString = false)
122
    {
123
        $this->command(CommandEnum::DELETE);
124
125
        return \call_user_func($this->repositoryCallback, 'delete', $this, $toString);
126
    }
127
128
    /**
129
     * @param bool $toString
130
     *
131
     * @return int
132
     */
133
    public function count(bool $toString = false)
134
    {
135
        $this->command(CommandEnum::SELECT);
136
137
        return \call_user_func($this->repositoryCallback, 'count', $this, $toString);
138
    }
139
140
    /**
141
     * @return string
142
     * @throws QueryBuilderException
143
     */
144
    public function buildQuery(): string
145
    {
146
        if (empty($this->command)) {
147
            throw new QueryBuilderException('Could not build query, as there is no command provided!');
148
        }
149
150
        switch ($this->command) {
151
            case CommandEnum::INSERT_IGNORE_INTO:
152
            case CommandEnum::INSERT_INTO:
153
            case CommandEnum::REPLACE_INTO:
154
                $queryParts = [
155
                    $this->buildCommandQueryPart(),
156
                    $this->buildTableQueryPart(),
157
                    $this->buildValueQueryPart(),
158
                    $this->buildOnDuplicateKeyUpdateQueryPart(),
159
                ];
160
161
                break;
162
163
            case CommandEnum::SELECT:
164
                if (!empty($this->unionAll)) {
165
                    $queryParts = [
166
                        $this->buildUnionAllQueryPart(),
167
                        $this->buildOrderByQueryPart(),
168
                        $this->buildLimitQueryPart(),
169
                        $this->buildOffsetQueryPart(),
170
                    ];
171
172
                    break;
173
                }
174
175
                $queryParts = [
176
                    $this->buildCommandQueryPart(),
177
                    $this->buildColumnQueryPart(),
178
                    $this->buildFromQueryPart(),
179
                    $this->buildJoinQueryPart(),
180
                    $this->buildWhereQueryPart(),
181
                    $this->buildGroupByQueryPart(),
182
                    $this->buildHavingQueryPart(),
183
                    $this->buildOrderByQueryPart(),
184
                    $this->buildLimitQueryPart(),
185
                    $this->buildOffsetQueryPart(),
186
                ];
187
188
                break;
189
190
            case CommandEnum::UPDATE:
191
            case CommandEnum::UPDATE_IGNORE:
192
                if (empty($this->set)) {
193
                    throw new QueryBuilderException('Cannot perform UPDATE action without SET condition!');
194
                }
195
196
                if (empty($this->where)) {
197
                    throw new QueryBuilderException('Cannot perform UPDATE action without WHERE condition!');
198
                }
199
200
                $queryParts = [
201
                    $this->buildCommandQueryPart(),
202
                    $this->buildTableQueryPart(),
203
                    $this->buildJoinQueryPart(),
204
                    $this->buildSetQueryPart(),
205
                    $this->buildWhereQueryPart(),
206
                    $this->buildLimitQueryPart(),
207
                    $this->buildOffsetQueryPart(),
208
                ];
209
210
                break;
211
212
            case CommandEnum::DELETE:
213
                if (empty($this->where)) {
214
                    throw new QueryBuilderException('Cannot perform DELETE action without WHERE condition!');
215
                }
216
217
                $queryParts = [
218
                    $this->buildCommandQueryPart(),
219
                    $this->buildTableQueryPart(),
220
                    $this->buildFromQueryPart(),
221
                    $this->buildJoinQueryPart(),
222
                    $this->buildWhereQueryPart(),
223
                    $this->buildLimitQueryPart(),
224
                    $this->buildOffsetQueryPart(),
225
                ];
226
227
                break;
228
229
            default:
230
                throw new QueryBuilderException(\sprintf(
231
                    'Could not build query, as there is no valid(%s) command provided!',
232
                    $this->command
233
                ));
234
        }
235
236
        return \trim(\implode(' ', \array_filter($queryParts)));
237
    }
238
239
    /**
240
     * @return null|EntityInterface
241
     */
242
    public function getEntity(): ?EntityInterface
243
    {
244
        return $this->entity;
245
    }
246
247
    /**
248
     * @return string
249
     */
250
    public function toString(): string
251
    {
252
        return $this->generateSqlExecuteString($this->buildQuery());
253
    }
254
255
    /**
256
     * @param string $query
257
     *
258
     * @return string
259
     */
260
    protected function generateSqlExecuteString(string $query): string
261
    {
262
        foreach ($this->bind as $bindName => $bindValue) {
263
            $query = \preg_replace(
264
                \sprintf('/\:\b%s\b/', \preg_quote($bindName)),
265
                \is_string($bindValue) ? \sprintf('\'%s\'', $bindValue) : $bindValue,
266
                $query
267
            );
268
        }
269
270
        foreach ($this->bindValue as $bindValueName => $bindValueValue) {
271
            $query = \preg_replace(
272
                \sprintf('/\:\b%s\b/', \preg_quote($bindValueName)),
273
                \is_string($bindValueValue) ? \sprintf('\'%s\'', $bindValueValue) : $bindValueValue,
274
                $query
275
            );
276
        }
277
278
        return $query;
279
    }
280
}
281