Completed
Pull Request — master (#1203)
by
unknown
04:38
created

testSingleEntityManagerWithDefaultConfiguration()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 9.552
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
3
namespace Doctrine\Bundle\DoctrineBundle\Tests\DependencyInjection;
4
5
use Doctrine\Bundle\DoctrineBundle\DependencyInjection\DoctrineExtension;
6
use Doctrine\Bundle\DoctrineBundle\Tests\Builder\BundleConfigurationBuilder;
7
use Doctrine\DBAL\Connection;
8
use Doctrine\DBAL\Driver\Connection as DriverConnection;
9
use Doctrine\ORM\EntityManagerInterface;
10
use InvalidArgumentException;
11
use PHPUnit\Framework\TestCase;
12
use Symfony\Bridge\Doctrine\Messenger\DoctrineClearEntityManagerWorkerSubscriber;
13
use Symfony\Component\Cache\Adapter\ArrayAdapter;
14
use Symfony\Component\Cache\DoctrineProvider;
15
use Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass;
16
use Symfony\Component\DependencyInjection\ContainerBuilder;
17
use Symfony\Component\DependencyInjection\Definition;
18
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
19
use Symfony\Component\DependencyInjection\Reference;
20
use Symfony\Component\Messenger\MessageBusInterface;
21
22
class DoctrineExtensionTest extends TestCase
23
{
24
    /**
25
     * https://github.com/doctrine/orm/pull/7953 needed, otherwise ORM classes we define services for trigger deprecations
26
     *
27
     * @group legacy
28
     */
29
    public function testAutowiringAlias() : void
30
    {
31
        if (! interface_exists(EntityManagerInterface::class)) {
32
            self::markTestSkipped('This test requires ORM');
33
        }
34
35
        $container = $this->getContainer();
36
        $extension = new DoctrineExtension();
37
        $config    = BundleConfigurationBuilder::createBuilderWithBaseValues()->build();
38
39
        $extension->load([$config], $container);
40
41
        $expectedAliases = [
42
            DriverConnection::class => 'database_connection',
43
            Connection::class => 'database_connection',
44
            EntityManagerInterface::class => 'doctrine.orm.entity_manager',
45
        ];
46
47
        foreach ($expectedAliases as $id => $target) {
48
            $this->assertTrue($container->hasAlias($id), sprintf('The container should have a `%s` alias for autowiring support.', $id));
49
50
            $alias = $container->getAlias($id);
51
            $this->assertEquals($target, (string) $alias, sprintf('The autowiring for `%s` should use `%s`.', $id, $target));
52
            $this->assertFalse($alias->isPublic(), sprintf('The autowiring alias for `%s` should be private.', $id, $target));
53
        }
54
    }
55
56
    public function testPublicServicesAndAliases() : void
57
    {
58
        if (! interface_exists(EntityManagerInterface::class)) {
59
            self::markTestSkipped('This test requires ORM');
60
        }
61
62
        $container = $this->getContainer();
63
        $extension = new DoctrineExtension();
64
        $config    = BundleConfigurationBuilder::createBuilderWithBaseValues()->build();
65
66
        $extension->load([$config], $container);
67
68
        $this->assertTrue($container->getDefinition('doctrine')->isPublic());
69
        $this->assertTrue($container->getAlias('doctrine.orm.entity_manager')->isPublic());
70
        $this->assertTrue($container->getAlias('database_connection')->isPublic());
71
    }
72
73
    public function testDbalGenerateDefaultConnectionConfiguration() : void
74
    {
75
        $container = $this->getContainer();
76
        $extension = new DoctrineExtension();
77
78
        $container->registerExtension($extension);
79
80
        $extension->load([['dbal' => []]], $container);
81
82
        // doctrine.dbal.default_connection
83
        $this->assertEquals('%doctrine.default_connection%', $container->getDefinition('doctrine')->getArgument(3));
84
        $this->assertEquals('default', $container->getParameter('doctrine.default_connection'));
85
        $this->assertEquals('root', $container->getDefinition('doctrine.dbal.default_connection')->getArgument(0)['user']);
86
        $this->assertNull($container->getDefinition('doctrine.dbal.default_connection')->getArgument(0)['password']);
87
        $this->assertEquals('localhost', $container->getDefinition('doctrine.dbal.default_connection')->getArgument(0)['host']);
88
        $this->assertNull($container->getDefinition('doctrine.dbal.default_connection')->getArgument(0)['port']);
89
        $this->assertEquals('pdo_mysql', $container->getDefinition('doctrine.dbal.default_connection')->getArgument(0)['driver']);
90
        $this->assertEquals([], $container->getDefinition('doctrine.dbal.default_connection')->getArgument(0)['driverOptions']);
91
    }
92
93
    public function testDbalOverrideDefaultConnection() : void
94
    {
95
        $container = $this->getContainer();
96
        $extension = new DoctrineExtension();
97
98
        $container->registerExtension($extension);
99
100
        $extension->load([[], ['dbal' => ['default_connection' => 'foo']], []], $container);
101
102
        // doctrine.dbal.default_connection
103
        $this->assertEquals('%doctrine.default_connection%', $container->getDefinition('doctrine')->getArgument(3), '->load() overrides existing configuration options');
104
        $this->assertEquals('foo', $container->getParameter('doctrine.default_connection'), '->load() overrides existing configuration options');
105
    }
106
107
    /**
108
     * @expectedException \LogicException
109
     * @expectedExceptionMessage Configuring the ORM layer requires to configure the DBAL layer as well.
110
     */
111
    public function testOrmRequiresDbal() : void
112
    {
113
        if (! interface_exists(EntityManagerInterface::class)) {
114
            self::markTestSkipped('This test requires ORM');
115
        }
116
117
        $extension = new DoctrineExtension();
118
119
        $extension->load([['orm' => ['auto_mapping' => true]]], $this->getContainer());
120
    }
121
122
    public function getAutomappingConfigurations() : array
123
    {
124
        return [
125
            [
126
                [
127
                    'em1' => [
128
                        'mappings' => ['YamlBundle' => null],
129
                    ],
130
                    'em2' => [
131
                        'mappings' => ['XmlBundle' => null],
132
                    ],
133
                ],
134
            ],
135
            [
136
                [
137
                    'em1' => ['auto_mapping' => true],
138
                    'em2' => [
139
                        'mappings' => ['XmlBundle' => null],
140
                    ],
141
                ],
142
            ],
143
            [
144
                [
145
                    'em1' => [
146
                        'auto_mapping' => true,
147
                        'mappings' => ['YamlBundle' => null],
148
                    ],
149
                    'em2' => [
150
                        'mappings' => ['XmlBundle' => null],
151
                    ],
152
                ],
153
            ],
154
        ];
155
    }
156
157
    /**
158
     * @dataProvider getAutomappingConfigurations
159
     */
160
    public function testAutomapping(array $entityManagers) : void
161
    {
162
        if (! interface_exists(EntityManagerInterface::class)) {
163
            self::markTestSkipped('This test requires ORM');
164
        }
165
166
        $extension = new DoctrineExtension();
167
168
        $container = $this->getContainer([
0 ignored issues
show
Documentation introduced by
array('YamlBundle', 'XmlBundle') is of type array<integer,string,{"0":"string","1":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
169
            'YamlBundle',
170
            'XmlBundle',
171
        ]);
172
173
        $extension->load(
174
            [
175
                [
176
                    'dbal' => [
177
                        'default_connection' => 'cn1',
178
                        'connections' => [
179
                            'cn1' => [],
180
                            'cn2' => [],
181
                        ],
182
                    ],
183
                    'orm' => ['entity_managers' => $entityManagers],
184
                ],
185
            ],
186
            $container
187
        );
188
189
        $configEm1 = $container->getDefinition('doctrine.orm.em1_configuration');
190
        $configEm2 = $container->getDefinition('doctrine.orm.em2_configuration');
191
192
        $this->assertContains(
193
            [
194
                'setEntityNamespaces',
195
                [
196
                    ['YamlBundle' => 'Fixtures\Bundles\YamlBundle\Entity'],
197
                ],
198
            ],
199
            $configEm1->getMethodCalls()
200
        );
201
202
        $this->assertContains(
203
            [
204
                'setEntityNamespaces',
205
                [
206
                    ['XmlBundle' => 'Fixtures\Bundles\XmlBundle\Entity'],
207
                ],
208
            ],
209
            $configEm2->getMethodCalls()
210
        );
211
    }
212
213
    public function testDbalLoad() : void
214
    {
215
        $container = $this->getContainer();
216
        $extension = new DoctrineExtension();
217
218
        $extension->load([
219
            ['dbal' => ['connections' => ['default' => ['password' => 'foo']]]],
220
            [],
221
            ['dbal' => ['default_connection' => 'foo']],
222
            [],
223
        ], $container);
224
225
        $config = $container->getDefinition('doctrine.dbal.default_connection')->getArgument(0);
226
227
        $this->assertEquals('foo', $config['password']);
228
        $this->assertEquals('root', $config['user']);
229
    }
230
231
    public function testDbalWrapperClass() : void
232
    {
233
        $container = $this->getContainer();
234
        $extension = new DoctrineExtension();
235
236
        $extension->load(
237
            [
238
                [
239
                    'dbal' => [
240
                        'connections' => [
241
                            'default' => ['password' => 'foo', 'wrapper_class' => TestWrapperClass::class],
242
                            'second' => ['password' => 'boo'],
243
                        ],
244
                    ],
245
                ],
246
                [],
247
                ['dbal' => ['default_connection' => 'foo']],
248
                [],
249
            ],
250
            $container
251
        );
252
253
        $this->assertEquals(TestWrapperClass::class, $container->getDefinition('doctrine.dbal.default_connection')->getClass());
254
        $this->assertNull($container->getDefinition('doctrine.dbal.second_connection')->getClass());
255
    }
256
257
    public function testDependencyInjectionConfigurationDefaults() : void
258
    {
259
        if (! interface_exists(EntityManagerInterface::class)) {
260
            self::markTestSkipped('This test requires ORM');
261
        }
262
263
        $container = $this->getContainer();
264
        $extension = new DoctrineExtension();
265
        $config    = BundleConfigurationBuilder::createBuilderWithBaseValues()->build();
266
267
        $extension->load([$config], $container);
268
269
        $this->assertFalse($container->getParameter('doctrine.orm.auto_generate_proxy_classes'));
270
        $this->assertEquals('Doctrine\ORM\Configuration', $container->getParameter('doctrine.orm.configuration.class'));
271
        $this->assertEquals('Doctrine\ORM\EntityManager', $container->getParameter('doctrine.orm.entity_manager.class'));
272
        $this->assertEquals('Proxies', $container->getParameter('doctrine.orm.proxy_namespace'));
273
        $this->assertEquals('Doctrine\Common\Cache\ArrayCache', $container->getParameter('doctrine.orm.cache.array.class'));
274
        $this->assertEquals('Doctrine\Common\Cache\ApcCache', $container->getParameter('doctrine.orm.cache.apc.class'));
275
        $this->assertEquals('Doctrine\Common\Cache\MemcacheCache', $container->getParameter('doctrine.orm.cache.memcache.class'));
276
        $this->assertEquals('localhost', $container->getParameter('doctrine.orm.cache.memcache_host'));
277
        $this->assertEquals('11211', $container->getParameter('doctrine.orm.cache.memcache_port'));
278
        $this->assertEquals('Memcache', $container->getParameter('doctrine.orm.cache.memcache_instance.class'));
279
        $this->assertEquals('Doctrine\Common\Cache\XcacheCache', $container->getParameter('doctrine.orm.cache.xcache.class'));
280
        $this->assertEquals('Doctrine\Persistence\Mapping\Driver\MappingDriverChain', $container->getParameter('doctrine.orm.metadata.driver_chain.class'));
281
        $this->assertEquals('Doctrine\ORM\Mapping\Driver\AnnotationDriver', $container->getParameter('doctrine.orm.metadata.annotation.class'));
282
        $this->assertEquals('Doctrine\ORM\Mapping\Driver\SimplifiedXmlDriver', $container->getParameter('doctrine.orm.metadata.xml.class'));
283
        $this->assertEquals('Doctrine\ORM\Mapping\Driver\SimplifiedYamlDriver', $container->getParameter('doctrine.orm.metadata.yml.class'));
284
285
        // second-level cache
286
        $this->assertEquals('Doctrine\ORM\Cache\DefaultCacheFactory', $container->getParameter('doctrine.orm.second_level_cache.default_cache_factory.class'));
287
        $this->assertEquals('Doctrine\ORM\Cache\Region\DefaultRegion', $container->getParameter('doctrine.orm.second_level_cache.default_region.class'));
288
        $this->assertEquals('Doctrine\ORM\Cache\Region\FileLockRegion', $container->getParameter('doctrine.orm.second_level_cache.filelock_region.class'));
289
        $this->assertEquals('Doctrine\ORM\Cache\Logging\CacheLoggerChain', $container->getParameter('doctrine.orm.second_level_cache.logger_chain.class'));
290
        $this->assertEquals('Doctrine\ORM\Cache\Logging\StatisticsCacheLogger', $container->getParameter('doctrine.orm.second_level_cache.logger_statistics.class'));
291
        $this->assertEquals('Doctrine\ORM\Cache\CacheConfiguration', $container->getParameter('doctrine.orm.second_level_cache.cache_configuration.class'));
292
        $this->assertEquals('Doctrine\ORM\Cache\RegionsConfiguration', $container->getParameter('doctrine.orm.second_level_cache.regions_configuration.class'));
293
294
        $config = BundleConfigurationBuilder::createBuilder()
295
            ->addBaseConnection()
296
            ->addEntityManager([
297
                'proxy_namespace' => 'MyProxies',
298
                'auto_generate_proxy_classes' => true,
299
                'default_entity_manager' => 'default',
300
                'entity_managers' => [
301
                    'default' => [
302
                        'mappings' => ['YamlBundle' => []],
303
                    ],
304
                ],
305
            ])
306
            ->build();
307
308
        $container = $this->getContainer();
309
        $extension->load([$config], $container);
310
        $this->compileContainer($container);
311
312
        $definition = $container->getDefinition('doctrine.dbal.default_connection');
313
314
        $args = $definition->getArguments();
315
        $this->assertEquals('pdo_mysql', $args[0]['driver']);
316
        $this->assertEquals('localhost', $args[0]['host']);
317
        $this->assertEquals('root', $args[0]['user']);
318
        $this->assertEquals('doctrine.dbal.default_connection.configuration', (string) $args[1]);
319
        $this->assertEquals('doctrine.dbal.default_connection.event_manager', (string) $args[2]);
320
        $this->assertCount(0, $definition->getMethodCalls());
0 ignored issues
show
Documentation introduced by
$definition->getMethodCalls() is of type array, but the function expects a object<Countable>|object...nit\Framework\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
321
322
        $definition = $container->getDefinition('doctrine.orm.default_entity_manager');
323
        $this->assertEquals('%doctrine.orm.entity_manager.class%', $definition->getClass());
324
        $this->assertEquals(['%doctrine.orm.entity_manager.class%', 'create'], $definition->getFactory());
325
326
        $this->assertEquals(['default' => 'doctrine.orm.default_entity_manager'], $container->getParameter('doctrine.entity_managers'), 'Set of the existing EntityManagers names is incorrect.');
327
        $this->assertEquals('%doctrine.entity_managers%', $container->getDefinition('doctrine')->getArgument(2), 'Set of the existing EntityManagers names is incorrect.');
328
329
        $arguments = $definition->getArguments();
330
        $this->assertInstanceOf('Symfony\Component\DependencyInjection\Reference', $arguments[0]);
331
        $this->assertEquals('doctrine.dbal.default_connection', (string) $arguments[0]);
332
        $this->assertInstanceOf('Symfony\Component\DependencyInjection\Reference', $arguments[1]);
333
        $this->assertEquals('doctrine.orm.default_configuration', (string) $arguments[1]);
334
335
        $definition = $container->getDefinition('doctrine.orm.default_configuration');
336
        $calls      = array_values($definition->getMethodCalls());
337
        $this->assertEquals(['YamlBundle' => 'Fixtures\Bundles\YamlBundle\Entity'], $calls[0][1][0]);
338
        $this->assertEquals('doctrine.orm.default_metadata_cache', (string) $calls[1][1][0]);
339
        $this->assertEquals('doctrine.orm.default_query_cache', (string) $calls[2][1][0]);
340
        $this->assertEquals('doctrine.orm.default_result_cache', (string) $calls[3][1][0]);
341
342
        $this->assertEquals('doctrine.orm.naming_strategy.default', (string) $calls[10][1][0]);
343
        $this->assertEquals('doctrine.orm.quote_strategy.default', (string) $calls[11][1][0]);
344
        $this->assertEquals('doctrine.orm.default_entity_listener_resolver', (string) $calls[12][1][0]);
345
346
        $definition = $container->getDefinition((string) $container->getAlias('doctrine.orm.default_metadata_cache'));
347
        $this->assertEquals(DoctrineProvider::class, $definition->getClass());
348
        $arguments = $definition->getArguments();
349
        $this->assertInstanceOf(Reference::class, $arguments[0]);
350
        $this->assertEquals('cache.doctrine.orm.default.metadata', (string) $arguments[0]);
351
        $this->assertSame(ArrayAdapter::class, $container->getDefinition((string) $arguments[0])->getClass());
352
353
        $definition = $container->getDefinition((string) $container->getAlias('doctrine.orm.default_query_cache'));
354
        $this->assertEquals(DoctrineProvider::class, $definition->getClass());
355
        $arguments = $definition->getArguments();
356
        $this->assertInstanceOf(Reference::class, $arguments[0]);
357
        $this->assertEquals('cache.doctrine.orm.default.query', (string) $arguments[0]);
358
        $this->assertSame(ArrayAdapter::class, $container->getDefinition((string) $arguments[0])->getClass());
359
360
        $definition = $container->getDefinition((string) $container->getAlias('doctrine.orm.default_result_cache'));
361
        $this->assertEquals(DoctrineProvider::class, $definition->getClass());
362
        $arguments = $definition->getArguments();
363
        $this->assertInstanceOf(Reference::class, $arguments[0]);
364
        $this->assertEquals('cache.doctrine.orm.default.result', (string) $arguments[0]);
365
        $this->assertSame(ArrayAdapter::class, $container->getDefinition((string) $arguments[0])->getClass());
366
    }
367
368
    public function testUseSavePointsAddMethodCallToAddSavepointsToTheConnection() : void
369
    {
370
        $container = $this->getContainer();
371
        $extension = new DoctrineExtension();
372
373
        $extension->load([
374
            [
375
                'dbal' => [
376
                    'connections' => [
377
                        'default' => ['password' => 'foo', 'use_savepoints' => true],
378
                    ],
379
                ],
380
            ],
381
        ], $container);
382
383
        $calls = $container->getDefinition('doctrine.dbal.default_connection')->getMethodCalls();
384
        $this->assertCount(1, $calls);
0 ignored issues
show
Documentation introduced by
$calls is of type array, but the function expects a object<Countable>|object...nit\Framework\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
385
        $this->assertEquals('setNestTransactionsWithSavepoints', $calls[0][0]);
386
        $this->assertTrue($calls[0][1][0]);
387
    }
388
389
    public function testAutoGenerateProxyClasses() : void
390
    {
391
        if (! interface_exists(EntityManagerInterface::class)) {
392
            self::markTestSkipped('This test requires ORM');
393
        }
394
395
        $container = $this->getContainer();
396
        $extension = new DoctrineExtension();
397
398
        $config = BundleConfigurationBuilder::createBuilder()
399
            ->addBaseConnection()
400
            ->addEntityManager([
401
                'proxy_namespace' => 'MyProxies',
402
                'auto_generate_proxy_classes' => 'eval',
403
                'default_entity_manager' => 'default',
404
                'entity_managers' => [
405
                    'default' => [
406
                        'mappings' => ['YamlBundle' => []],
407
                    ],
408
                ],
409
            ])
410
            ->build();
411
412
        $extension->load([$config], $container);
413
414
        $this->assertEquals(3 /* \Doctrine\Common\Proxy\AbstractProxyFactory::AUTOGENERATE_EVAL */, $container->getParameter('doctrine.orm.auto_generate_proxy_classes'));
415
    }
416
417
    public function testSingleEntityManagerWithDefaultConfiguration() : void
418
    {
419
        if (! interface_exists(EntityManagerInterface::class)) {
420
            self::markTestSkipped('This test requires ORM');
421
        }
422
423
        $container = $this->getContainer();
424
        $extension = new DoctrineExtension();
425
426
        $configurationArray = BundleConfigurationBuilder::createBuilderWithBaseValues()->build();
427
428
        $extension->load([$configurationArray], $container);
429
        $this->compileContainer($container);
430
431
        $definition = $container->getDefinition('doctrine.orm.default_entity_manager');
432
        $this->assertEquals('%doctrine.orm.entity_manager.class%', $definition->getClass());
433
        $this->assertEquals(['%doctrine.orm.entity_manager.class%', 'create'], $definition->getFactory());
434
435
        $this->assertDICConstructorArguments($definition, [
436
            new Reference('doctrine.dbal.default_connection'),
437
            new Reference('doctrine.orm.default_configuration'),
438
        ]);
439
    }
440
441
    public function testSingleEntityManagerWithDefaultSecondLevelCacheConfiguration() : void
442
    {
443
        if (! interface_exists(EntityManagerInterface::class)) {
444
            self::markTestSkipped('This test requires ORM');
445
        }
446
447
        $container = $this->getContainer();
448
        $extension = new DoctrineExtension();
449
450
        $configurationArray = BundleConfigurationBuilder::createBuilderWithBaseValues()
451
            ->addBaseSecondLevelCache()
452
            ->build();
453
454
        $extension->load([$configurationArray], $container);
455
        $this->compileContainer($container);
456
457
        $definition = $container->getDefinition('doctrine.orm.default_entity_manager');
458
        $this->assertEquals('%doctrine.orm.entity_manager.class%', $definition->getClass());
459
        $this->assertEquals(['%doctrine.orm.entity_manager.class%', 'create'], $definition->getFactory());
460
461
        $this->assertDICConstructorArguments($definition, [
462
            new Reference('doctrine.dbal.default_connection'),
463
            new Reference('doctrine.orm.default_configuration'),
464
        ]);
465
466
        $slcDefinition = $container->getDefinition('doctrine.orm.default_second_level_cache.default_cache_factory');
467
        $this->assertEquals('%doctrine.orm.second_level_cache.default_cache_factory.class%', $slcDefinition->getClass());
468
    }
469
470
    public function testSingleEntityManagerWithCustomSecondLevelCacheConfiguration() : void
471
    {
472
        if (! interface_exists(EntityManagerInterface::class)) {
473
            self::markTestSkipped('This test requires ORM');
474
        }
475
476
        $container = $this->getContainer();
477
        $extension = new DoctrineExtension();
478
479
        $configurationArray = BundleConfigurationBuilder::createBuilderWithBaseValues()
480
            ->addSecondLevelCache([
481
                'region_cache_driver' => ['type' => 'service', 'id' => 'my_cache'],
482
                'regions' => [
483
                    'hour_region' => ['lifetime' => 3600],
484
                ],
485
                'factory' => 'YamlBundle\Cache\MyCacheFactory',
486
            ])
487
            ->build();
488
489
        $extension->load([$configurationArray], $container);
490
        $this->compileContainer($container);
491
492
        $definition = $container->getDefinition('doctrine.orm.default_entity_manager');
493
        $this->assertEquals('%doctrine.orm.entity_manager.class%', $definition->getClass());
494
        $this->assertEquals(['%doctrine.orm.entity_manager.class%', 'create'], $definition->getFactory());
495
496
        $this->assertDICConstructorArguments($definition, [
497
            new Reference('doctrine.dbal.default_connection'),
498
            new Reference('doctrine.orm.default_configuration'),
499
        ]);
500
501
        $slcDefinition = $container->getDefinition('doctrine.orm.default_second_level_cache.default_cache_factory');
502
        $this->assertEquals('YamlBundle\Cache\MyCacheFactory', $slcDefinition->getClass());
503
    }
504
505 View Code Duplication
    public function testBundleEntityAliases() : void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
506
    {
507
        if (! interface_exists(EntityManagerInterface::class)) {
508
            self::markTestSkipped('This test requires ORM');
509
        }
510
511
        $container = $this->getContainer();
512
        $extension = new DoctrineExtension();
513
514
        $config        = BundleConfigurationBuilder::createBuilder()
515
             ->addBaseConnection()
516
             ->build();
517
        $config['orm'] = ['default_entity_manager' => 'default', 'entity_managers' => ['default' => ['mappings' => ['YamlBundle' => []]]]];
518
        $extension->load([$config], $container);
519
520
        $definition = $container->getDefinition('doctrine.orm.default_configuration');
521
        $this->assertDICDefinitionMethodCallOnce(
522
            $definition,
523
            'setEntityNamespaces',
524
            [['YamlBundle' => 'Fixtures\Bundles\YamlBundle\Entity']]
525
        );
526
    }
527
528 View Code Duplication
    public function testOverwriteEntityAliases() : void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
529
    {
530
        if (! interface_exists(EntityManagerInterface::class)) {
531
            self::markTestSkipped('This test requires ORM');
532
        }
533
534
        $container = $this->getContainer();
535
        $extension = new DoctrineExtension();
536
537
        $config        = BundleConfigurationBuilder::createBuilder()
538
             ->addBaseConnection()
539
             ->build();
540
        $config['orm'] = ['default_entity_manager' => 'default', 'entity_managers' => ['default' => ['mappings' => ['YamlBundle' => ['alias' => 'yml']]]]];
541
        $extension->load([$config], $container);
542
543
        $definition = $container->getDefinition('doctrine.orm.default_configuration');
544
        $this->assertDICDefinitionMethodCallOnce(
545
            $definition,
546
            'setEntityNamespaces',
547
            [['yml' => 'Fixtures\Bundles\YamlBundle\Entity']]
548
        );
549
    }
550
551
    public function testYamlBundleMappingDetection() : void
552
    {
553
        if (! interface_exists(EntityManagerInterface::class)) {
554
            self::markTestSkipped('This test requires ORM');
555
        }
556
557
        $container = $this->getContainer('YamlBundle');
558
        $extension = new DoctrineExtension();
559
560
        $config = BundleConfigurationBuilder::createBuilder()
561
            ->addBaseConnection()
562
            ->addBaseEntityManager()
563
            ->build();
564
        $extension->load([$config], $container);
565
566
        $definition = $container->getDefinition('doctrine.orm.default_metadata_driver');
567
        $this->assertDICDefinitionMethodCallOnce($definition, 'addDriver', [
568
            new Reference('doctrine.orm.default_yml_metadata_driver'),
569
            'Fixtures\Bundles\YamlBundle\Entity',
570
        ]);
571
    }
572
573 View Code Duplication
    public function testXmlBundleMappingDetection() : void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
574
    {
575
        if (! interface_exists(EntityManagerInterface::class)) {
576
            self::markTestSkipped('This test requires ORM');
577
        }
578
579
        $container = $this->getContainer('XmlBundle');
580
        $extension = new DoctrineExtension();
581
582
        $config = BundleConfigurationBuilder::createBuilder()
583
            ->addBaseConnection()
584
            ->addEntityManager([
585
                'default_entity_manager' => 'default',
586
                'entity_managers' => [
587
                    'default' => [
588
                        'mappings' => [
589
                            'XmlBundle' => [],
590
                        ],
591
                    ],
592
                ],
593
            ])
594
            ->build();
595
        $extension->load([$config], $container);
596
597
        $definition = $container->getDefinition('doctrine.orm.default_metadata_driver');
598
        $this->assertDICDefinitionMethodCallOnce($definition, 'addDriver', [
599
            new Reference('doctrine.orm.default_xml_metadata_driver'),
600
            'Fixtures\Bundles\XmlBundle\Entity',
601
        ]);
602
    }
603
604 View Code Duplication
    public function testAnnotationsBundleMappingDetection() : void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
605
    {
606
        if (! interface_exists(EntityManagerInterface::class)) {
607
            self::markTestSkipped('This test requires ORM');
608
        }
609
610
        $container = $this->getContainer('AnnotationsBundle');
611
        $extension = new DoctrineExtension();
612
613
        $config = BundleConfigurationBuilder::createBuilder()
614
            ->addBaseConnection()
615
            ->addEntityManager([
616
                'default_entity_manager' => 'default',
617
                'entity_managers' => [
618
                    'default' => [
619
                        'mappings' => [
620
                            'AnnotationsBundle' => [],
621
                        ],
622
                    ],
623
                ],
624
            ])
625
            ->build();
626
        $extension->load([$config], $container);
627
628
        $definition = $container->getDefinition('doctrine.orm.default_metadata_driver');
629
        $this->assertDICDefinitionMethodCallOnce($definition, 'addDriver', [
630
            new Reference('doctrine.orm.default_annotation_metadata_driver'),
631
            'Fixtures\Bundles\AnnotationsBundle\Entity',
632
        ]);
633
    }
634
635
    public function testOrmMergeConfigs() : void
636
    {
637
        if (! interface_exists(EntityManagerInterface::class)) {
638
            self::markTestSkipped('This test requires ORM');
639
        }
640
641
        $container = $this->getContainer(['XmlBundle', 'AnnotationsBundle']);
0 ignored issues
show
Documentation introduced by
array('XmlBundle', 'AnnotationsBundle') is of type array<integer,string,{"0":"string","1":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
642
        $extension = new DoctrineExtension();
643
644
        $config1 = BundleConfigurationBuilder::createBuilder()
645
            ->addBaseConnection()
646
            ->addEntityManager([
647
                'auto_generate_proxy_classes' => true,
648
                'default_entity_manager' => 'default',
649
                'entity_managers' => [
650
                    'default' => [
651
                        'mappings' => [
652
                            'AnnotationsBundle' => [],
653
                        ],
654
                    ],
655
                ],
656
            ])
657
            ->build();
658
        $config2 = BundleConfigurationBuilder::createBuilder()
659
            ->addBaseConnection()
660
            ->addEntityManager([
661
                'auto_generate_proxy_classes' => false,
662
                'default_entity_manager' => 'default',
663
                'entity_managers' => [
664
                    'default' => [
665
                        'mappings' => [
666
                            'XmlBundle' => [],
667
                        ],
668
                    ],
669
                ],
670
            ])
671
            ->build();
672
        $extension->load([$config1, $config2], $container);
673
674
        $definition = $container->getDefinition('doctrine.orm.default_metadata_driver');
675
        $this->assertDICDefinitionMethodCallAt(0, $definition, 'addDriver', [
676
            new Reference('doctrine.orm.default_annotation_metadata_driver'),
677
            'Fixtures\Bundles\AnnotationsBundle\Entity',
678
        ]);
679
        $this->assertDICDefinitionMethodCallAt(1, $definition, 'addDriver', [
680
            new Reference('doctrine.orm.default_xml_metadata_driver'),
681
            'Fixtures\Bundles\XmlBundle\Entity',
682
        ]);
683
684
        $configDef = $container->getDefinition('doctrine.orm.default_configuration');
685
        $this->assertDICDefinitionMethodCallOnce($configDef, 'setAutoGenerateProxyClasses');
686
687
        $calls = $configDef->getMethodCalls();
688
        foreach ($calls as $call) {
689
            if ($call[0] === 'setAutoGenerateProxyClasses') {
690
                $this->assertFalse($container->getParameterBag()->resolveValue($call[1][0]));
691
                break;
692
            }
693
        }
694
    }
695
696
    public function testAnnotationsBundleMappingDetectionWithVendorNamespace() : void
697
    {
698
        if (! interface_exists(EntityManagerInterface::class)) {
699
            self::markTestSkipped('This test requires ORM');
700
        }
701
702
        $container = $this->getContainer('AnnotationsBundle', 'Vendor');
703
        $extension = new DoctrineExtension();
704
705
        $config = BundleConfigurationBuilder::createBuilder()
706
            ->addBaseConnection()
707
            ->addEntityManager([
708
                'default_entity_manager' => 'default',
709
                'entity_managers' => [
710
                    'default' => [
711
                        'mappings' => [
712
                            'AnnotationsBundle' => [],
713
                        ],
714
                    ],
715
                ],
716
            ])
717
            ->build();
718
        $extension->load([$config], $container);
719
720
        $calls = $container->getDefinition('doctrine.orm.default_metadata_driver')->getMethodCalls();
721
        $this->assertEquals('doctrine.orm.default_annotation_metadata_driver', (string) $calls[0][1][0]);
722
        $this->assertEquals('Fixtures\Bundles\Vendor\AnnotationsBundle\Entity', $calls[0][1][1]);
723
    }
724
725
    public function testMessengerIntegration() : void
726
    {
727
        if (! interface_exists(MessageBusInterface::class)) {
728
            $this->markTestSkipped('Symfony Messenger component is not installed');
729
        }
730
731
        $container = $this->getContainer();
732
        $extension = new DoctrineExtension();
733
734
        $config = BundleConfigurationBuilder::createBuilder()
735
            ->addBaseConnection()
736
            ->build();
737
        $extension->load([$config], $container);
738
739
        $this->assertNotNull($middlewarePrototype = $container->getDefinition('messenger.middleware.doctrine_transaction'));
740
        $this->assertCount(1, $middlewarePrototype->getArguments());
0 ignored issues
show
Documentation introduced by
$middlewarePrototype->getArguments() is of type array, but the function expects a object<Countable>|object...nit\Framework\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
741
        $this->assertNotNull($middlewarePrototype = $container->getDefinition('messenger.middleware.doctrine_ping_connection'));
742
        $this->assertCount(1, $middlewarePrototype->getArguments());
0 ignored issues
show
Documentation introduced by
$middlewarePrototype->getArguments() is of type array, but the function expects a object<Countable>|object...nit\Framework\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
743
        $this->assertNotNull($middlewarePrototype = $container->getDefinition('messenger.middleware.doctrine_close_connection'));
744
        $this->assertCount(1, $middlewarePrototype->getArguments());
0 ignored issues
show
Documentation introduced by
$middlewarePrototype->getArguments() is of type array, but the function expects a object<Countable>|object...nit\Framework\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
745
746
        if (class_exists(DoctrineClearEntityManagerWorkerSubscriber::class)) {
747
            $this->assertNotNull($subscriber = $container->getDefinition('doctrine.orm.messenger.event_subscriber.doctrine_clear_entity_manager'));
748
            $this->assertCount(1, $subscriber->getArguments());
0 ignored issues
show
Documentation introduced by
$subscriber->getArguments() is of type array, but the function expects a object<Countable>|object...nit\Framework\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
749
        } else {
750
            $this->assertFalse($container->hasDefinition('doctrine.orm.messenger.event_subscriber.doctrine_clear_entity_manager'));
751
        }
752
    }
753
754
    public function testInvalidCacheConfiguration() : void
755
    {
756
        if (! interface_exists(EntityManagerInterface::class)) {
757
            self::markTestSkipped('This test requires ORM');
758
        }
759
760
        $container = $this->getContainer();
761
        $extension = new DoctrineExtension();
762
763
        $config = BundleConfigurationBuilder::createBuilder()
764
            ->addBaseConnection()
765
            ->addEntityManager(['metadata_cache_driver' => 'redis'])
766
            ->build();
767
768
        $this->expectException(InvalidArgumentException::class);
769
        $this->expectExceptionMessage('Unknown cache of type "redis" configured for cache "metadata_cache" in entity manager "default"');
770
771
        $extension->load([$config], $container);
772
    }
773
774
    /**
775
     * @param array|string $cacheConfig
776
     *
777
     * @dataProvider cacheConfigurationProvider
778
     */
779
    public function testCacheConfiguration(string $expectedAliasName, string $expectedAliasTarget, string $cacheName, $cacheConfig) : void
780
    {
781
        if (! interface_exists(EntityManagerInterface::class)) {
782
            self::markTestSkipped('This test requires ORM');
783
        }
784
785
        $container = $this->getContainer();
786
        $extension = new DoctrineExtension();
787
788
        $config = BundleConfigurationBuilder::createBuilder()
789
            ->addBaseConnection()
790
            ->addEntityManager([$cacheName => $cacheConfig])
791
            ->build();
792
793
        $extension->load([$config], $container);
794
795
        $this->assertTrue($container->hasAlias($expectedAliasName));
796
        $alias = $container->getAlias($expectedAliasName);
797
        $this->assertEquals($expectedAliasTarget, (string) $alias);
798
    }
799
800
    public static function cacheConfigurationProvider() : array
801
    {
802
        return [
803
            'metadata_cache_default' => [
804
                'expectedAliasName' => 'doctrine.orm.default_metadata_cache',
805
                'expectedAliasTarget' => 'doctrine.orm.cache.provider.cache.doctrine.orm.default.metadata',
806
                'cacheName' => 'metadata_cache_driver',
807
                'cacheConfig' => ['type' => null],
808
            ],
809
            'query_cache_default' => [
810
                'expectedAliasName' => 'doctrine.orm.default_query_cache',
811
                'expectedAliasTarget' => 'doctrine.orm.cache.provider.cache.doctrine.orm.default.query',
812
                'cacheName' => 'query_cache_driver',
813
                'cacheConfig' => ['type' => null],
814
            ],
815
            'result_cache_default' => [
816
                'expectedAliasName' => 'doctrine.orm.default_result_cache',
817
                'expectedAliasTarget' => 'doctrine.orm.cache.provider.cache.doctrine.orm.default.result',
818
                'cacheName' => 'result_cache_driver',
819
                'cacheConfig' => ['type' => null],
820
            ],
821
822
            'metadata_cache_pool' => [
823
                'expectedAliasName' => 'doctrine.orm.default_metadata_cache',
824
                'expectedAliasTarget' => 'doctrine.orm.cache.provider.metadata_cache_pool',
825
                'cacheName' => 'metadata_cache_driver',
826
                'cacheConfig' => ['type' => 'pool', 'pool' => 'metadata_cache_pool'],
827
            ],
828
            'query_cache_pool' => [
829
                'expectedAliasName' => 'doctrine.orm.default_query_cache',
830
                'expectedAliasTarget' => 'doctrine.orm.cache.provider.query_cache_pool',
831
                'cacheName' => 'query_cache_driver',
832
                'cacheConfig' => ['type' => 'pool', 'pool' => 'query_cache_pool'],
833
            ],
834
            'result_cache_pool' => [
835
                'expectedAliasName' => 'doctrine.orm.default_result_cache',
836
                'expectedAliasTarget' => 'doctrine.orm.cache.provider.result_cache_pool',
837
                'cacheName' => 'result_cache_driver',
838
                'cacheConfig' => ['type' => 'pool', 'pool' => 'result_cache_pool'],
839
            ],
840
841
            'metadata_cache_service' => [
842
                'expectedAliasName' => 'doctrine.orm.default_metadata_cache',
843
                'expectedAliasTarget' => 'service_target_metadata',
844
                'cacheName' => 'metadata_cache_driver',
845
                'cacheConfig' => ['type' => 'service', 'id' => 'service_target_metadata'],
846
            ],
847
            'query_cache_service' => [
848
                'expectedAliasName' => 'doctrine.orm.default_query_cache',
849
                'expectedAliasTarget' => 'service_target_query',
850
                'cacheName' => 'query_cache_driver',
851
                'cacheConfig' => ['type' => 'service', 'id' => 'service_target_query'],
852
            ],
853
            'result_cache_service' => [
854
                'expectedAliasName' => 'doctrine.orm.default_result_cache',
855
                'expectedAliasTarget' => 'service_target_result',
856
                'cacheName' => 'result_cache_driver',
857
                'cacheConfig' => ['type' => 'service', 'id' => 'service_target_result'],
858
            ],
859
        ];
860
    }
861
862
    public function testShardManager() : void
863
    {
864
        $container = $this->getContainer();
865
        $extension = new DoctrineExtension();
866
867
        $config = BundleConfigurationBuilder::createBuilder()
868
             ->addConnection([
869
                 'connections' => [
870
                     'foo' => [
871
                         'shards' => [
872
                             'test' => ['id' => 1],
873
                         ],
874
                     ],
875
                     'bar' => [],
876
                 ],
877
             ])
878
            ->build();
879
880
        $extension->load([$config], $container);
881
882
        $this->assertTrue($container->hasDefinition('doctrine.dbal.foo_shard_manager'));
883
        $this->assertFalse($container->hasDefinition('doctrine.dbal.bar_shard_manager'));
884
    }
885
886
    private function getContainer($bundles = 'YamlBundle', $vendor = null) : ContainerBuilder
887
    {
888
        $bundles = (array) $bundles;
889
890
        $map = [];
891
        foreach ($bundles as $bundle) {
892
            require_once __DIR__ . '/Fixtures/Bundles/' . ($vendor ? $vendor . '/' : '') . $bundle . '/' . $bundle . '.php';
893
894
            $map[$bundle] = 'Fixtures\\Bundles\\' . ($vendor ? $vendor . '\\' : '') . $bundle . '\\' . $bundle;
895
        }
896
897
        $container = new ContainerBuilder(new ParameterBag([
898
            'kernel.name' => 'app',
899
            'kernel.debug' => false,
900
            'kernel.bundles' => $map,
901
            'kernel.cache_dir' => sys_get_temp_dir(),
902
            'kernel.environment' => 'test',
903
            'kernel.root_dir' => __DIR__ . '/../../', // src dir
904
        ]));
905
906
        // Register dummy cache services so we don't have to load the FrameworkExtension
907
        $container->setDefinition('cache.system', (new Definition(ArrayAdapter::class))->setPublic(true));
908
        $container->setDefinition('cache.app', (new Definition(ArrayAdapter::class))->setPublic(true));
909
        $container->setDefinition('my_pool', (new Definition(ArrayAdapter::class))->setPublic(true));
910
911
        return $container;
912
    }
913
914
    private function assertDICConstructorArguments(Definition $definition, array $args) : void
915
    {
916
        $this->assertEquals($args, $definition->getArguments(), "Expected and actual DIC Service constructor arguments of definition '" . $definition->getClass() . "' don't match.");
917
    }
918
919 View Code Duplication
    private function assertDICDefinitionMethodCallAt(int $pos, Definition $definition, string $methodName, array $params = null) : void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
920
    {
921
        $calls = $definition->getMethodCalls();
922
        if (! isset($calls[$pos][0])) {
923
            return;
924
        }
925
926
        $this->assertEquals($methodName, $calls[$pos][0], "Method '" . $methodName . "' is expected to be called at position " . $pos . '.');
927
928
        if ($params === null) {
929
            return;
930
        }
931
932
        $this->assertEquals($params, $calls[$pos][1], "Expected parameters to methods '" . $methodName . "' do not match the actual parameters.");
933
    }
934
935
    /**
936
     * Assertion for the DI Container, check if the given definition contains a method call with the given parameters.
937
     */
938 View Code Duplication
    private function assertDICDefinitionMethodCallOnce(Definition $definition, string $methodName, array $params = null) : void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
939
    {
940
        $calls  = $definition->getMethodCalls();
941
        $called = false;
942
        foreach ($calls as $call) {
943
            if ($call[0] !== $methodName) {
944
                continue;
945
            }
946
947
            if ($called) {
948
                $this->fail("Method '" . $methodName . "' is expected to be called only once, a second call was registered though.");
949
            } else {
950
                $called = true;
951
                if ($params !== null) {
952
                    $this->assertEquals($params, $call[1], "Expected parameters to methods '" . $methodName . "' do not match the actual parameters.");
953
                }
954
            }
955
        }
956
        if ($called) {
957
            return;
958
        }
959
960
        $this->fail("Method '" . $methodName . "' is expected to be called once, definition does not contain a call though.");
961
    }
962
963
    private function compileContainer(ContainerBuilder $container) : void
964
    {
965
        $container->getCompilerPassConfig()->setOptimizationPasses([new ResolveChildDefinitionsPass()]);
966
        $container->getCompilerPassConfig()->setRemovingPasses([]);
967
        $container->compile();
968
    }
969
}
970
971
class TestWrapperClass extends Connection
972
{
973
}
974