Completed
Push — master ( 6dfd8b...4e2354 )
by Saulius
04:35 queued 22s
created

PersistentBatchObjectsManager::setRefresh()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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