EntityManagerProviderTest   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 393
Duplicated Lines 0 %

Importance

Changes 6
Bugs 1 Features 0
Metric Value
eloc 195
c 6
b 1
f 0
dl 0
loc 393
rs 10
wmc 16

12 Methods

Rating   Name   Duplication   Size   Complexity  
A testGetEntityManagerWillThrowEntityManagerProviderExceptionIfNotCreated() 0 45 1
A testImplementsEntityManagerProviderInterface() 0 5 1
A testGetEntityManagerWillThrowEntityManagerProviderExceptionIfNotFound() 0 20 1
A testSetAndGetEntityManagers() 0 33 3
A testGetEntityManagerWillReturnLazyLoadedEntityManagerByName() 0 41 1
A setUp() 0 5 1
A testRefresh() 0 45 1
A getHasData() 0 7 1
A testGetEntityManagerWillReturnEntityManagerByName() 0 19 1
A testHas() 0 20 3
A testSetAndGetEntityManager() 0 25 1
A testGetEntityManagerWillThrowEntityManagerProviderExceptionIfNotRetrieved() 0 27 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ArpTest\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\EntityManagerProvider;
11
use Arp\LaminasDoctrine\Service\EntityManager\EntityManagerProviderInterface;
12
use Arp\LaminasDoctrine\Service\EntityManager\Exception\EntityManagerProviderException;
13
use Doctrine\ORM\EntityManagerInterface;
14
use Laminas\ServiceManager\Exception\ServiceNotCreatedException;
15
use PHPUnit\Framework\MockObject\MockObject;
16
use PHPUnit\Framework\TestCase;
17
18
/**
19
 * @covers  \Arp\LaminasDoctrine\Service\EntityManager\EntityManagerProvider
20
 */
21
final class EntityManagerProviderTest extends TestCase
22
{
23
    /**
24
     * @var EntityManagerConfigs&MockObject
25
     */
26
    private EntityManagerConfigs $config;
27
28
    /**
29
     * @var ContainerInterface<EntityManagerInterface>&MockObject
30
     */
31
    private ContainerInterface $container;
32
33
    /**
34
     * Prepare the test case dependencies
35
     */
36
    public function setUp(): void
37
    {
38
        $this->config = $this->createMock(EntityManagerConfigs::class);
39
40
        $this->container = $this->createMock(ContainerInterface::class);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->createMock(Arp\La...tainerInterface::class) of type PHPUnit\Framework\MockObject\MockObject is incompatible with the declared type Arp\LaminasDoctrine\Service\ContainerInterface of property $container.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
41
    }
42
43
    /**
44
     * Assert the class is an instance of the EntityManagerProviderInterface
45
     *
46
     * @throws EntityManagerProviderException
47
     */
48
    public function testImplementsEntityManagerProviderInterface(): void
49
    {
50
        $provider = new EntityManagerProvider($this->config, $this->container);
51
52
        $this->assertInstanceOf(EntityManagerProviderInterface::class, $provider);
53
    }
54
55
    /**
56
     * Assert has() will return the expected boolean result
57
     *
58
     * @param bool $expected
59
     * @param bool $hasContainer
60
     * @param bool $hasConfig
61
     *
62
     * @dataProvider getHasData
63
     *
64
     * @throws EntityManagerProviderException
65
     */
66
    public function testHas(bool $expected, bool $hasContainer, bool $hasConfig): void
67
    {
68
        $name = 'FooServiceName';
69
        if ($hasContainer) {
70
            $this->container->expects($this->once())
0 ignored issues
show
Bug introduced by
The method expects() does not exist on Arp\LaminasDoctrine\Service\ContainerInterface. ( Ignorable by Annotation )

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

70
            $this->container->/** @scrutinizer ignore-call */ 
71
                              expects($this->once())

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
71
                ->method('has')
72
                ->with($name)
73
                ->willReturn(true);
74
        }
75
76
        if (!$hasContainer) {
77
            $this->config->expects($this->once())
0 ignored issues
show
Bug introduced by
The method expects() does not exist on Arp\LaminasDoctrine\Config\EntityManagerConfigs. ( Ignorable by Annotation )

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

77
            $this->config->/** @scrutinizer ignore-call */ 
78
                           expects($this->once())

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
78
                ->method('hasEntityManagerConfig')
79
                ->with($name)
80
                ->willReturn($hasConfig);
81
        }
82
83
        $provider = new EntityManagerProvider($this->config, $this->container);
84
85
        $this->assertSame($expected, $provider->hasEntityManager($name));
86
    }
87
88
    /**
89
     * @return array<mixed>
90
     */
91
    public function getHasData(): array
92
    {
93
        return [
94
            [true, true, true],
95
            [true, true, false],
96
            [true, false, true],
97
            [false, false, false],
98
        ];
99
    }
100
101
    /**
102
     * Assert that getCollection() will return a matching connection by name
103
     *
104
     * @throws EntityManagerProviderException
105
     */
106
    public function testGetEntityManagerWillReturnEntityManagerByName(): void
107
    {
108
        $provider = new EntityManagerProvider($this->config, $this->container);
109
110
        /** @var EntityManagerInterface|MockObject $entityManager */
111
        $entityManager = $this->createMock(EntityManagerInterface::class);
112
        $name = 'FooEntityManager';
113
114
        $this->container->expects($this->exactly(2))
115
            ->method('has')
116
            ->withConsecutive([$name], [$name])
117
            ->willReturn(true, true);
118
119
        $this->container->expects($this->once())
120
            ->method('get')
121
            ->with($name)
122
            ->willReturn($entityManager);
123
124
        $this->assertSame($entityManager, $provider->getEntityManager($name));
125
    }
126
127
    /**
128
     * Assert that a single entity manager can be set and then returned by its $name
129
     *
130
     * @throws EntityManagerProviderException
131
     */
132
    public function testSetAndGetEntityManager(): void
133
    {
134
        $provider = new EntityManagerProvider($this->config, $this->container);
135
136
        /** @var EntityManagerInterface&MockObject $entityManager */
137
        $entityManager = $this->createMock(EntityManagerInterface::class);
138
        $name = 'FooEntityManager';
139
140
        $this->container->expects($this->once())
141
            ->method('setService')
142
            ->with($name, $entityManager);
143
144
        $provider->setEntityManager($name, $entityManager);
145
146
        $this->container->expects($this->exactly(2))
147
            ->method('has')
148
            ->withConsecutive([$name], [$name])
149
            ->willReturnOnConsecutiveCalls(true, true);
150
151
        $this->container->expects($this->once())
152
            ->method('get')
153
            ->with($name)
154
            ->willReturn($entityManager);
155
156
        $this->assertSame($entityManager, $provider->getEntityManager($name));
157
    }
158
159
    /**
160
     * Assert that a multiple entity manager can be set and then returned by their names
161
     *
162
     * @throws EntityManagerProviderException
163
     */
164
    public function testSetAndGetEntityManagers(): void
165
    {
166
        /** @var array<mixed> $configs */
167
        $configs = [
168
            'foo' => $this->createMock(EntityManagerInterface::class),
169
            'bar' => $this->createMock(EntityManagerInterface::class),
170
            'test' => [
171
                'name' => 'hello',
172
                'test' => 'data',
173
                'active' => true,
174
            ],
175
        ];
176
177
        $provider = new EntityManagerProvider($this->config, $this->container);
178
179
        $setArgs = $configsArgs = [];
180
        foreach ($configs as $name => $config) {
181
            if (is_array($config)) {
182
                $configsArgs[] = [$name, $config];
183
            } else {
184
                $setArgs[] = [$name, $config];
185
            }
186
        }
187
188
        $this->container->expects($this->exactly(count($setArgs)))
189
            ->method('setService')
190
            ->withConsecutive(...$setArgs);
191
192
        $this->config->expects($this->exactly(count($configsArgs)))
193
            ->method('setEntityManagerConfig')
194
            ->withConsecutive(...$configsArgs);
195
196
        $provider->setEntityManagers($configs);
197
    }
198
199
    /**
200
     * Assert that getCollection() will return a connection by lazy loading the configuration
201
     *
202
     * @throws EntityManagerProviderException
203
     */
204
    public function testGetEntityManagerWillReturnLazyLoadedEntityManagerByName(): void
205
    {
206
        $provider = new EntityManagerProvider($this->config, $this->container);
207
208
        /** @var EntityManagerInterface&MockObject $entityManager */
209
        $entityManager = $this->createMock(EntityManagerInterface::class);
210
        $name = 'FooEntityManager';
211
        $config = [
212
            'foo' => 'bar',
213
        ];
214
215
        $this->container->expects($this->exactly(3))
216
            ->method('has')
217
            ->withConsecutive([$name], [$name], [$name])
218
            ->willReturn(false, false, true);
219
220
        $this->config->expects($this->once())
221
            ->method('hasEntityManagerConfig')
222
            ->with($name)
223
            ->willReturn(true);
224
225
        $this->config->expects($this->once())
226
            ->method('getEntityManagerConfig')
227
            ->with($name)
228
            ->willReturn($config);
229
230
        $this->container->expects($this->once())
231
            ->method('setFactory')
232
            ->with($name, EntityManagerFactory::class);
233
234
        $this->container->expects($this->once())
235
            ->method('build')
236
            ->with($name, $config)
237
            ->willReturn($entityManager);
238
239
        $this->container->expects($this->once())
240
            ->method('get')
241
            ->with($name)
242
            ->willReturn($entityManager);
243
244
        $this->assertSame($entityManager, $provider->getEntityManager($name));
245
    }
246
247
    /**
248
     * Assert a EntityManagerProviderException is thrown from getEntityManager() if the provided $name can not be
249
     * resolved to a valid entity manager instance
250
     *
251
     * @throws EntityManagerProviderException
252
     */
253
    public function testGetEntityManagerWillThrowEntityManagerProviderExceptionIfNotFound(): void
254
    {
255
        $provider = new EntityManagerProvider($this->config, $this->container);
256
257
        $name = 'EntityManagerTest';
258
259
        $this->container->expects($this->exactly(2))
260
            ->method('has')
261
            ->withConsecutive([$name], [$name])
262
            ->willReturnOnConsecutiveCalls(false, false);
263
264
        $this->config->expects($this->once())
265
            ->method('hasEntityManagerConfig')
266
            ->with($name)
267
            ->willReturn(false);
268
269
        $this->expectException(EntityManagerProviderException::class);
270
        $this->expectExceptionMessage(sprintf('Unable to find entity manager \'%s\'', $name));
271
272
        $provider->refresh($name);
273
    }
274
275
    /**
276
     * Assert a EntityManagerProviderException is thrown from getEntityManager() if the lazy loaded entity manager
277
     * cannot be created
278
     *
279
     * @throws EntityManagerProviderException
280
     */
281
    public function testGetEntityManagerWillThrowEntityManagerProviderExceptionIfNotCreated(): void
282
    {
283
        $provider = new EntityManagerProvider($this->config, $this->container);
284
285
        $name = 'EntityManagerTest';
286
        $config = [
287
            'foo' => 123,
288
            'bar' => 'Hello World!',
289
        ];
290
291
        $this->container->expects($this->exactly(2))
292
            ->method('has')
293
            ->withConsecutive([$name], [$name])
294
            ->willReturnOnConsecutiveCalls(false, false);
295
296
        $this->config->expects($this->once())
297
            ->method('hasEntityManagerConfig')
298
            ->with($name)
299
            ->willReturn(true);
300
301
        $this->config->expects($this->once())
302
            ->method('getEntityManagerConfig')
303
            ->with($name)
304
            ->willReturn($config);
305
306
        $this->container->expects($this->once())
307
            ->method('setFactory')
308
            ->with($name, EntityManagerFactory::class);
309
310
        $exceptionMessage = 'This is a test exception message for ' . __FUNCTION__;
311
        $exceptionCode = 12345;
312
        $exception = new ServiceNotCreatedException($exceptionMessage, $exceptionCode);
313
314
        $this->container->expects($this->once())
315
            ->method('build')
316
            ->with($name, $config)
317
            ->willThrowException($exception);
318
319
        $this->expectException(EntityManagerProviderException::class);
320
        $this->expectExceptionCode($exceptionCode);
321
        $this->expectExceptionMessage(
322
            sprintf('Failed to create entity manager \'%s\' from configuration: %s', $name, $exceptionMessage)
323
        );
324
325
        $provider->getEntityManager($name);
326
    }
327
328
    /**
329
     * Assert a EntityManagerProviderException is thrown from getEntityManager() if the lazy loaded entity manager
330
     * cannot be returned from the container
331
     *
332
     * @throws EntityManagerProviderException
333
     */
334
    public function testGetEntityManagerWillThrowEntityManagerProviderExceptionIfNotRetrieved(): void
335
    {
336
        $provider = new EntityManagerProvider($this->config, $this->container);
337
338
        $name = 'EntityManagerTest';
339
340
        $this->container->expects($this->exactly(2))
341
            ->method('has')
342
            ->withConsecutive([$name], [$name])
343
            ->willReturnOnConsecutiveCalls(true, true);
344
345
        $exceptionMessage = 'This is a test exception message for ' . __FUNCTION__;
346
        $exceptionCode = 54321;
347
        $exception = new ServiceNotCreatedException($exceptionMessage, $exceptionCode);
348
349
        $this->container->expects($this->once())
350
            ->method('get')
351
            ->with($name)
352
            ->willThrowException($exception);
353
354
        $this->expectException(EntityManagerProviderException::class);
355
        $this->expectExceptionCode($exceptionCode);
356
        $this->expectExceptionMessage(
357
            sprintf('Failed retrieve entity manager \'%s\': %s', $name, $exceptionMessage),
358
        );
359
360
        $provider->getEntityManager($name);
361
    }
362
363
    /**
364
     * Assert an EntityManager instance can be refreshed by closing the existing connection and creating a new
365
     * instance based on the configuration
366
     *
367
     * @throws EntityManagerProviderException
368
     */
369
    public function testRefresh(): void
370
    {
371
        $provider = new EntityManagerProvider($this->config, $this->container);
372
373
        $name = 'FooEntityManager';
374
375
        /** @var EntityManagerInterface&MockObject $entityManager */
376
        $entityManager = $this->createMock(EntityManagerInterface::class);
377
378
        /** @var EntityManagerInterface&MockObject $newInstance */
379
        $newInstance = $this->createMock(EntityManagerInterface::class);
380
381
        $config = [
382
            'foo' => 123,
383
            'bar' => 'test',
384
        ];
385
386
        $this->container->expects($this->exactly(4))
387
            ->method('has')
388
            ->withConsecutive([$name], [$name], [$name], [$name])
389
            ->willReturnOnConsecutiveCalls(true, true, true, true);
390
391
        $this->container->expects($this->once())
392
            ->method('get')
393
            ->with($name)
394
            ->willReturn($entityManager);
395
396
        $entityManager->expects($this->once())
397
            ->method('isOpen')
398
            ->willReturn(true);
399
400
        $entityManager->expects($this->once())
401
            ->method('close');
402
403
        $this->config->expects($this->once())
404
            ->method('getEntityManagerConfig')
405
            ->with($name)
406
            ->willReturn($config);
407
408
        $this->container->expects($this->once())
409
            ->method('build')
410
            ->with($name, $config)
411
            ->willReturn($newInstance);
412
413
        $this->assertSame($newInstance, $provider->refresh($name));
414
    }
415
}
416