Passed
Push — v1.x ( 9eac6f...b30d34 )
by Saulius
07:54
created

getOperationByName()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of the sauls/object-registry-bundle package.
4
 *
5
 * @author    Saulius Vaičeliūnas <[email protected]>
6
 * @link      http://saulius.vaiceliunas.lt
7
 * @copyright 2018
8
 *
9
 * For the full copyright and license information, please view the LICENSE
10
 * file that was distributed with this source code.
11
 */
12
13
namespace Sauls\Bundle\ObjectRegistryBundle\Manager;
14
15
use Doctrine\ORM\EntityManagerInterface;
16
use Psr\Log\LoggerInterface;
17
use Sauls\Bundle\ObjectRegistryBundle\Batch\Operation\OperationInterface;
18
use Sauls\Bundle\ObjectRegistryBundle\Batch\Operation\PersistOperation;
19
use Sauls\Bundle\ObjectRegistryBundle\Batch\Operation\RemoveOperation;
20
use Sauls\Bundle\ObjectRegistryBundle\Collection\BatchOperationCollectionInterface;
21
use Sauls\Bundle\ObjectRegistryBundle\Event\GenericDoctrineCollectionEvent;
22
use Sauls\Bundle\ObjectRegistryBundle\EventDispatcher\EventDispatcherInterface;
23
use Sauls\Bundle\ObjectRegistryBundle\Exception\EmptyDataException;
24
use Sauls\Bundle\ObjectRegistryBundle\Exception\ManagerNotFoundException;
25
use Sauls\Bundle\ObjectRegistryBundle\Exception\OperationNotFoundException;
26
27
class PersistentBatchObjectsManager implements PersistentBatchObjectsManagerInterface
28
{
29
    /**
30
     * @var array
31
     */
32
    private $chunks;
33
34
    /**
35
     * @var DoctrineEntityManagerInterface
36
     */
37
    private $manager;
38
    /**
39
     * @var EntityManagerInterface
40
     */
41
    private $entityManager;
42
    /**
43
     * @var EventDispatcherInterface
44
     */
45
    private $eventDispatcher;
46
    /**
47
     * @var LoggerInterface
48
     */
49
    private $logger;
50
    /**
51
     * @var BatchOperationCollectionInterface
52
     */
53
    private $batchOperations;
54
55
    public function __construct(
56
        EntityManagerInterface $entityManager,
57
        EventDispatcherInterface $eventDispatcher,
58
        BatchOperationCollectionInterface $batchOperations,
59
        LoggerInterface $logger
60
    ) {
61
        $this->entityManager = $entityManager;
62
        $this->eventDispatcher = $eventDispatcher;
63
        $this->batchOperations = $batchOperations;
64
        $this->logger = $logger;
65
    }
66
67
    public function save(): bool
68
    {
69
        return $this->process(PersistOperation::NAME);
70
    }
71
72
    private function process(string $operationName): bool
73
    {
74
        $this->checkManagerIsNotNull();
75
        $this->checkChunksIsNotEmpty();
76
77
        try {
78
            $self = $this;
79
            $this->entityManager->transactional(function () use ($operationName, $self) {
80
                $self->processChunks($operationName);
81
            });
82
            return true;
83
        } catch (\Throwable $exception) {
84
            $this->logger->critical($exception->getMessage(), [$exception]);
85
            return false;
86
        }
87
    }
88
89
    private function checkManagerIsNotNull(): void
90
    {
91
        if (null === $this->manager) {
92
            throw new ManagerNotFoundException(
93
                'Manager cannot be `null` maybe you forgot to assign it? To do so use `setManager` method'
94
            );
95
        }
96
    }
97
98
    private function checkChunksIsNotEmpty(): void
99
    {
100
        if (true === empty($this->chunks)) {
101
            throw new EmptyDataException(
102
                \sprintf('No data to work with maybe you forgot to fill?')
103
            );
104
        }
105
    }
106
107
    private function processChunks(string $operationName): void
108
    {
109
        $operation = $this->getOperationByName($operationName);
110
111
        foreach ($this->chunks as $chunk) {
112
            $event = new GenericDoctrineCollectionEvent($chunk);
113
            $this->eventDispatcher->dispatch($operation->getPreEventName(), $event);
114
            $this->processChunk($operation, $chunk);
115
            $this->entityManager->flush();
116
            $this->eventDispatcher->dispatch($operation->getPostEventName(), $event);
117
            $this->entityManager->clear();
118
        }
119
    }
120
121
    private function getOperationByName(string $operationName): OperationInterface
122
    {
123
        $operation = $this->batchOperations->get($operationName);
124
125
        if (null === $operation) {
126
            throw new OperationNotFoundException(sprintf('Batch operation `%s` was not found', $operationName));
127
        }
128
129
        return $operation;
130
    }
131
132
    private function processChunk(OperationInterface $operation, array $chunk): void
133
    {
134
        foreach ($chunk as $object) {
135
            $this->manager->checkObjectIntegrity($object);
136
            $operation->execute($object);
137
        }
138
    }
139
140
    public function remove(): bool
141
    {
142
        return $this->process(RemoveOperation::NAME);
143
    }
144
145
    public function fill(array $objects, int $batchSize): void
146
    {
147
        $this->chunks = $this->splitToChunks($objects, $batchSize);
148
    }
149
150
    private function splitToChunks(array $objects, int $batchSize): array
151
    {
152
        return \array_chunk($objects, $batchSize);
153
    }
154
155
    public function setManager(DoctrineEntityManagerInterface $manager): void
156
    {
157
        $this->manager = $manager;
158
    }
159
}
160