Passed
Pull Request — master (#2)
by Alex
24:05 queued 15:48
created

EntityManagerProvider::refresh()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 13
c 0
b 0
f 0
dl 0
loc 23
rs 9.8333
cc 4
nc 5
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Arp\LaminasDoctrine\Service\EntityManager;
6
7
use Arp\LaminasDoctrine\Config\DoctrineConfig;
8
use Arp\LaminasDoctrine\Factory\Service\EntityManagerFactory;
9
use Arp\LaminasDoctrine\Service\EntityManager\Exception\EntityManagerProviderException;
10
use Doctrine\ORM\EntityManagerInterface;
11
use Laminas\ServiceManager\Exception\ContainerModificationsNotAllowedException;
12
use Psr\Container\ContainerExceptionInterface;
13
14
/**
15
 * @author  Alex Patterson <[email protected]>
16
 * @package Arp\LaminasDoctrine\Service\EntityManager
17
 */
18
final class EntityManagerProvider implements EntityManagerProviderInterface
19
{
20
    /**
21
     * @var DoctrineConfig
22
     */
23
    private DoctrineConfig $config;
24
25
    /**
26
     * @var ContainerInterface
27
     */
28
    private ContainerInterface $container;
29
30
    /**
31
     * @param DoctrineConfig                              $config
32
     * @param ContainerInterface                          $container
33
     * @param array<string, EntityManagerInterface|array> $entityManagers
34
     *
35
     * @throws EntityManagerProviderException
36
     */
37
    public function __construct(DoctrineConfig $config, ContainerInterface $container, array $entityManagers = [])
38
    {
39
        $this->config = $config;
40
        $this->container = $container;
41
42
        $this->setEntityManagers($entityManagers);
43
    }
44
45
    /**
46
     * @param string $name
47
     *
48
     * @return EntityManagerInterface
49
     *
50
     * @throws EntityManagerProviderException
51
     */
52
    public function getEntityManager(string $name): EntityManagerInterface
53
    {
54
        try {
55
            if (!$this->container->has($name) && $this->config->hasEntityManagerConfig($name)) {
56
                $this->container->setService($name, $this->create($name, $this->config->getEntityManagerConfig($name)));
57
            }
58
59
            if ($this->container->has($name)) {
60
                return $this->container->get($name);
61
            }
62
        } catch (EntityManagerProviderException $e) {
63
            throw $e;
64
        } catch (ContainerExceptionInterface $e) {
65
            throw new EntityManagerProviderException(
66
                sprintf('Failed retrieve entity manager \'%s\': %s', $name, $e->getMessage()),
0 ignored issues
show
Bug introduced by
The method getMessage() does not exist on Psr\Container\ContainerExceptionInterface. It seems like you code against a sub-type of said class. However, the method does not exist in Psr\Container\NotFoundExceptionInterface or Interop\Container\Exception\ContainerException or Interop\Container\Exception\NotFoundException or Interop\Container\Exception\NotFoundException or Laminas\ServiceManager\E...tion\ExceptionInterface. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

66
                sprintf('Failed retrieve entity manager \'%s\': %s', $name, $e->/** @scrutinizer ignore-call */ getMessage()),
Loading history...
67
                $e->getCode(),
0 ignored issues
show
Bug introduced by
The method getCode() does not exist on Psr\Container\ContainerExceptionInterface. It seems like you code against a sub-type of said class. However, the method does not exist in Psr\Container\NotFoundExceptionInterface or Interop\Container\Exception\ContainerException or Interop\Container\Exception\NotFoundException or Interop\Container\Exception\NotFoundException or Laminas\ServiceManager\E...tion\ExceptionInterface. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

67
                $e->/** @scrutinizer ignore-call */ 
68
                    getCode(),
Loading history...
68
                $e
69
            );
70
        }
71
72
        throw new EntityManagerProviderException(
73
            sprintf('Unable to find entity manager \'%s\'', $name)
74
        );
75
    }
76
77
    /**
78
     * @param string $name
79
     *
80
     * @return EntityManagerInterface
81
     *
82
     * @throws EntityManagerProviderException
83
     */
84
    public function refresh(string $name): EntityManagerInterface
85
    {
86
        $entityManager = $this->getEntityManager($name);
87
88
        if ($this->container->has($name)) {
89
            if ($entityManager->isOpen()) {
90
                $entityManager->close();
91
            }
92
93
            $entityManager = $this->create($name, $this->config->getEntityManagerConfig($name));
94
95
            try {
96
                $this->container->setService($name, $entityManager);
97
            } catch (ContainerExceptionInterface $e) {
98
                throw new EntityManagerProviderException(
99
                    sprintf('Failed to set create service \'%s\': %s', $name, $e->getMessage()),
100
                    $e->getCode(),
101
                    $e
102
                );
103
            }
104
        }
105
106
        return $entityManager;
107
    }
108
109
    /**
110
     * Set the configuration options for a single entity manager with the provided $name
111
     *
112
     * @param string               $name
113
     * @param array<string, mixed> $config
114
     */
115
    public function setEntityManagerConfig(string $name, array $config): void
116
    {
117
        $this->config->setEntityManagerConfig($name, $config);
118
    }
119
120
    /**
121
     * Check if the entity manager is registered with the provider
122
     *
123
     * @param string $name The name of the entity manager to check
124
     *
125
     * @return bool
126
     */
127
    public function hasEntityManager(string $name): bool
128
    {
129
        return $this->container->has($name) || $this->config->hasEntityManagerConfig($name);
130
    }
131
132
    /**
133
     * @param string                 $name
134
     * @param EntityManagerInterface $entityManager
135
     *
136
     * @throws EntityManagerProviderException
137
     */
138
    public function setEntityManager(string $name, EntityManagerInterface $entityManager): void
139
    {
140
        try {
141
            $this->container->setService($name, $entityManager);
142
        } catch (ContainerModificationsNotAllowedException $e) {
143
            throw new EntityManagerProviderException(
144
                sprintf('Unable to set entity manager service \'%s\': %s', $name, $e->getMessage()),
145
                $e->getCode(),
146
                $e
147
            );
148
        }
149
    }
150
151
    /**
152
     * @param array<string, EntityManagerInterface|array> $entityManagers
153
     *
154
     * @throws EntityManagerProviderException
155
     */
156
    public function setEntityManagers(array $entityManagers): void
157
    {
158
        foreach ($entityManagers as $name => $entityManager) {
159
            if (is_array($entityManager)) {
160
                $this->setEntityManagerConfig($name, $entityManager);
161
            } else {
162
                $this->setEntityManager($name, $entityManager);
163
            }
164
        }
165
    }
166
167
    /**
168
     * @param string               $name
169
     * @param array<string, mixed> $config
170
     * @param string|null          $factoryClassName
171
     *
172
     * @return EntityManagerInterface
173
     *
174
     * @throws EntityManagerProviderException
175
     */
176
    private function create(string $name, array $config, ?string $factoryClassName = null): EntityManagerInterface
177
    {
178
        // We must exclude calls from refresh() so we need to check
179
        if (!$this->container->has($name)) {
180
            $this->registerServiceFactory($name, $factoryClassName ?: EntityManagerFactory::class);
181
        }
182
183
        try {
184
            return $this->container->build($name, $config);
185
        } catch (ContainerExceptionInterface $e) {
186
            throw new EntityManagerProviderException(
187
                sprintf('Failed to create entity manager \'%s\' from configuration: %s', $name, $e->getMessage()),
188
                $e->getCode(),
189
                $e
190
            );
191
        }
192
    }
193
194
    /**
195
     * Add a manual factory service entry for entity manager $name, so we do not need to explicitly define it each
196
     * time with the 'entity_manager_container'
197
     *
198
     * @param string $name
199
     * @param string $factoryClassName
200
     *
201
     * @throws EntityManagerProviderException
202
     */
203
    private function registerServiceFactory(string $name, string $factoryClassName): void
204
    {
205
        try {
206
            $this->container->setFactory($name, $factoryClassName);
207
        } catch (ContainerModificationsNotAllowedException $e) {
208
            throw new EntityManagerProviderException(
209
                sprintf(
210
                    'Unable to set entity manager factory service \'%s\': %s',
211
                    $factoryClassName,
212
                    $e->getMessage()
213
                ),
214
                $e->getCode(),
215
                $e
216
            );
217
        }
218
    }
219
}
220