Passed
Push — master ( 02118d...11fb63 )
by Petr
03:00
created

AMongo::getReadDatabase()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 4
ccs 0
cts 4
cp 0
crap 2
rs 10
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\Mappers\Shared\TEntityChanged;
10
use kalanis\kw_mapper\Records\ARecord;
11
use kalanis\kw_mapper\Records\TFill;
12
use kalanis\kw_mapper\Storage\Database;
13
use kalanis\kw_mapper\Storage\Shared;
14
15
16
/**
17
 * Class AMongo
18
 * @package kalanis\kw_mapper\Mappers\Database
19
 * Mapper to NoSQL database MongoDB
20
 * @codeCoverageIgnore for now - external source
21
 */
22
abstract class AMongo extends AMapper
23
{
24
    use TEntityChanged;
25
    use TFill;
26
    use TTable;
27
28
    /** @var string|null */
29
    protected $readSource = null;
30
    /** @var string|null */
31
    protected $writeSource = null;
32
    /** @var Database\Raw\MongoDb */
33
    protected $readDatabase = null;
34
    /** @var Database\Raw\MongoDb */
35
    protected $writeDatabase = null;
36
    /** @var Database\Dialects\MongoDb */
37
    protected $readDialect = null;
38
    /** @var Database\Dialects\MongoDb */
39
    protected $writeDialect = null;
40
    /** @var Shared\QueryBuilder */
41
    protected $readQueryBuilder = null;
42
    /** @var Shared\QueryBuilder */
43
    protected $writeQueryBuilder = null;
44
45
    /**
46
     * @throws MapperException
47
     */
48
    public function __construct()
49
    {
50
        parent::__construct();
51
52
        $this->initReadDatabase();
53
        $this->initWriteDatabase();
54
    }
55
56
    /**
57
     * @throws MapperException
58
     */
59
    protected function initReadDatabase(): void
60
    {
61
        $this->readDatabase = $this->getReadDatabase();
62
        $this->readDialect = $this->getReadDialect($this->readDatabase);
63
        $this->readQueryBuilder = $this->getReadQueryBuilder();
64
    }
65
66
    /**
67
     * @throws MapperException
68
     */
69
    public function initWriteDatabase(): void
70
    {
71
        $this->writeDatabase = $this->getWriteDatabase();
72
        $this->writeDialect = $this->getWriteDialect($this->writeDatabase);
73
        $this->writeQueryBuilder = $this->getWriteQueryBuilder();
74
    }
75
76
    protected function setReadSource(string $readSource): void
77
    {
78
        $this->readSource = $readSource;
79
    }
80
81
    protected function getReadSource(): string
82
    {
83
        return $this->readSource ?? $this->getSource();
84
    }
85
86
    protected function setWriteSource(string $writeSource): void
87
    {
88
        $this->writeSource = $writeSource;
89
    }
90
91
    protected function getWriteSource(): string
92
    {
93
        return $this->writeSource ?? $this->getSource();
94
    }
95
96
    /**
97
     * @throws MapperException
98
     * @return Database\ADatabase
99
     */
100
    protected function getReadDatabase(): Database\ADatabase
101
    {
102
        return Database\DatabaseSingleton::getInstance()->getDatabase(
103
            Database\ConfigStorage::getInstance()->getConfig($this->getReadSource())
104
        );
105
    }
106
107
    /**
108
     * @param Database\ADatabase $database
109
     * @throws MapperException
110
     * @return Database\Dialects\ADialect
111
     */
112
    protected function getReadDialect(Database\ADatabase $database): Database\Dialects\ADialect
113
    {
114
        return Database\Dialects\Factory::getInstance()->getDialectClass($database->languageDialect());
115
    }
116
117
    protected function getReadQueryBuilder(): Shared\QueryBuilder
118
    {
119
        return new Shared\QueryBuilder();
120
    }
121
122
    /**
123
     * @throws MapperException
124
     * @return Database\ADatabase
125
     */
126
    protected function getWriteDatabase(): Database\ADatabase
127
    {
128
        return Database\DatabaseSingleton::getInstance()->getDatabase(
129
            Database\ConfigStorage::getInstance()->getConfig($this->getWriteSource())
130
        );
131
    }
132
133
    /**
134
     * @param Database\ADatabase $database
135
     * @throws MapperException
136
     * @return Database\Dialects\ADialect
137
     */
138
    protected function getWriteDialect(Database\ADatabase $database): Database\Dialects\ADialect
139
    {
140
        return Database\Dialects\Factory::getInstance()->getDialectClass($database->languageDialect());
141
    }
142
143
    protected function getWriteQueryBuilder(): Shared\QueryBuilder
144
    {
145
        return new Shared\QueryBuilder();
146
    }
147
148
    public function getAlias(): string
149
    {
150
        return $this->getTable();
151
    }
152
153
    protected function insertRecord(ARecord $record): bool
154
    {
155
        $this->writeQueryBuilder->clear();
156
        $this->writeQueryBuilder->setBaseTable($record->getMapper()->getAlias());
157
        $relations = $record->getMapper()->getRelations();
158
159
        foreach ($record as $key => $item) {
160
            if (isset($relations[$key]) && $this->ifEntryChanged($record->getEntry($key))) {
161
                $this->writeQueryBuilder->addProperty(
162
                    $record->getMapper()->getAlias(),
163
                    $relations[$key],
164
                    $item
165
                );
166
            }
167
        }
168
169
        if (empty($this->writeQueryBuilder->getProperties())) {
170
            return false;
171
        }
172
173
        return $this->writeDatabase->exec(
174
            $this->writeQueryBuilder,
175
            // @phpstan-ignore-next-line  expects MongoDB\Driver\BulkWrite, object|string given
176
            $this->writeDialect->insert($this->writeQueryBuilder)
177
        );
178
    }
179
180
    protected function updateRecord(ARecord $record): bool
181
    {
182
        $this->writeQueryBuilder->clear();
183
        $this->writeQueryBuilder->setBaseTable($record->getMapper()->getAlias());
184
        $relations = $record->getMapper()->getRelations();
185
186
        foreach ($record as $key => $item) {
187
            if (isset($relations[$key]) && $this->ifEntryChanged($record->getEntry($key))) {
188
                if ($record->getEntry($key)->isFromStorage()) {
189
                    $this->writeQueryBuilder->addCondition(
190
                        $record->getMapper()->getAlias(),
191
                        $relations[$key],
192
                        IQueryBuilder::OPERATION_EQ,
193
                        $item
194
                    );
195
                } else {
196
                    $this->writeQueryBuilder->addProperty(
197
                        $record->getMapper()->getAlias(),
198
                        $relations[$key],
199
                        $item
200
                    );
201
                }
202
            }
203
        }
204
205
        if (empty($this->writeQueryBuilder->getConditions())) { /// this one is questionable - I really want to update everything?
206
            return false;
207
        }
208
        if (empty($this->writeQueryBuilder->getProperties())) {
209
            return false;
210
        }
211
212
        return $this->writeDatabase->exec(
213
            $this->writeQueryBuilder,
214
            // @phpstan-ignore-next-line  expects MongoDB\Driver\BulkWrite, object|string given
215
            $this->writeDialect->update($this->writeQueryBuilder)
216
        );
217
    }
218
219
    protected function deleteRecord(ARecord $record): bool
220
    {
221
        $this->writeQueryBuilder->clear();
222
        $this->writeQueryBuilder->setBaseTable($record->getMapper()->getAlias());
223
        $relations = $record->getMapper()->getRelations();
224
225
        foreach ($record as $key => $item) {
226
            if (isset($relations[$key]) && $this->ifEntryChanged($record->getEntry($key))) {
227
                $this->writeQueryBuilder->addCondition(
228
                    $record->getMapper()->getAlias(),
229
                    $relations[$key],
230
                    IQueryBuilder::OPERATION_EQ,
231
                    $item
232
                );
233
            }
234
        }
235
236
        if (empty($this->writeQueryBuilder->getConditions())) { /// this one is necessary - delete everything? do it yourself - and manually!
237
            return false;
238
        }
239
240
        return $this->writeDatabase->exec(
241
            $this->writeQueryBuilder,
242
            // @phpstan-ignore-next-line  expects MongoDB\Driver\BulkWrite, object|string given
243
            $this->writeDialect->delete($this->writeQueryBuilder)
244
        );
245
    }
246
247
    protected function loadRecord(ARecord $record): bool
248
    {
249
        $this->fillConditions($record);
250
        $lines = $this->multiple();
251
        if (empty($lines) || empty($lines[0]) || !is_iterable($lines[0])) { // nothing found
252
            return false;
253
        }
254
255
        // fill entries in record
256
        $relations = $record->getMapper()->getRelations();
257
        $relationMap = array_flip($relations);
258
        foreach ($lines[0] as $index => $item) {
259
            $entry = $record->getEntry($relationMap[$index]);
260
            $entry->setData($this->typedFillSelection($entry, $item), true);
261
        }
262
        return true;
263
    }
264
265
    public function countRecord(ARecord $record): int
266
    {
267
        $this->fillConditions($record);
268
        return count($this->multiple());
269
    }
270
271
    public function loadMultiple(ARecord $record): array
272
    {
273
        $this->fillConditions($record);
274
        $lines = $this->multiple();
275
        if (empty($lines)) {
276
            return [];
277
        }
278
279
        $result = [];
280
        $relations = $record->getMapper()->getRelations();
281
        $relationMap = array_flip($relations);
282
        foreach ($lines as $key => $line) {
283
            if (is_numeric($key) && is_iterable($line)) {
284
                $rec = clone $record;
285
                foreach ($line as $index => $item) {
286
                    $entry = $rec->getEntry($relationMap[$index]);
287
                    $entry->setData($this->typedFillSelection($entry, $item), true);
288
                }
289
                $result[] = $rec;
290
            }
291
        }
292
        return $result;
293
    }
294
295
    /**
296
     * @param ARecord $record
297
     * @throws MapperException
298
     */
299
    protected function fillConditions(ARecord $record): void
300
    {
301
        $this->readQueryBuilder->clear();
302
        $this->readQueryBuilder->setBaseTable($record->getMapper()->getAlias());
303
        $relations = $record->getMapper()->getRelations();
304
305
        foreach ($record as $key => $item) {
306
            if (!$record->getEntry($key)->isFromStorage() && $this->ifEntryChanged($record->getEntry($key))) {
307
                $this->readQueryBuilder->addCondition(
308
                    $record->getMapper()->getAlias(),
309
                    $relations[$key],
310
                    IQueryBuilder::OPERATION_EQ,
311
                    strval($item)
312
                );
313
            }
314
        }
315
    }
316
317
    /**
318
     * @throws MapperException
319
     * @return array<string|int, string|int|float|array<string|int|float>>
320
     */
321
    protected function multiple(): array
322
    {
323
        return $this->readDatabase->query(
324
            $this->readQueryBuilder,
325
            // @phpstan-ignore-next-line  expects MongoDB\Driver\Query, object|string given
326
            $this->readDialect->select($this->readQueryBuilder)
327
        )->toArray();
328
    }
329
}
330