Completed
Push — master ( 60f2df...616eb8 )
by Saulius
12s
created

PersistentBatchObjectsManager::fill()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
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 6
    public function __construct(
56
        EntityManagerInterface $entityManager,
57
        EventDispatcherInterface $eventDispatcher,
58
        BatchOperationCollectionInterface $batchOperations,
59
        LoggerInterface $logger
60
    ) {
61 6
        $this->entityManager = $entityManager;
62 6
        $this->eventDispatcher = $eventDispatcher;
63 6
        $this->batchOperations = $batchOperations;
64 6
        $this->logger = $logger;
65 6
    }
66
67 5
    public function save(): bool
68
    {
69 5
        return $this->process(PersistOperation::NAME);
70
    }
71
72 6
    private function process(string $operationName): bool
73
    {
74 6
        $this->checkManagerIsNotNull();
75 5
        $this->checkChunksIsNotEmpty();
76
77
        try {
78 4
            $self = $this;
79
            $this->entityManager->transactional(function () use ($operationName, $self) {
80 3
                $self->processChunks($operationName);
81 4
            });
82 2
            return true;
83 2
        } catch (\Throwable $exception) {
84 2
            $this->logger->critical($exception->getMessage(), [$exception]);
85 2
            return false;
86
        }
87
    }
88
89 6
    private function checkManagerIsNotNull(): void
90
    {
91 6
        if (null === $this->manager) {
92 1
            throw new ManagerNotFoundException(
93 1
                'Manager cannot be `null` maybe you forgot to assign it? To do so use `setManager` method'
94
            );
95
        }
96 5
    }
97
98 5
    private function checkChunksIsNotEmpty(): void
99
    {
100 5
        if (true === empty($this->chunks)) {
101 1
            throw new EmptyDataException(
102 1
                \sprintf('No data to work with maybe you forgot to fill?')
103
            );
104
        }
105 4
    }
106
107 3
    private function processChunks(string $operationName): void
108
    {
109 3
        $operation = $this->getOperationByName($operationName);
110
111 2
        foreach ($this->chunks as $chunk) {
112 2
            $event = new GenericDoctrineCollectionEvent($chunk);
113 2
            $this->eventDispatcher->dispatch($operation->getPreEventName(), $event);
114 2
            $this->processChunk($operation, $chunk);
115 2
            $this->entityManager->flush();
116 2
            $this->eventDispatcher->dispatch($operation->getPostEventName(), $event);
117 2
            $this->entityManager->clear();
118
        }
119 2
    }
120
121 3
    private function getOperationByName(string $operationName): OperationInterface
122
    {
123 3
        $operation = $this->batchOperations->get($operationName);
124
125 3
        if (null === $operation) {
126 1
            throw new OperationNotFoundException(sprintf('Batch operation `%s` was not found', $operationName));
127
        }
128
129 2
        return $operation;
130
    }
131
132 2
    private function processChunk(OperationInterface $operation, array $chunk): void
133
    {
134 2
        foreach ($chunk as $object) {
135 2
            $this->manager->checkObjectIntegrity($object);
136 2
            $operation->execute($object);
137
        }
138 2
    }
139
140 1
    public function remove(): bool
141
    {
142 1
        return $this->process(RemoveOperation::NAME);
143
    }
144
145 4
    public function fill(array $objects, int $batchSize): void
146
    {
147 4
        $this->chunks = $this->splitToChunks($objects, $batchSize);
148 4
    }
149
150 4
    private function splitToChunks(array $objects, int $batchSize): array
151
    {
152 4
        return \array_chunk($objects, $batchSize);
153
    }
154
155 5
    public function setManager(DoctrineEntityManagerInterface $manager): void
156
    {
157 5
        $this->manager = $manager;
158 5
    }
159
}
160