AMongo   B
last analyzed

Complexity

Total Complexity 48

Size/Duplication

Total Lines 298
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 127
c 1
b 0
f 0
dl 0
loc 298
rs 8.5599
wmc 48

22 Methods

Rating   Name   Duplication   Size   Complexity  
A getReadDatabase() 0 4 1
A getReadQueryBuilder() 0 3 1
A fillConditions() 0 13 4
A setWriteSource() 0 3 1
A loadMultiple() 0 22 6
A getWriteQueryBuilder() 0 3 1
A __construct() 0 6 1
A countRecord() 0 4 1
A setReadSource() 0 3 1
A deleteRecord() 0 25 5
A getWriteSource() 0 3 1
A getAlias() 0 3 1
A getReadDialect() 0 3 1
A initReadDatabase() 0 5 1
A multiple() 0 7 1
B updateRecord() 0 36 7
A initWriteDatabase() 0 5 1
A getWriteDialect() 0 3 1
A getReadSource() 0 3 1
A loadRecord() 0 16 5
A getWriteDatabase() 0 4 1
A insertRecord() 0 24 5

How to fix   Complexity   

Complex Class

Complex classes like AMongo often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AMongo, and based on these observations, apply Extract Interface, too.

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