Passed
Push — master ( 79bf3c...52a24b )
by Alex
01:04 queued 13s
created

EntityManagerProvider::create()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 9
c 1
b 0
f 0
dl 0
loc 14
rs 9.9666
cc 4
nc 4
nop 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Arp\LaminasDoctrine\Service\EntityManager;
6
7
use Arp\LaminasDoctrine\Config\EntityManagerConfigs;
8
use Arp\LaminasDoctrine\Factory\Service\EntityManager\EntityManagerFactory;
9
use Arp\LaminasDoctrine\Service\ContainerInterface;
10
use Arp\LaminasDoctrine\Service\EntityManager\Exception\EntityManagerProviderException;
11
use Doctrine\ORM\EntityManagerInterface;
12
use Laminas\ServiceManager\Exception\ContainerModificationsNotAllowedException;
13
use Psr\Container\ContainerExceptionInterface;
14
15
/**
16
 * @author  Alex Patterson <[email protected]>
17
 * @package Arp\LaminasDoctrine\Service
18
 */
19
final class EntityManagerProvider implements EntityManagerProviderInterface
20
{
21
    /**
22
     * @var EntityManagerConfigs
23
     */
24
    private EntityManagerConfigs $configs;
25
26
    /**
27
     * @var ContainerInterface
28
     */
29
    private ContainerInterface $container;
30
31
    /**
32
     * @param EntityManagerConfigs                               $configs
33
     * @param ContainerInterface                                 $container
34
     * @param array<string, EntityManagerInterface|array<mixed>> $entityManagers
35
     *
36
     * @throws EntityManagerProviderException
37
     */
38
    public function __construct(
39
        EntityManagerConfigs $configs,
40
        ContainerInterface $container,
41
        array $entityManagers = []
42
    ) {
43
        $this->configs = $configs;
44
        $this->container = $container;
45
46
        $this->setEntityManagers($entityManagers);
47
    }
48
49
    /**
50
     * @param string $name
51
     *
52
     * @return EntityManagerInterface
53
     *
54
     * @throws EntityManagerProviderException
55
     */
56
    public function getEntityManager(string $name): EntityManagerInterface
57
    {
58
        try {
59
            if (!$this->container->has($name) && $this->configs->hasEntityManagerConfig($name)) {
60
                $this->container->setService(
61
                    $name,
62
                    $this->create($name, $this->configs->getEntityManagerConfig($name))
63
                );
64
            }
65
66
            if ($this->container->has($name)) {
67
                return $this->container->get($name);
68
            }
69
        } catch (EntityManagerProviderException $e) {
70
            throw $e;
71
        } catch (ContainerExceptionInterface $e) {
72
            throw new EntityManagerProviderException(
73
                sprintf('Failed retrieve entity manager \'%s\': %s', $name, $e->getMessage()),
74
                $e->getCode(),
75
                $e
76
            );
77
        }
78
79
        throw new EntityManagerProviderException(
80
            sprintf('Unable to find entity manager \'%s\'', $name)
81
        );
82
    }
83
84
    /**
85
     * @param string $name
86
     *
87
     * @return EntityManagerInterface
88
     *
89
     * @throws EntityManagerProviderException
90
     */
91
    public function refresh(string $name): EntityManagerInterface
92
    {
93
        $entityManager = $this->getEntityManager($name);
94
95
        if ($this->container->has($name)) {
96
            if ($entityManager->isOpen()) {
97
                $entityManager->close();
98
            }
99
100
            $entityManager = $this->create($name, $this->configs->getEntityManagerConfig($name));
101
102
            try {
103
                $this->container->setService($name, $entityManager);
104
            } catch (ContainerExceptionInterface $e) {
105
                throw new EntityManagerProviderException(
106
                    sprintf('Failed to set create service \'%s\': %s', $name, $e->getMessage()),
107
                    $e->getCode(),
108
                    $e
109
                );
110
            }
111
        }
112
113
        return $entityManager;
114
    }
115
116
    /**
117
     * Set the configuration options for a single entity manager with the provided $name
118
     *
119
     * @param string               $name
120
     * @param array<string, mixed> $config
121
     */
122
    public function setEntityManagerConfig(string $name, array $config): void
123
    {
124
        $this->configs->setEntityManagerConfig($name, $config);
125
    }
126
127
    /**
128
     * Check if the entity manager is registered with the provider
129
     *
130
     * @param string $name The name of the entity manager to check
131
     *
132
     * @return bool
133
     */
134
    public function hasEntityManager(string $name): bool
135
    {
136
        return $this->container->has($name) || $this->configs->hasEntityManagerConfig($name);
137
    }
138
139
    /**
140
     * @param string                 $name
141
     * @param EntityManagerInterface $entityManager
142
     *
143
     * @throws EntityManagerProviderException
144
     */
145
    public function setEntityManager(string $name, EntityManagerInterface $entityManager): void
146
    {
147
        try {
148
            $this->container->setService($name, $entityManager);
149
        } catch (ContainerModificationsNotAllowedException $e) {
150
            throw new EntityManagerProviderException(
151
                sprintf('Unable to set entity manager service \'%s\': %s', $name, $e->getMessage()),
152
                $e->getCode(),
153
                $e
154
            );
155
        }
156
    }
157
158
    /**
159
     * @param array<string, EntityManagerInterface|array<mixed>> $entityManagers
160
     *
161
     * @throws EntityManagerProviderException
162
     */
163
    public function setEntityManagers(array $entityManagers): void
164
    {
165
        foreach ($entityManagers as $name => $entityManager) {
166
            if (is_array($entityManager)) {
167
                $this->setEntityManagerConfig($name, $entityManager);
168
            } else {
169
                $this->setEntityManager($name, $entityManager);
170
            }
171
        }
172
    }
173
174
    /**
175
     * @param string               $name
176
     * @param array<string, mixed> $config
177
     * @param string|null          $factoryClassName
178
     *
179
     * @return EntityManagerInterface
180
     *
181
     * @throws EntityManagerProviderException
182
     */
183
    private function create(string $name, array $config, ?string $factoryClassName = null): EntityManagerInterface
184
    {
185
        // We must exclude calls from refresh() so we need to check
186
        if (!$this->container->has($name)) {
187
            $this->registerServiceFactory($name, $factoryClassName ?: EntityManagerFactory::class);
188
        }
189
190
        try {
191
            return $this->container->build($name, $config);
192
        } catch (ContainerExceptionInterface $e) {
193
            throw new EntityManagerProviderException(
194
                sprintf('Failed to create entity manager \'%s\' from configuration: %s', $name, $e->getMessage()),
195
                $e->getCode(),
196
                $e
197
            );
198
        }
199
    }
200
201
    /**
202
     * Add a manual factory service entry for entity manager $name, so we do not need to explicitly define it each
203
     * time with the 'entity_manager_container'
204
     *
205
     * @param string $name
206
     * @param string $factoryClassName
207
     *
208
     * @throws EntityManagerProviderException
209
     */
210
    private function registerServiceFactory(string $name, string $factoryClassName): void
211
    {
212
        try {
213
            $this->container->setFactory($name, $factoryClassName);
214
        } catch (ContainerModificationsNotAllowedException $e) {
215
            throw new EntityManagerProviderException(
216
                sprintf(
217
                    'Unable to set entity manager factory service \'%s\': %s',
218
                    $factoryClassName,
219
                    $e->getMessage()
220
                ),
221
                $e->getCode(),
222
                $e
223
            );
224
        }
225
    }
226
}
227