Test Failed
Pull Request — master (#2)
by Alex
04:49 queued 01:37
created

EntityManagerProvider::getEntityManager()   A

Complexity

Conditions 6
Paths 16

Size

Total Lines 22
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

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