Completed
Push — master ( 52a24b...0631b2 )
by Alex
16s queued 13s
created

PersistService::save()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
c 1
b 0
f 0
dl 0
loc 6
rs 10
cc 2
nc 2
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Arp\LaminasDoctrine\Repository\Persistence;
6
7
use Arp\Entity\EntityInterface;
8
use Arp\LaminasDoctrine\Repository\Persistence\Exception\PersistenceException;
9
use Doctrine\ORM\EntityManagerInterface;
10
use Psr\Log\LoggerInterface;
11
12
/**
13
 * @implements PersistServiceInterface<EntityInterface>
14
 */
15
class PersistService implements PersistServiceInterface
16
{
17
    /**
18
     * @param class-string<EntityInterface> $entityName
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<EntityInterface> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<EntityInterface>.
Loading history...
19
     */
20
    public function __construct(
21
        protected readonly string $entityName,
22
        protected readonly EntityManagerInterface $entityManager,
23
        protected readonly LoggerInterface $logger
24
    ) {
25
    }
26
27
    /**
28
     * @return class-string<EntityInterface>
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<EntityInterface> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<EntityInterface>.
Loading history...
29
     */
30
    public function getEntityName(): string
31
    {
32
        return $this->entityName;
33
    }
34
35
    /**
36
     * @param array<string|int, mixed> $options
37
     *
38
     * @throws PersistenceException
39
     */
40
    public function save(EntityInterface $entity, array $options = []): EntityInterface
41
    {
42
        if ($entity->hasId()) {
43
            return $this->update($entity, $options);
44
        }
45
        return $this->insert($entity, $options);
46
    }
47
48
    /**
49
     * @param iterable<EntityInterface> $collection
50
     * @param array<string|int, mixed>  $options
51
     *
52
     * @return iterable<EntityInterface>
53
     *
54
     * @throws PersistenceException
55
     */
56
    public function saveCollection(iterable $collection, array $options = []): iterable
57
    {
58
        $transaction = (bool)($options['transaction'] ?? true);
59
        $flush = (bool)($options['flush'] ?? true);
60
61
        try {
62
            if ($transaction) {
63
                $this->beginTransaction();
64
            }
65
66
            $saveOptions = array_replace_recursive(
67
                [
68
                    'flush' => !$flush,
69
                    'transaction' => !$transaction,
70
                ],
71
                $options['entity_options'] ?? []
72
            );
73
74
            foreach ($collection as $entity) {
75
                $this->save($entity, $saveOptions);
76
            }
77
78
            if ($flush) {
79
                $this->entityManager->flush();
80
            }
81
82
            if ($transaction) {
83
                $this->commitTransaction();
84
            }
85
86
            return $collection;
87
        } catch (PersistenceException $e) {
88
            if ($transaction) {
89
                $this->rollbackTransaction();
90
            }
91
            throw $e;
92
        } catch (\Exception $e) {
93
            if ($transaction) {
94
                $this->rollbackTransaction();
95
            }
96
97
            $this->logger->error($e->getMessage(), ['exception' => $e, 'entity_name' => $this->entityName]);
98
99
            throw new PersistenceException(
100
                sprintf('Failed to save collection of type \'%s\'', $this->entityName),
101
                $e->getCode(),
102
                $e
103
            );
104
        }
105
    }
106
107
    /**
108
     * @param array<string|int, mixed> $options
109
     *
110
     * @throws PersistenceException
111
     */
112
    protected function update(EntityInterface $entity, array $options = []): EntityInterface
113
    {
114
        $transaction = (bool)($options['transaction'] ?? false);
115
        $flush = (bool)($options['flush'] ?? true);
116
117
        try {
118
            if ($transaction) {
119
                $this->beginTransaction();
120
            }
121
122
            if ($flush) {
123
                $this->entityManager->flush();
124
            }
125
126
            if ($transaction) {
127
                $this->commitTransaction();
128
            }
129
130
            return $entity;
131
        } catch (PersistenceException $e) {
132
            $this->rollbackTransaction();
133
            throw $e;
134
        } catch (\Exception $e) {
135
            if ($transaction) {
136
                $this->rollbackTransaction();
137
            }
138
139
            $this->logger->error($e->getMessage(), ['exception' => $e, 'entity_name' => $this->entityName]);
140
141
            throw new PersistenceException(
142
                sprintf('Failed to update entity of type \'%s\'', $this->entityName),
143
                $e->getCode(),
144
                $e
145
            );
146
        }
147
    }
148
149
    /**
150
     * @param array<string|int, mixed> $options
151
     *
152
     * @throws PersistenceException
153
     */
154
    protected function insert(EntityInterface $entity, array $options = []): EntityInterface
155
    {
156
        $transaction = (bool)($options['transaction'] ?? false);
157
        $flush = (bool)($options['flush'] ?? true);
158
159
        try {
160
            $this->entityManager->persist($entity);
161
162
            if ($transaction) {
163
                $this->beginTransaction();
164
            }
165
166
            if ($flush) {
167
                $this->flush();
168
            }
169
170
            if ($transaction) {
171
                $this->commitTransaction();
172
            }
173
174
            return $entity;
175
        } catch (PersistenceException $e) {
176
            if ($transaction) {
177
                $this->rollbackTransaction();
178
            }
179
            throw $e;
180
        } catch (\Exception $e) {
181
            if ($transaction) {
182
                $this->rollbackTransaction();
183
            }
184
185
            $this->logger->error($e->getMessage(), ['exception' => $e, 'entity_name' => $this->entityName]);
186
187
            throw new PersistenceException(
188
                sprintf('Failed to insert entity of type \'%s\'', $this->entityName),
189
                $e->getCode(),
190
                $e
191
            );
192
        }
193
    }
194
195
    /**
196
     * @param array<string|int, mixed> $options
197
     *
198
     * @throws PersistenceException
199
     */
200
    public function delete(EntityInterface $entity, array $options = []): bool
201
    {
202
        $transaction = (bool)($options['transaction'] ?? false);
203
        $flush = (bool)($options['flush'] ?? true);
204
205
        try {
206
            if ($transaction) {
207
                $this->beginTransaction();
208
            }
209
210
            $this->entityManager->remove($entity);
211
212
            if ($flush) {
213
                $this->flush();
214
            }
215
216
            if ($transaction) {
217
                $this->commitTransaction();
218
            }
219
220
            return true;
221
        } catch (PersistenceException $e) {
222
            if ($transaction) {
223
                $this->rollbackTransaction();
224
            }
225
            throw $e;
226
        } catch (\Exception $e) {
227
            if ($transaction) {
228
                $this->rollbackTransaction();
229
            }
230
231
            $this->logger->error($e->getMessage(), ['exception' => $e, 'entity_name' => $this->entityName]);
232
233
            throw new PersistenceException(
234
                sprintf('Failed to delete entity of type \'%s\'', $this->entityName),
235
                $e->getCode(),
236
                $e
237
            );
238
        }
239
    }
240
241
    /**
242
     * @param iterable<EntityInterface> $collection
243
     * @param array<string|int, mixed>  $options
244
     *
245
     * @throws PersistenceException
246
     */
247
    public function deleteCollection(iterable $collection, array $options = []): int
248
    {
249
        $transaction = (bool)($options['transaction'] ?? true);
250
        $flush = (bool)($options['flush'] ?? true);
251
252
        try {
253
            if ($transaction) {
254
                $this->beginTransaction();
255
            }
256
257
            $saveOptions = array_replace_recursive(
258
                [
259
                    'flush' => !$flush,
260
                    'transaction' => !$transaction,
261
                ],
262
                $options['entity_options'] ?? []
263
            );
264
265
            $deletedCount = 0;
266
            foreach ($collection as $entity) {
267
                if ($this->delete($entity, $saveOptions)) {
268
                    $deletedCount++;
269
                }
270
            }
271
272
            if ($flush) {
273
                $this->flush();
274
            }
275
276
            if ($transaction) {
277
                $this->commitTransaction();
278
            }
279
280
            return $deletedCount;
281
        } catch (\Exception $e) {
282
            if ($transaction) {
283
                $this->beginTransaction();
284
            }
285
286
            $this->logger->error($e->getMessage(), ['exception' => $e, 'entity_name' => $this->entityName]);
287
288
            throw new PersistenceException(
289
                sprintf('Failed to save collection of type \'%s\'', $this->entityName),
290
                $e->getCode(),
291
                $e
292
            );
293
        }
294
    }
295
296
    /**
297
     * @throws PersistenceException
298
     */
299
    public function flush(): void
300
    {
301
        try {
302
            $this->entityManager->flush();
303
        } catch (\Exception $e) {
304
            $this->logger->error($e->getMessage(), ['exception' => $e, 'entity_name' => $this->entityName]);
305
306
            throw new PersistenceException(
307
                sprintf('Failed to flush entity of type \'%s\'', $this->entityName),
308
                $e->getCode(),
309
                $e
310
            );
311
        }
312
    }
313
314
    /**
315
     * @throws PersistenceException
316
     */
317
    public function clear(): void
318
    {
319
        try {
320
            $this->entityManager->clear();
321
        } catch (\Exception $e) {
322
            $this->logger->error($e->getMessage(), ['exception' => $e, 'entity_name' => $this->entityName]);
323
324
            throw new PersistenceException(
325
                sprintf('The clear  operation failed for entity \'%s\'', $this->entityName),
326
                $e->getCode(),
327
                $e
328
            );
329
        }
330
    }
331
332
    /**
333
     * @throws PersistenceException
334
     */
335
    public function refresh(EntityInterface $entity): void
336
    {
337
        try {
338
            $this->entityManager->refresh($entity);
339
        } catch (\Exception $e) {
340
            $this->logger->error($e->getMessage(), ['exception' => $e, 'entity_name' => $this->entityName]);
341
342
            throw new PersistenceException(
343
                sprintf('The refresh operation failed for entity \'%s\'', $this->entityName),
344
                $e->getCode(),
345
                $e
346
            );
347
        }
348
    }
349
350
    /**
351
     * @throws PersistenceException
352
     */
353
    public function beginTransaction(): void
354
    {
355
        try {
356
            $this->entityManager->beginTransaction();
357
        } catch (\Exception $e) {
358
            $this->logger->error($e->getMessage(), ['exception' => $e, 'entity_name' => $this->entityName]);
359
360
            throw new PersistenceException(
361
                sprintf('Failed to start transaction for entity \'%s\'', $this->entityName),
362
                $e->getCode(),
363
                $e
364
            );
365
        }
366
    }
367
368
    /**
369
     * @throws PersistenceException
370
     */
371
    public function commitTransaction(): void
372
    {
373
        try {
374
            $this->entityManager->commit();
375
        } catch (\Exception $e) {
376
            $this->logger->error($e->getMessage(), ['exception' => $e, 'entity_name' => $this->entityName]);
377
378
            throw new PersistenceException(
379
                sprintf('Failed to commit transaction for entity \'%s\'', $this->entityName),
380
                $e->getCode(),
381
                $e
382
            );
383
        }
384
    }
385
386
    /**
387
     * @throws PersistenceException
388
     */
389
    public function rollbackTransaction(): void
390
    {
391
        try {
392
            $this->entityManager->rollback();
393
        } catch (\Exception $e) {
394
            $this->logger->error($e->getMessage(), ['exception' => $e, 'entity_name' => $this->entityName]);
395
396
            throw new PersistenceException(
397
                sprintf('Failed to rollback transaction for entity \'%s\'', $this->entityName),
398
                $e->getCode(),
399
                $e
400
            );
401
        }
402
    }
403
}
404