Passed
Push — master ( f2aa8d...153a1c )
by Petr
13:28 queued 05:17
created

AReadWriteDatabase::loadRecord()   B

Complexity

Conditions 9
Paths 22

Size

Total Lines 39
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 9

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 9
eloc 20
nc 22
nop 1
dl 0
loc 39
ccs 21
cts 21
cp 1
crap 9
rs 8.0555
c 1
b 0
f 1
1
<?php
2
3
namespace kalanis\kw_mapper\Mappers\Database;
4
5
6
use kalanis\kw_mapper\Interfaces\IQueryBuilder;
7
use kalanis\kw_mapper\MapperException;
8
use kalanis\kw_mapper\Mappers\AMapper;
9
use kalanis\kw_mapper\Records\ARecord;
10
use kalanis\kw_mapper\Records\TFill;
11
use kalanis\kw_mapper\Storage;
12
13
14
/**
15
 * Class AReadWriteDatabase
16
 * @package kalanis\kw_mapper\Mappers\Database
17
 * Separated Read and write DB entry without need to reload mapper
18
 * The most parts are similar to usual read/write one, just with separation of read-write operations
19
 */
20
abstract class AReadWriteDatabase extends AMapper
21
{
22
    use TFill;
23
    use TTable;
24
25
    /** @var string */
26
    protected $readSource = '';
27
    /** @var string */
28
    protected $writeSource = '';
29
    /** @var Storage\Database\ASQL */
30
    protected $readDatabase = null;
31
    /** @var Storage\Database\ASQL */
32
    protected $writeDatabase = null;
33
    /** @var Storage\Database\Dialects\ADialect */
34
    protected $readDialect = null;
35
    /** @var Storage\Database\Dialects\ADialect */
36
    protected $writeDialect = null;
37
    /** @var Storage\Database\QueryBuilder */
38
    protected $readQueryBuilder = null;
39
    /** @var Storage\Database\QueryBuilder */
40
    protected $writeQueryBuilder = null;
41
42
    /**
43
     * @throws MapperException
44
     */
45 4
    public function __construct()
46
    {
47 4
        parent::__construct();
48
49
        // read part
50 4
        $readConfig = Storage\Database\ConfigStorage::getInstance()->getConfig($this->getReadSource());
51 4
        $this->readDatabase = Storage\Database\DatabaseSingleton::getInstance()->getDatabase($readConfig);
52 4
        $this->readDialect = Storage\Database\Dialects\Factory::getInstance()->getDialectClass($this->readDatabase->languageDialect());
53 4
        $this->readQueryBuilder = new Storage\Database\QueryBuilder($this->readDialect);
54
55
        // write part
56 4
        $writeConfig = Storage\Database\ConfigStorage::getInstance()->getConfig($this->getWriteSource());
57 4
        $this->writeDatabase = Storage\Database\DatabaseSingleton::getInstance()->getDatabase($writeConfig);
58 4
        $this->writeDialect = Storage\Database\Dialects\Factory::getInstance()->getDialectClass($this->writeDatabase->languageDialect());
59 4
        $this->writeQueryBuilder = new Storage\Database\QueryBuilder($this->writeDialect);
60
    }
61
62 4
    protected function setReadSource(string $readSource): void
63
    {
64 4
        $this->readSource = $readSource;
65
    }
66
67 4
    protected function getReadSource(): string
68
    {
69 4
        return $this->readSource;
70
    }
71
72 4
    protected function setWriteSource(string $writeSource): void
73
    {
74 4
        $this->writeSource = $writeSource;
75
    }
76
77 4
    protected function getWriteSource(): string
78
    {
79 4
        return $this->writeSource;
80
    }
81
82 2
    public function getAlias(): string
83
    {
84 2
        return $this->getTable();
85
    }
86
87 5
    protected function insertRecord(ARecord $record): bool
88
    {
89 5
        $this->writeQueryBuilder->clear();
90 5
        $this->writeQueryBuilder->setBaseTable($this->getTable());
91 5
        foreach ($record as $key => $item) {
92 5
            if (isset($this->relations[$key]) && (false !== $item)) {
93 4
                $this->writeQueryBuilder->addProperty($this->getTable(), $this->relations[$key], $item);
94
            }
95
        }
96 5
        if (empty($this->writeQueryBuilder->getProperties())) {
97 1
            return false;
98
        }
99
100 4
        return $this->writeDatabase->exec(strval($this->writeDialect->insert($this->writeQueryBuilder)), $this->writeQueryBuilder->getParams());
101
    }
102
103 4
    protected function updateRecord(ARecord $record): bool
104
    {
105 4
        if ($this->updateRecordByPk($record)) {
106 1
            return true;
107
        }
108 3
        $this->writeQueryBuilder->clear();
109 3
        $this->writeQueryBuilder->setBaseTable($this->getTable());
110 3
        foreach ($record as $key => $item) {
111 3
            if (isset($this->relations[$key]) && (false !== $item)) {
112 3
                if ($record->getEntry($key)->isFromStorage()) {
113 2
                    $this->writeQueryBuilder->addCondition($this->getTable(), $this->relations[$key], IQueryBuilder::OPERATION_EQ, $item);
114
                } else {
115 2
                    $this->writeQueryBuilder->addProperty($this->getTable(), $this->relations[$key], $item);
116
                }
117
            }
118
        }
119 3
        if (empty($this->writeQueryBuilder->getConditions())) {
120 1
            return false;
121
        }
122 2
        if (empty($this->writeQueryBuilder->getProperties())) {
123 1
            return false;
124
        }
125
126 1
        return $this->writeDatabase->exec(strval($this->writeDialect->update($this->writeQueryBuilder)), $this->writeQueryBuilder->getParams());
127
    }
128
129
    /**
130
     * @param ARecord $record
131
     * @throws MapperException
132
     * @return bool
133
     */
134 6
    protected function updateRecordByPk(ARecord $record): bool
135
    {
136 6
        if (empty($record->getMapper()->getPrimaryKeys())) {
137 2
            return false;
138
        }
139
140 4
        $this->writeQueryBuilder->clear();
141 4
        $this->writeQueryBuilder->setBaseTable($this->getTable());
142 4
        foreach ($record->getMapper()->getPrimaryKeys() as $key) {
143
            try {
144 4
                if (isset($this->relations[$key])) {
145 4
                    $entry = $record->getEntry($key);
146 3
                    if ($entry->isFromStorage() && (false !== $entry->getData())) {
147 3
                        $this->writeQueryBuilder->addCondition($this->getTable(), $this->relations[$key], IQueryBuilder::OPERATION_EQ, $entry->getData());
148
                    }
149
                }
150 1
            } catch (MapperException $ex) {
151 1
                return false;
152
            }
153
        }
154
155 3
        if (empty($this->writeQueryBuilder->getConditions())) { // no conditions, nothing in PKs - back to normal system
156 1
            return false;
157
        }
158
159 2
        foreach ($record as $key => $item) {
160 2
            if (isset($this->relations[$key])) {
161 2
                $entry = $record->getEntry($key);
162 2
                if (!in_array($key, $record->getMapper()->getPrimaryKeys()) && !$entry->isFromStorage() && (false !== $item)) {
163 1
                    $this->writeQueryBuilder->addProperty($this->getTable(), $this->relations[$key], $item);
164
                }
165
            }
166
        }
167 2
        if (empty($this->writeQueryBuilder->getProperties())) {
168 1
            return false;
169
        }
170
171 1
        return $this->writeDatabase->exec(strval($this->writeDialect->update($this->writeQueryBuilder)), $this->writeQueryBuilder->getParams());
172
    }
173
174 2
    protected function loadRecord(ARecord $record): bool
175
    {
176 2
        if ($this->loadRecordByPk($record)) {
177 1
            return true;
178
        }
179
180 2
        $this->readQueryBuilder->clear();
181 2
        $this->readQueryBuilder->setBaseTable($this->getTable());
182
183
        // conditions - must be equal
184 2
        foreach ($record as $key => $item) {
185 2
            if (isset($this->relations[$key]) && (false !== $item)) {
186 2
                $this->readQueryBuilder->addCondition($this->getTable(), $this->relations[$key], IQueryBuilder::OPERATION_EQ, $item);
187
            }
188
        }
189
190 2
        if (empty($this->readQueryBuilder->getConditions())) {
191 1
            return false;
192
        }
193
194
        // relations - what to get
195 2
        foreach ($this->relations as $localAlias => $remoteColumn) {
196 2
            $this->readQueryBuilder->addColumn($this->getTable(), $remoteColumn, $localAlias);
197
        }
198 2
        $this->readQueryBuilder->setLimits(0,1);
199
200
        // query itself
201 2
        $lines = $this->readDatabase->query(strval($this->readDialect->select($this->readQueryBuilder)), $this->readQueryBuilder->getParams());
202 2
        if (empty($lines)) {
203 1
            return false;
204
        }
205
206
        // fill entries in record
207 1
        $line = reset($lines);
208 1
        foreach ($line as $index => $item) {
209 1
            $entry = $record->getEntry($index);
210 1
            $entry->setData($this->typedFillSelection($entry, $item), true);
211
        }
212 1
        return true;
213
    }
214
215
    /**
216
     * @param ARecord $record
217
     * @throws MapperException
218
     * @return bool
219
     */
220 5
    protected function loadRecordByPk(ARecord $record): bool
221
    {
222 5
        if (empty($record->getMapper()->getPrimaryKeys())) {
223 2
            return false;
224
        }
225
226 4
        $this->readQueryBuilder->clear();
227 4
        $this->readQueryBuilder->setBaseTable($this->getTable());
228
229
        // conditions - everything must be equal
230 4
        foreach ($record->getMapper()->getPrimaryKeys() as $key) {
231
            try {
232 4
                if (isset($this->relations[$key])) {
233 4
                    $item = $record->offsetGet($key);
234 3
                    if (false !== $item) {
235 3
                        $this->readQueryBuilder->addCondition($this->getTable(), $this->relations[$key], IQueryBuilder::OPERATION_EQ, $item);
236
                    }
237
                }
238 2
            } catch (MapperException $ex) {
239 2
                return false;
240
            }
241
        }
242
243 3
        if (empty($this->readQueryBuilder->getConditions())) { // no conditions, nothing in PKs - back to normal system
244 1
            return false;
245
        }
246
247
        // relations - what to get
248 2
        foreach ($this->relations as $localAlias => $remoteColumn) {
249 2
            $this->readQueryBuilder->addColumn($this->getTable(), $remoteColumn, $localAlias);
250
        }
251
252
        // query itself
253 2
        $this->readQueryBuilder->setLimits(0,1);
254 2
        $lines = $this->readDatabase->query(strval($this->readDialect->select($this->readQueryBuilder)), $this->readQueryBuilder->getParams());
255 2
        if (empty($lines)) {
256 1
            return false;
257
        }
258
259
        // fill entries in record
260 1
        $line = reset($lines);
261 1
        foreach ($line as $index => $item) {
262 1
            $entry = $record->getEntry($index);
263 1
            $entry->setData($this->typedFillSelection($entry, $item), true);
264
        }
265 1
        return true;
266
    }
267
268 1
    public function countRecord(ARecord $record): int
269
    {
270 1
        $this->readQueryBuilder->clear();
271 1
        $this->readQueryBuilder->setBaseTable($this->getTable());
272 1
        foreach ($record as $key => $item) {
273 1
            if (isset($this->relations[$key]) && (false !== $item)) {
274 1
                $this->readQueryBuilder->addCondition($this->getTable(), $this->relations[$key], IQueryBuilder::OPERATION_EQ, $item);
275
            }
276
        }
277
278 1
        if (empty($this->readQueryBuilder->getConditions())) {
279 1
            return 0;
280
        }
281
282 1
        if (empty($record->getMapper()->getPrimaryKeys())) {
283 1
            $relation = reset($this->relations);
284 1
            if (false !== $relation) {
285 1
                $this->readQueryBuilder->addColumn($this->getTable(), $relation, 'count', IQueryBuilder::AGGREGATE_COUNT);
286
            }
287
        } else {
288
//            foreach ($record->getMapper()->getPrimaryKeys() as $primaryKey) {
289
//                $this->queryBuilder->addColumn($this->getTable(), $primaryKey, '', IQueryBuilder::AGGREGATE_COUNT);
290
//            }
291 1
            $pks = $record->getMapper()->getPrimaryKeys();
292 1
            $key = reset($pks);
293 1
            $this->readQueryBuilder->addColumn($this->getTable(), $this->relations[$key], 'count', IQueryBuilder::AGGREGATE_COUNT);
294
        }
295
296 1
        $lines = $this->readDatabase->query(strval($this->readDialect->select($this->readQueryBuilder)), $this->readQueryBuilder->getParams());
297 1
        if (empty($lines) || !is_iterable($lines)) {
298
            // @codeCoverageIgnoreStart
299
            return 0;
300
        }
301
        // @codeCoverageIgnoreEnd
302 1
        $line = reset($lines);
303 1
        return intval(reset($line));
304
    }
305
306 4
    protected function deleteRecord(ARecord $record): bool
307
    {
308 4
        if ($this->deleteRecordByPk($record)) {
309 2
            return true;
310
        }
311
312 2
        $this->writeQueryBuilder->clear();
313 2
        $this->writeQueryBuilder->setBaseTable($this->getTable());
314 2
        foreach ($record as $key => $item) {
315 2
            if (isset($this->relations[$key]) && (false !== $item)) {
316 1
                $this->writeQueryBuilder->addCondition($this->getTable(), $this->relations[$key], IQueryBuilder::OPERATION_EQ, $item);
317
            }
318
        }
319
320 2
        if (empty($this->writeQueryBuilder->getConditions())) {
321 1
            return false;
322
        }
323
324 1
        return $this->writeDatabase->exec(strval($this->writeDialect->delete($this->writeQueryBuilder)), $this->writeQueryBuilder->getParams());
325
    }
326
327
    /**
328
     * @param ARecord $record
329
     * @throws MapperException
330
     * @return bool
331
     */
332 6
    protected function deleteRecordByPk(ARecord $record): bool
333
    {
334 6
        if (empty($record->getMapper()->getPrimaryKeys())) {
335 3
            return false;
336
        }
337
338 4
        $this->writeQueryBuilder->clear();
339 4
        $this->writeQueryBuilder->setBaseTable($this->getTable());
340 4
        foreach ($record->getMapper()->getPrimaryKeys() as $key) {
341
            try {
342 4
                if (isset($this->relations[$key])) {
343 4
                    $item = $record->offsetGet($key);
344 3
                    if (false !== $item) {
345 3
                        $this->writeQueryBuilder->addCondition($this->getTable(), $this->relations[$key], IQueryBuilder::OPERATION_EQ, $item);
346
                    }
347
                }
348 1
            } catch (MapperException $ex) {
349 1
                return false;
350
            }
351
        }
352
353 3
        if (empty($this->writeQueryBuilder->getConditions())) { // no conditions, nothing in PKs - back to normal system
354 1
            return false;
355
        }
356
357 2
        return $this->writeDatabase->exec(strval($this->writeDialect->delete($this->writeQueryBuilder)), $this->writeQueryBuilder->getParams());
358
    }
359
360 2
    public function loadMultiple(ARecord $record): array
361
    {
362 2
        $this->readQueryBuilder->clear();
363 2
        $this->readQueryBuilder->setBaseTable($this->getTable());
364 2
        foreach ($record as $key => $item) {
365 2
            if (isset($this->relations[$key]) && (false !== $item)) {
366 2
                $this->readQueryBuilder->addCondition($this->getTable(), $this->relations[$key], IQueryBuilder::OPERATION_EQ, $item);
367
            }
368
        }
369
370 2
        if (empty($this->readQueryBuilder->getConditions())) {
371 1
            return [];
372
        }
373
374
        // relations - what to get
375 2
        foreach ($this->relations as $localAlias => $remoteColumn) {
376 2
            $this->readQueryBuilder->addColumn($this->getTable(), $remoteColumn, $localAlias);
377
        }
378
379
        // query itself
380 2
        $lines = $this->readDatabase->query(strval($this->readDialect->select($this->readQueryBuilder)), $this->readQueryBuilder->getParams());
381 2
        if (empty($lines)) {
382 1
            return [];
383
        }
384
385 1
        $result = [];
386 1
        foreach ($lines as $line) {
387 1
            $rec = clone $record;
388 1
            foreach ($line as $index => $item) {
389 1
                $entry = $rec->getEntry($index);
390 1
                $entry->setData($this->typedFillSelection($entry, $item), true);
391
            }
392 1
            $result[] = $rec;
393
        }
394 1
        return $result;
395
    }
396
}
397