EntityManagerProvider::hasEntityManager()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 2
nc 2
nop 1
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
final class EntityManagerProvider implements EntityManagerProviderInterface
16
{
17
    /**
18
     * @param ContainerInterface<EntityManagerInterface> $container
19
     * @param array<string, EntityManagerInterface|array<mixed>> $entityManagers
20
     *
21
     * @throws EntityManagerProviderException
22
     */
23
    public function __construct(
24
        private readonly EntityManagerConfigs $configs,
25
        private readonly ContainerInterface $container,
26
        array $entityManagers = []
27
    ) {
28
        $this->setEntityManagers($entityManagers);
29
    }
30
31
    /**
32
     * @throws EntityManagerProviderException
33
     */
34
    public function getEntityManager(string $name): EntityManagerInterface
35
    {
36
        try {
37
            if (!$this->container->has($name) && $this->configs->hasEntityManagerConfig($name)) {
38
                $this->container->setService(
39
                    $name,
40
                    $this->create($name, $this->configs->getEntityManagerConfig($name))
41
                );
42
            }
43
44
            if ($this->container->has($name)) {
45
                return $this->container->get($name);
46
            }
47
        } catch (EntityManagerProviderException $e) {
48
            throw $e;
49
        } catch (ContainerExceptionInterface $e) {
50
            throw new EntityManagerProviderException(
51
                sprintf('Failed retrieve entity manager \'%s\': %s', $name, $e->getMessage()),
52
                $e->getCode(),
53
                $e
54
            );
55
        }
56
57
        throw new EntityManagerProviderException(
58
            sprintf('Unable to find entity manager \'%s\'', $name)
59
        );
60
    }
61
62
    /**
63
     * @throws EntityManagerProviderException
64
     */
65
    public function refresh(string $name): EntityManagerInterface
66
    {
67
        $entityManager = $this->getEntityManager($name);
68
69
        if ($this->container->has($name)) {
70
            if ($entityManager->isOpen()) {
71
                $entityManager->close();
72
            }
73
74
            $entityManager = $this->create($name, $this->configs->getEntityManagerConfig($name));
75
76
            try {
77
                $this->container->setService($name, $entityManager);
78
            } catch (ContainerExceptionInterface $e) {
79
                throw new EntityManagerProviderException(
80
                    sprintf('Failed to set create service \'%s\': %s', $name, $e->getMessage()),
81
                    $e->getCode(),
82
                    $e
83
                );
84
            }
85
        }
86
87
        return $entityManager;
88
    }
89
90
    /**
91
     * @param array<string, mixed> $config
92
     */
93
    public function setEntityManagerConfig(string $name, array $config): void
94
    {
95
        $this->configs->setEntityManagerConfig($name, $config);
96
    }
97
98
    public function hasEntityManager(string $name): bool
99
    {
100
        return $this->container->has($name) || $this->configs->hasEntityManagerConfig($name);
101
    }
102
103
    /**
104
     * @throws EntityManagerProviderException
105
     */
106
    public function setEntityManager(string $name, EntityManagerInterface $entityManager): void
107
    {
108
        try {
109
            $this->container->setService($name, $entityManager);
110
        } catch (ContainerModificationsNotAllowedException $e) {
111
            throw new EntityManagerProviderException(
112
                sprintf('Unable to set entity manager service \'%s\': %s', $name, $e->getMessage()),
113
                $e->getCode(),
114
                $e
115
            );
116
        }
117
    }
118
119
    /**
120
     * @param array<string, EntityManagerInterface|array<mixed>> $entityManagers
121
     *
122
     * @throws EntityManagerProviderException
123
     */
124
    public function setEntityManagers(array $entityManagers): void
125
    {
126
        foreach ($entityManagers as $name => $entityManager) {
127
            if (is_array($entityManager)) {
128
                $this->setEntityManagerConfig($name, $entityManager);
129
            } else {
130
                $this->setEntityManager($name, $entityManager);
131
            }
132
        }
133
    }
134
135
    /**
136
     * @param array<string, mixed> $config
137
     *
138
     * @throws EntityManagerProviderException
139
     */
140
    private function create(string $name, array $config, ?string $factoryClassName = null): EntityManagerInterface
141
    {
142
        // We must exclude calls from refresh() so we need to check
143
        if (!$this->container->has($name)) {
144
            $this->registerServiceFactory($name, $factoryClassName ?: EntityManagerFactory::class);
145
        }
146
147
        try {
148
            return $this->container->build($name, $config);
149
        } catch (ContainerExceptionInterface $e) {
150
            throw new EntityManagerProviderException(
151
                sprintf('Failed to create entity manager \'%s\' from configuration: %s', $name, $e->getMessage()),
152
                $e->getCode(),
153
                $e
154
            );
155
        }
156
    }
157
158
    /**
159
     * Add a manual factory service entry for entity manager $name, so we do not need to explicitly define it each
160
     * time with the 'entity_manager_container'
161
     *
162
     * @throws EntityManagerProviderException
163
     */
164
    private function registerServiceFactory(string $name, string $factoryClassName): void
165
    {
166
        try {
167
            $this->container->setFactory($name, $factoryClassName);
168
        } catch (ContainerModificationsNotAllowedException $e) {
169
            throw new EntityManagerProviderException(
170
                sprintf(
171
                    'Unable to set entity manager factory service \'%s\': %s',
172
                    $factoryClassName,
173
                    $e->getMessage()
174
                ),
175
                $e->getCode(),
176
                $e
177
            );
178
        }
179
    }
180
}
181