Completed
Push — master ( e03816...0f0d76 )
by
unknown
03:02
created

NOSQLActiveRecord::getDtoCopy()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
namespace NOSQL\Models;
3
4
use MongoDB\BSON\ObjectId;
5
use MongoDB\Database;
6
use NOSQL\Dto\Model\NOSQLModelDto;
7
use NOSQL\Exceptions\NOSQLValidationException;
8
use NOSQL\Models\base\NOSQLModelTrait;
9
use NOSQL\Models\base\NOSQLParserTrait;
10
use NOSQL\Services\ParserService;
11
use PSFS\base\Logger;
12
use PSFS\base\types\traits\SingletonTrait;
13
14
/**
15
 * Class NOSQLActiveRecord
16
 * @package NOSQL\Models
17
 */
18
abstract class NOSQLActiveRecord {
19
    use NOSQLModelTrait;
20
    use NOSQLParserTrait;
21
    use SingletonTrait;
22
23
    /**
24
     * NOSQLActiveRecord constructor.
25
     * @throws \NOSQL\Exceptions\NOSQLParserException
26
     * @throws \PSFS\base\exception\GeneratorException
27
     */
28
    public function __construct()
29
    {
30
        $this->hydrate();
31
    }
32
33
    /**
34
     * @return array
35
     */
36
    public function toArray() {
37
        return $this->dto->toArray();
38
    }
39
40
    /**
41
     * @param bool $cleanPk
42
     * @return \NOSQL\Dto\Model\NOSQLModelDto
43
     */
44
    public function getDtoCopy($cleanPk = false) {
45
        $copy = clone $this->dto;
46
        if($cleanPk) {
47
            $this->dto->resetPk();
48
        }
49
        return $copy;
50
    }
51
52
    private function prepareData() {
53
        $this->dto->validate(true);
54
    }
55
56
    /**
57
     * @param Database|null $con
58
     * @return bool
59
     */
60
    public function save(Database $con = null) {
61
        $saved = false;
62
        if(null === $con) {
63
            $con = ParserService::getInstance()->createConnection($this->getDomain());
64
        }
65
        $collection = $con->selectCollection($this->getSchema()->name);
66
        try {
67
            $isInsert = $isUpdate = false;
68
            $this->prepareData();
69
            $this->dto->setLastUpdate();
70
            if($this->isNew()) {
71
                $this->preInsert($con);
72
                $isInsert = true;
73
            } elseif ($this->isModified()) {
74
                $this->preUpdate($con);
75
                $isUpdate = true;
76
            }
77
            $result = $collection->insertOne($this->toArray());
78
            if($result->getInsertedCount() > 0) {
79
                $id = $result->getInsertedId();
80
                $this->dto->setPk($id->jsonSerialize()['$oid']);
81
                if($isInsert) {
82
                    $this->postInsert($con);
83
                } elseif($isUpdate) {
84
                    $this->postUpdate($con);
85
                }
86
                $saved = true;
87
                $this->countAction();
88
            }
89
        } catch(\Exception $exception) {
90
            if($exception instanceof NOSQLValidationException) {
91
                throw $exception;
92
            } else {
93
                Logger::log($exception->getMessage(), LOG_CRIT, $this->toArray());
94
            }
95
        }
96
        return $saved;
97
    }
98
99
    /**
100
     * @param Database|null $con
101
     * @return bool
102
     */
103
    public function update(Database $con = null) {
104
        $updated = false;
105
        if(null === $con) {
106
            $con = ParserService::getInstance()->createConnection($this->getDomain());
107
        }
108
        $collection = $con->selectCollection($this->getSchema()->name);
109
        try {
110
            $this->prepareData();
111
            $this->dto->setLastUpdate();
112
            $this->preUpdate($con);
113
            $data = $this->toArray();
114
            unset($data['_id']);
115
            $collection->findOneAndReplace(['_id' => new ObjectId($this->dto->getPk())], $data);
116
            $this->postUpdate($con);
117
            $updated = true;
118
            $this->countAction();
119
        } catch(\Exception $exception) {
120
            if($exception instanceof NOSQLValidationException) {
121
                throw $exception;
122
            } else {
123
                Logger::log($exception->getMessage(), LOG_CRIT, $this->toArray());
124
            }
125
        }
126
        return $updated;
127
    }
128
129
    /**
130
     * @param array $data
131
     * @param Database|null $con
132
     * @return int
133
     */
134
    public function bulkInsert(array $data, Database $con = null) {
135
        $inserts = 0;
136
        if(null === $con) {
137
            $con = ParserService::getInstance()->createConnection($this->getDomain());
138
        }
139
        $collection = $con->selectCollection($this->getSchema()->name);
140
        try {
141
            [$dtos, $data] = $this->prepareInsertDtos($data, $con);
142
            $result = $collection->insertMany($data);
143
            $ids = $result->getInsertedIds();
144
            $inserts = $this->parseInsertedDtos($con, $ids, $dtos);
145
            $this->setActionCount($inserts);
146
        } catch(\Exception $exception) {
147
            Logger::log($exception->getMessage(), LOG_CRIT, $this->toArray());
148
        }
149
        return $inserts;
150
    }
151
152
    /**
153
     * Function to make a bulk upsert of documents
154
     * @param array $data
155
     * @param string $id
156
     * @param Database|null $con
157
     * @return int
158
     */
159
    public function bulkUpsert(array $data, $id, Database $con = null) {
160
        $upserts = 0;
161
        $filters = $options = [];
162
163
        if(null === $con) {
164
            $con = ParserService::getInstance()->createConnection($this->getDomain());
165
        }
166
        $collection = $con->selectCollection($this->getSchema()->name);
167
168
        foreach($data as $item) {
169
            try {
170
                $filters[$id] = ['$eq' => $item[$id]];
171
                $updateSet = [];
172
                $updateSet['$set'] = $item;
173
                $options['upsert'] = true;
174
175
                $updated = $collection->updateOne($filters, $updateSet, $options);
176
177
                if (null !== $updated) {
178
                    $upserts += $updated->getModifiedCount();
179
                }
180
            } catch (\Exception $exception) {
181
                Logger::log($exception->getMessage(), LOG_CRIT, $this->toArray());
182
            }
183
        }
184
185
        return $upserts;
186
    }
187
188
    /**
189
     * @param Database|null $con
190
     * @return bool
191
     */
192
    public function delete(Database $con = null) {
193
        $deleted = false;
194
        if(null === $con) {
195
            $con = ParserService::getInstance()->createConnection($this->getDomain());
196
        }
197
        $collection = $con->selectCollection($this->getSchema()->name);
198
        try {
199
            $this->preDelete($con);
200
            $collection->deleteOne(['_id' => new ObjectId($this->dto->getPk())]);
201
            $this->postDelete($con);
202
            $deleted = true;
203
            $this->dto = null;
204
            $this->countAction();
205
        } catch(\Exception $exception) {
206
            Logger::log($exception->getMessage(), LOG_CRIT, $this->toArray());
207
        }
208
        return $deleted;
209
    }
210
211
    /**
212
     * Function to make a bulk delete of documents
213
     * @param array $filters
214
     * @param Database|null $con
215
     * @return int
216
     */
217
    public function bulkDelete(array $filters, Database $con = null) {
218
        $deletedCount = 0;
219
        if(null === $con) {
220
            $con = ParserService::getInstance()->createConnection($this->getDomain());
221
        }
222
        $collection = $con->selectCollection($this->getSchema()->name);
223
        try {
224
            $result = $collection->deleteMany($filters);
225
            $deletedCount = $result->getDeletedCount();
226
        } catch(\Exception $exception) {
227
            Logger::log($exception->getMessage(), LOG_CRIT, $this->toArray());
228
        }
229
        return $deletedCount;
230
    }
231
232
    /**
233
     * @param array $data
234
     * @param Database $con
235
     * @return array
236
     * @throws \NOSQL\Exceptions\NOSQLValidationException
237
     */
238
    private function prepareInsertDtos(array $data, Database $con)
239
    {
240
        $dtos = [];
241
        /** @var NOSQLModelDto $dto */
242
        foreach ($data as &$insertData) {
243
            if(is_object($insertData) && $insertData instanceof NOSQLModelDto) {
244
                $dto = clone $insertData;
245
            } else {
246
                $dto = $this->getDtoCopy(true);
247
                $dto->fromArray($insertData);
248
            }
249
            $dto->validate();
250
            $dto->setLastUpdate();
251
            self::invokeHook($this, $dto, 'preInsert', $con);
252
            self::invokeHook($this, $dto, 'preSave', $con);
253
            $dtos[] = $dto;
254
            $insertData = $dto->toArray();
255
        }
256
        unset($dto);
257
        return [$dtos, $data];
258
    }
259
260
    /**
261
     * @param Database $con
262
     * @param ObjectId[] $ids
263
     * @param NOSQLModelDto[] $dtos
264
     * @return int
265
     * @throws \NOSQL\Exceptions\NOSQLValidationException
266
     */
267
    private function parseInsertedDtos(Database $con, $ids, $dtos)
268
    {
269
        $inserts = 0;
270
        foreach ($ids as $index => $insertedId) {
271
            $id = $insertedId->jsonSerialize();
0 ignored issues
show
Bug introduced by
The method jsonSerialize() does not exist on MongoDB\BSON\ObjectId. ( Ignorable by Annotation )

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

271
            /** @scrutinizer ignore-call */ 
272
            $id = $insertedId->jsonSerialize();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
272
            $dto = $dtos[$index];
273
            if($dto instanceof  NOSQLModelDto) {
274
                $dto->setPk($id['$oid']);
275
            } else {
276
277
            }
278
            self::invokeHook($this, $dtos[$index], 'postInsert', $con);
279
            self::invokeHook($this, $dtos[$index], 'postSave', $con);
280
            $inserts++;
281
        }
282
        return $inserts;
283
    }
284
}