From a7c24b2f1bec103d0c89956050638c84295bef69 Mon Sep 17 00:00:00 2001 From: David Maicher Date: Tue, 14 May 2024 21:31:04 +0200 Subject: [PATCH 1/2] use configurable keys for keeping static connections --- composer.json | 1 - makefile | 3 +- .../DependencyInjection/Configuration.php | 49 +++++++++ .../DAMADoctrineTestExtension.php | 4 + .../DoctrineTestCompilerPass.php | 102 ++++++++++++------ .../Doctrine/Cache/Psr6StaticArrayCache.php | 3 + .../Doctrine/DBAL/StaticDriver.php | 10 +- .../DoctrineTestCompilerPassTest.php | 91 +++++++++++++--- .../Doctrine/DBAL/StaticDriverTest.php | 75 ++----------- tests/Functional/FunctionalTestTrait.php | 2 +- tests/Functional/PhpunitTest.php | 4 + tests/Functional/app/AppKernel.php | 4 + tests/Functional/app/config.yml | 4 +- tests/bootstrap.php | 10 +- 14 files changed, 242 insertions(+), 120 deletions(-) diff --git a/composer.json b/composer.json index cbdd0f6..890959f 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,6 @@ ], "require": { "php": "^7.4 || ^8.0", - "ext-json": "*", "doctrine/dbal": "^3.3 || ^4.0", "doctrine/doctrine-bundle": "^2.2.2", "psr/cache": "^1.0 || ^2.0 || ^3.0", diff --git a/makefile b/makefile index 7b11cdb..8d98a98 100644 --- a/makefile +++ b/makefile @@ -8,7 +8,8 @@ test_phpunit_legacy: tests/Functional/app/parameters.yml vendor/bin/phpunit -c tests/phpunit.9.xml tests/ phpstan: - vendor/bin/phpstan analyse -c phpstan.neon -a vendor/autoload.php -l 5 src tests + vendor/bin/phpstan analyse -c phpstan.neon -a vendor/autoload.php -l 8 src + vendor/bin/phpstan analyse -c phpstan.neon -a vendor/autoload.php -l 5 tests behat: vendor/bin/behat -c tests/behat.yml -fprogress diff --git a/src/DAMA/DoctrineTestBundle/DependencyInjection/Configuration.php b/src/DAMA/DoctrineTestBundle/DependencyInjection/Configuration.php index fd9df4a..da85819 100644 --- a/src/DAMA/DoctrineTestBundle/DependencyInjection/Configuration.php +++ b/src/DAMA/DoctrineTestBundle/DependencyInjection/Configuration.php @@ -8,6 +8,7 @@ class Configuration implements ConfigurationInterface { public const ENABLE_STATIC_CONNECTION = 'enable_static_connection'; + public const CONNECTION_KEYS = 'connection_keys'; public const STATIC_META_CACHE = 'enable_static_meta_data_cache'; public const STATIC_QUERY_CACHE = 'enable_static_query_cache'; @@ -45,9 +46,57 @@ public function getConfigTreeBuilder(): TreeBuilder ->end() ->booleanNode(self::STATIC_META_CACHE)->defaultTrue()->end() ->booleanNode(self::STATIC_QUERY_CACHE)->defaultTrue()->end() + ->arrayNode(self::CONNECTION_KEYS) + ->normalizeKeys(false) + ->variablePrototype() + ->end() + ->validate() + ->ifTrue(function ($value) { + if ($value === null) { + return false; + } + + if (!is_array($value)) { + return true; + } + + foreach ($value as $k => $v) { + if (!is_string($k) || !(is_string($v) || is_array($v))) { + return true; + } + + if (!is_array($v)) { + continue; + } + + if (count($v) !== 2 + || !is_string($v['primary'] ?? null) + || !is_array($v['replicas'] ?? null) + || !$this->isAssocStringArray($v['replicas']) + ) { + return true; + } + } + + return false; + }) + ->thenInvalid('Must be array}>') + ->end() + ->end() ->end() ; return $treeBuilder; } + + private function isAssocStringArray(array $value): bool + { + foreach ($value as $k => $v) { + if (!is_string($k) || !is_string($v)) { + return false; + } + } + + return true; + } } diff --git a/src/DAMA/DoctrineTestBundle/DependencyInjection/DAMADoctrineTestExtension.php b/src/DAMA/DoctrineTestBundle/DependencyInjection/DAMADoctrineTestExtension.php index 19b4f94..6396b7a 100644 --- a/src/DAMA/DoctrineTestBundle/DependencyInjection/DAMADoctrineTestExtension.php +++ b/src/DAMA/DoctrineTestBundle/DependencyInjection/DAMADoctrineTestExtension.php @@ -24,5 +24,9 @@ public function load(array $configs, ContainerBuilder $container): void 'dama.'.Configuration::ENABLE_STATIC_CONNECTION, $config[Configuration::ENABLE_STATIC_CONNECTION] ); + $container->setParameter( + 'dama.'.Configuration::CONNECTION_KEYS, + $config[Configuration::CONNECTION_KEYS] ?? [], + ); } } diff --git a/src/DAMA/DoctrineTestBundle/DependencyInjection/DoctrineTestCompilerPass.php b/src/DAMA/DoctrineTestBundle/DependencyInjection/DoctrineTestCompilerPass.php index 9e7d79d..7b553e5 100644 --- a/src/DAMA/DoctrineTestBundle/DependencyInjection/DoctrineTestCompilerPass.php +++ b/src/DAMA/DoctrineTestBundle/DependencyInjection/DoctrineTestCompilerPass.php @@ -17,7 +17,6 @@ class DoctrineTestCompilerPass implements CompilerPassInterface { public function process(ContainerBuilder $container): void { - $transactionalBehaviorEnabledConnections = $this->getTransactionEnabledConnectionNames($container); $container->register('dama.doctrine.dbal.middleware', Middleware::class); $cacheNames = []; @@ -29,11 +28,15 @@ public function process(ContainerBuilder $container): void $cacheNames[] = 'doctrine.orm.%s_query_cache'; } - $connectionNames = array_keys($container->getParameter('doctrine.connections')); + /** @var array $connections */ + $connections = $container->getParameter('doctrine.connections'); + $connectionNames = array_keys($connections); + $transactionalBehaviorEnabledConnections = $this->getTransactionEnabledConnectionNames($container, $connectionNames); + $connectionKeys = $this->getConnectionKeys($container, $connectionNames); foreach ($connectionNames as $name) { if (in_array($name, $transactionalBehaviorEnabledConnections, true)) { - $this->modifyConnectionService($container, $name); + $this->modifyConnectionService($container, $connectionKeys[$name] ?? null, $name); } foreach ($cacheNames as $cacheName) { @@ -56,9 +59,13 @@ public function process(ContainerBuilder $container): void $container->getParameterBag()->remove('dama.'.Configuration::ENABLE_STATIC_CONNECTION); $container->getParameterBag()->remove('dama.'.Configuration::STATIC_META_CACHE); $container->getParameterBag()->remove('dama.'.Configuration::STATIC_QUERY_CACHE); + $container->getParameterBag()->remove('dama.'.Configuration::CONNECTION_KEYS); } - private function modifyConnectionService(ContainerBuilder $container, string $name): void + /** + * @param string|array{primary: string, replicas: array}|null $connectionKey + */ + private function modifyConnectionService(ContainerBuilder $container, $connectionKey, string $name): void { $connectionDefinition = $container->getDefinition(sprintf('doctrine.dbal.%s_connection', $name)); @@ -66,9 +73,11 @@ private function modifyConnectionService(ContainerBuilder $container, string $na throw new \LogicException(sprintf('This bundle relies on savepoints for nested database transactions. You need to enable "use_savepoints" on the Doctrine DBAL config for connection "%s".', $name)); } + /** @var array $connectionOptions */ + $connectionOptions = $connectionDefinition->getArgument(0); $connectionDefinition->replaceArgument( 0, - $this->getModifiedConnectionOptions($connectionDefinition->getArgument(0), $name), + $this->getModifiedConnectionOptions($connectionOptions, $connectionKey, $name), ); $connectionConfig = $container->getDefinition(sprintf('doctrine.dbal.%s_connection.configuration', $name)); @@ -90,27 +99,44 @@ private function modifyConnectionService(ContainerBuilder $container, string $na $connectionConfig->setMethodCalls($methodCalls); } - private function getModifiedConnectionOptions(array $options, string $name): array - { - $connectionOptions = array_merge($options, [ - 'dama.keep_static' => true, - 'dama.connection_name' => $name, - ]); - - if (isset($connectionOptions['primary'])) { - $connectionOptions['primary'] = array_merge($connectionOptions['primary'], [ - 'dama.keep_static' => true, - 'dama.connection_name' => $name, - ]); - } - - if (isset($connectionOptions['replica']) && is_array($connectionOptions['replica'])) { - foreach ($connectionOptions['replica'] as $replicaName => &$replica) { - $replica = array_merge($replica, [ - 'dama.keep_static' => true, - 'dama.connection_name' => sprintf('%s.%s', $name, $replicaName), - ]); + /** + * @param array $connectionOptions + * @param string|array{primary: string, replicas: array}|null $connectionKey + * + * @return array + */ + private function getModifiedConnectionOptions( + array $connectionOptions, + $connectionKey, + string $name + ): array { + if (!isset($connectionOptions['primary'])) { + if (is_array($connectionKey)) { + throw new \InvalidArgumentException(sprintf('Connection key for connection "%s" must be a string', $name)); } + + $connectionOptions['dama.connection_key'] = $connectionKey ?? $name; + + return $connectionOptions; + } + + $connectionOptions['dama.connection_key'] = $connectionKey['primary'] ?? $connectionKey ?? $name; + $connectionOptions['primary']['dama.connection_key'] = $connectionOptions['dama.connection_key']; + + if (!is_array($connectionOptions['replica'] ?? null)) { + return $connectionOptions; + } + + $replicaKeys = []; + if (isset($connectionKey['replicas'])) { + /** @var array $definedReplicaNames */ + $definedReplicaNames = array_keys($connectionOptions['replica']); + $this->validateConnectionNames(array_keys($connectionKey['replicas']), $definedReplicaNames); + $replicaKeys = $connectionKey['replicas']; + } + + foreach ($connectionOptions['replica'] as $replicaName => &$replicaOptions) { + $replicaOptions['dama.connection_key'] = $replicaKeys[$replicaName] ?? $connectionOptions['dama.connection_key']; } return $connectionOptions; @@ -123,11 +149,12 @@ private function registerStaticCache( ): void { $cache = new Definition(); $namespace = sha1($cacheServiceId); + $originalServiceClass = $originalCacheServiceDefinition->getClass(); - if (is_a($originalCacheServiceDefinition->getClass(), CacheItemPoolInterface::class, true)) { + if ($originalServiceClass !== null && is_a($originalServiceClass, CacheItemPoolInterface::class, true)) { $cache->setClass(Psr6StaticArrayCache::class); $cache->setArgument(0, $namespace); // make sure we have no key collisions - } elseif (is_a($originalCacheServiceDefinition->getClass(), Cache::class, true)) { + } elseif ($originalServiceClass !== null && is_a($originalServiceClass, Cache::class, true)) { throw new \InvalidArgumentException(sprintf('Configuring "%s" caches is not supported anymore. Upgrade to PSR-6 caches instead.', Cache::class)); } else { throw new \InvalidArgumentException(sprintf('Unsupported cache class "%s" found on service "%s".', $originalCacheServiceDefinition->getClass(), $cacheServiceId)); @@ -140,14 +167,15 @@ private function registerStaticCache( } /** + * @param string[] $connectionNames + * * @return string[] */ - private function getTransactionEnabledConnectionNames(ContainerBuilder $container): array + private function getTransactionEnabledConnectionNames(ContainerBuilder $container, array $connectionNames): array { - /** @var bool|array $enableStaticConnectionsConfig */ + /** @var bool|array $enableStaticConnectionsConfig */ $enableStaticConnectionsConfig = $container->getParameter('dama.'.Configuration::ENABLE_STATIC_CONNECTION); - $connectionNames = array_keys($container->getParameter('doctrine.connections')); if (is_array($enableStaticConnectionsConfig)) { $this->validateConnectionNames(array_keys($enableStaticConnectionsConfig), $connectionNames); } @@ -193,4 +221,18 @@ private function hasSavepointsEnabled(Definition $connectionDefinition): bool return false; } + + /** + * @param string[] $connectionNames + * + * @return array}> + */ + private function getConnectionKeys(ContainerBuilder $container, array $connectionNames): array + { + /** @var array $connectionKeys */ + $connectionKeys = $container->getParameter('dama.'.Configuration::CONNECTION_KEYS); + $this->validateConnectionNames(array_keys($connectionKeys), $connectionNames); + + return $connectionKeys; + } } diff --git a/src/DAMA/DoctrineTestBundle/Doctrine/Cache/Psr6StaticArrayCache.php b/src/DAMA/DoctrineTestBundle/Doctrine/Cache/Psr6StaticArrayCache.php index a0eff0e..8566a35 100644 --- a/src/DAMA/DoctrineTestBundle/Doctrine/Cache/Psr6StaticArrayCache.php +++ b/src/DAMA/DoctrineTestBundle/Doctrine/Cache/Psr6StaticArrayCache.php @@ -39,6 +39,9 @@ public function getItem($key): CacheItemInterface return $this->adapter->getItem($key); } + /** + * @return iterable + */ public function getItems(array $keys = []): iterable { return $this->adapter->getItems($keys); diff --git a/src/DAMA/DoctrineTestBundle/Doctrine/DBAL/StaticDriver.php b/src/DAMA/DoctrineTestBundle/Doctrine/DBAL/StaticDriver.php index 4422a14..ab002de 100644 --- a/src/DAMA/DoctrineTestBundle/Doctrine/DBAL/StaticDriver.php +++ b/src/DAMA/DoctrineTestBundle/Doctrine/DBAL/StaticDriver.php @@ -10,7 +10,7 @@ class StaticDriver extends Driver\Middleware\AbstractDriverMiddleware { /** - * @var Connection[] + * @var array */ private static $connections = []; @@ -21,14 +21,12 @@ class StaticDriver extends Driver\Middleware\AbstractDriverMiddleware public function connect(array $params): Connection { - if (!self::isKeepStaticConnections() - || !isset($params['dama.keep_static']) - || !$params['dama.keep_static'] - ) { + if (!self::isKeepStaticConnections() || !isset($params['dama.connection_key'])) { return parent::connect($params); } - $key = sha1(json_encode($params)); + /** @var string $key */ + $key = $params['dama.connection_key']; if (!isset(self::$connections[$key])) { self::$connections[$key] = parent::connect($params); diff --git a/tests/DAMA/DoctrineTestBundle/DependencyInjection/DoctrineTestCompilerPassTest.php b/tests/DAMA/DoctrineTestBundle/DependencyInjection/DoctrineTestCompilerPassTest.php index 6ada236..502692a 100644 --- a/tests/DAMA/DoctrineTestBundle/DependencyInjection/DoctrineTestCompilerPassTest.php +++ b/tests/DAMA/DoctrineTestBundle/DependencyInjection/DoctrineTestCompilerPassTest.php @@ -95,8 +95,7 @@ function (ContainerBuilder $containerBuilder): void { } self::assertSame([ - 'dama.keep_static' => true, - 'dama.connection_name' => 'a', + 'dama.connection_key' => 'a', ], $containerBuilder->getDefinition('doctrine.dbal.a_connection')->getArgument(0)); self::assertEquals( @@ -166,8 +165,7 @@ function (ContainerBuilder $containerBuilder): void { ], function (ContainerBuilder $containerBuilder): void { self::assertSame([ - 'dama.keep_static' => true, - 'dama.connection_name' => 'a', + 'dama.connection_key' => 'a', ], $containerBuilder->getDefinition('doctrine.dbal.a_connection')->getArgument(0)); self::assertSame([], $containerBuilder->getDefinition('doctrine.dbal.b_connection')->getArgument(0)); @@ -175,21 +173,17 @@ function (ContainerBuilder $containerBuilder): void { self::assertSame( [ 'primary' => [ - 'dama.keep_static' => true, - 'dama.connection_name' => 'c', + 'dama.connection_key' => 'c', ], 'replica' => [ 'one' => [ - 'dama.keep_static' => true, - 'dama.connection_name' => 'c.one', + 'dama.connection_key' => 'c', ], 'two' => [ - 'dama.keep_static' => true, - 'dama.connection_name' => 'c.two', + 'dama.connection_key' => 'c', ], ], - 'dama.keep_static' => true, - 'dama.connection_name' => 'c', + 'dama.connection_key' => 'c', ], $containerBuilder->getDefinition('doctrine.dbal.c_connection')->getArgument(0) ); @@ -213,6 +207,79 @@ function (TestCase $testCase): void { }, ]; + yield 'Custom keys' => [ + [ + 'connection_keys' => [ + 'a' => 'key_1', + 'b' => 'key_2', + 'c' => 'key_3', + ], + ], + function (ContainerBuilder $containerBuilder): void { + self::assertSame([ + 'dama.connection_key' => 'key_1', + ], $containerBuilder->getDefinition('doctrine.dbal.a_connection')->getArgument(0)); + + self::assertSame([ + 'dama.connection_key' => 'key_2', + ], $containerBuilder->getDefinition('doctrine.dbal.b_connection')->getArgument(0)); + + self::assertSame( + [ + 'primary' => [ + 'dama.connection_key' => 'key_3', + ], + 'replica' => [ + 'one' => [ + 'dama.connection_key' => 'key_3', + ], + 'two' => [ + 'dama.connection_key' => 'key_3', + ], + ], + 'dama.connection_key' => 'key_3', + ], + $containerBuilder->getDefinition('doctrine.dbal.c_connection')->getArgument(0) + ); + }, + ]; + + yield 'Custom keys for primary/replica' => [ + [ + 'connection_keys' => [ + 'c' => [ + 'primary' => 'key_3', + 'replicas' => [ + 'one' => 'key_4', + ], + ], + ], + ], + function (ContainerBuilder $containerBuilder): void { + self::assertSame([ + 'dama.connection_key' => 'a', + ], $containerBuilder->getDefinition('doctrine.dbal.a_connection')->getArgument(0)); + + self::assertSame( + [ + 'primary' => [ + 'dama.connection_key' => 'key_3', + ], + 'replica' => [ + 'one' => [ + 'dama.connection_key' => 'key_4', + ], + 'two' => [ + 'dama.connection_key' => 'key_3', + ], + ], + 'dama.connection_key' => 'key_3', + ], + $containerBuilder->getDefinition('doctrine.dbal.c_connection')->getArgument(0) + ); + }, + ]; + yield 'psr6 ORM cache services' => [ $defaultConfig, function (ContainerBuilder $containerBuilder): void { diff --git a/tests/DAMA/DoctrineTestBundle/Doctrine/DBAL/StaticDriverTest.php b/tests/DAMA/DoctrineTestBundle/Doctrine/DBAL/StaticDriverTest.php index 3b31947..94f1926 100644 --- a/tests/DAMA/DoctrineTestBundle/Doctrine/DBAL/StaticDriverTest.php +++ b/tests/DAMA/DoctrineTestBundle/Doctrine/DBAL/StaticDriverTest.php @@ -4,11 +4,13 @@ use DAMA\DoctrineTestBundle\Doctrine\DBAL\StaticConnection; use DAMA\DoctrineTestBundle\Doctrine\DBAL\StaticDriver; -use Doctrine\DBAL\Platforms\AbstractPlatform; use PHPUnit\Framework\TestCase; class StaticDriverTest extends TestCase { + /** + * @var MockDriver + */ private $driver; protected function setUp(): void @@ -35,15 +37,14 @@ public function testConnect(): void 'user' => 'user', 'password' => 'password', 'port' => 3306, - 'dama.keep_static' => true, - 'dama.connection_name' => 'foo', + 'dama.connection_key' => 'foo', 'some_closure' => function (): void {}, ]; /** @var StaticConnection $connection1 */ - $connection1 = $driver->connect(['dama.connection_name' => 'foo'] + $params); + $connection1 = $driver->connect(['dama.connection_key' => 'foo'] + $params); /** @var StaticConnection $connection2 */ - $connection2 = $driver->connect(['dama.connection_name' => 'bar'] + $params); + $connection2 = $driver->connect(['dama.connection_key' => 'bar'] + $params); $this->assertInstanceOf(StaticConnection::class, $connection1); $this->assertNotSame($connection1->getWrappedConnection(), $connection2->getWrappedConnection()); @@ -51,9 +52,9 @@ public function testConnect(): void $driver = new StaticDriver($this->driver); /** @var StaticConnection $connectionNew1 */ - $connectionNew1 = $driver->connect(['dama.connection_name' => 'foo'] + $params); + $connectionNew1 = $driver->connect(['dama.connection_key' => 'foo'] + $params); /** @var StaticConnection $connectionNew2 */ - $connectionNew2 = $driver->connect(['dama.connection_name' => 'bar'] + $params); + $connectionNew2 = $driver->connect(['dama.connection_key' => 'bar'] + $params); $this->assertSame($connection1->getWrappedConnection(), $connectionNew1->getWrappedConnection()); $this->assertSame($connection2->getWrappedConnection(), $connectionNew2->getWrappedConnection()); @@ -63,65 +64,5 @@ public function testConnect(): void /** @var StaticConnection $connection2 */ $connection2 = $driver->connect($params); $this->assertSame($connection1->getWrappedConnection(), $connection2->getWrappedConnection()); - - /** @var StaticConnection $connection3 */ - $connection3 = $driver->connect(['host' => 'bar'] + $params); - $this->assertNotSame($connection1->getWrappedConnection(), $connection3->getWrappedConnection()); - } - - public function testConnectWithPlatform(): void - { - $driver = new StaticDriver($this->driver); - - $driver::setKeepStaticConnections(true); - - $platform = $this->createMock(AbstractPlatform::class); - $platform - ->expects(self::exactly(7)) - ->method('supportsSavepoints') - ->willReturn(true) - ; - - $params = [ - 'driver' => 'pdo_mysql', - 'charset' => 'UTF8', - 'host' => 'foo', - 'dbname' => 'doctrine_test_bundle', - 'user' => 'user', - 'password' => 'password', - 'port' => 3306, - 'platform' => $platform, - 'dama.keep_static' => true, - 'dama.connection_name' => 'foo', - 'some_closure' => function (): void {}, - ]; - - /** @var StaticConnection $connection1 */ - $connection1 = $driver->connect(['dama.connection_name' => 'foo'] + $params); - /** @var StaticConnection $connection2 */ - $connection2 = $driver->connect(['dama.connection_name' => 'bar'] + $params); - - $this->assertInstanceOf(StaticConnection::class, $connection1); - $this->assertNotSame($connection1->getWrappedConnection(), $connection2->getWrappedConnection()); - - $driver = new StaticDriver($this->driver); - - /** @var StaticConnection $connectionNew1 */ - $connectionNew1 = $driver->connect(['dama.connection_name' => 'foo'] + $params); - /** @var StaticConnection $connectionNew2 */ - $connectionNew2 = $driver->connect(['dama.connection_name' => 'bar'] + $params); - - $this->assertSame($connection1->getWrappedConnection(), $connectionNew1->getWrappedConnection()); - $this->assertSame($connection2->getWrappedConnection(), $connectionNew2->getWrappedConnection()); - - /** @var StaticConnection $connection1 */ - $connection1 = $driver->connect($params); - /** @var StaticConnection $connection2 */ - $connection2 = $driver->connect($params); - $this->assertSame($connection1->getWrappedConnection(), $connection2->getWrappedConnection()); - - /** @var StaticConnection $connection3 */ - $connection3 = $driver->connect(['host' => 'bar'] + $params); - $this->assertNotSame($connection1->getWrappedConnection(), $connection3->getWrappedConnection()); } } diff --git a/tests/Functional/FunctionalTestTrait.php b/tests/Functional/FunctionalTestTrait.php index a4ca6da..1a8dfdc 100644 --- a/tests/Functional/FunctionalTestTrait.php +++ b/tests/Functional/FunctionalTestTrait.php @@ -39,7 +39,7 @@ public function tearDown(): void * @Then there are :count rows * @Then there is :count row */ - public function assertRowCount($count): void + public function assertRowCount(int $count): void { Assert::assertEquals([$count], $this->connection->fetchFirstColumn('SELECT COUNT(*) FROM test')); } diff --git a/tests/Functional/PhpunitTest.php b/tests/Functional/PhpunitTest.php index 22bc84f..f27c3bc 100644 --- a/tests/Functional/PhpunitTest.php +++ b/tests/Functional/PhpunitTest.php @@ -58,6 +58,10 @@ public function testChangeDbStateForReplicaConnection(): void $this->assertRowCount(0); $this->insertRow(); $this->assertRowCount(1); + + // this will make sure the next select uses the read replica + $this->connection->close(); + $this->assertRowCount(1); } /** diff --git a/tests/Functional/app/AppKernel.php b/tests/Functional/app/AppKernel.php index 4e56845..34f0f89 100644 --- a/tests/Functional/app/AppKernel.php +++ b/tests/Functional/app/AppKernel.php @@ -8,10 +8,14 @@ use Symfony\Bundle\FrameworkBundle\FrameworkBundle; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\HttpKernel\Bundle\Bundle; use Symfony\Component\HttpKernel\Kernel; class AppKernel extends Kernel { + /** + * @return array + */ public function registerBundles(): array { return [ diff --git a/tests/Functional/app/config.yml b/tests/Functional/app/config.yml index 1bc4eac..ce625b6 100644 --- a/tests/Functional/app/config.yml +++ b/tests/Functional/app/config.yml @@ -18,11 +18,13 @@ doctrine: replicas: replica_one: url: '%database.url%' - + dama_doctrine_test: enable_static_connection: true enable_static_meta_data_cache: true enable_static_query_cache: true + connection_keys: + default: custom_key parameters: kernel.secret: foo diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 09fa644..5ddcbb4 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,6 +1,8 @@ 'doctrine:database:create', ])); - $kernel->getContainer()->get('doctrine')->getConnection()->executeQuery('CREATE TABLE test (test VARCHAR(10))'); + /** @var ManagerRegistry $registry */ + $registry = $kernel->getContainer()->get('doctrine'); + + /** @var Connection $connection */ + $connection = $registry->getConnection(); + $connection->executeQuery('CREATE TABLE test (test VARCHAR(10))'); + $kernel->shutdown(); } From 8fa3b00195c8374a2d076e8ba7149f05bc30a2e9 Mon Sep 17 00:00:00 2001 From: David Maicher Date: Tue, 21 May 2024 20:03:35 +0200 Subject: [PATCH 2/2] adjust readme --- README.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/README.md b/README.md index b047de8..7affbde 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,51 @@ dama_doctrine_test: connection_a: true ``` +#### Controlling how connections are kept statically in the current php process + +By default, every configured doctrine DBAL connection will have its own driver connection that is managed in the current php process. +In case you need to customize this behavior you can choose different "connection keys" that are used to select driver connections. + +Example for 2 connections that will re-use the same driver connection instance: + +```yaml +doctrine: + dbal: + connections: + default: + url: '%database.url1%' + + foo: + url: '%database.url2%' + +dama_doctrine_test: + connection_keys: + # assigning the same key will result in the same internal driver connection being re-used for both DBAL connections + default: custom_key + foo: custom_key +``` + +**Since v8.1.0**: For connections with read/write replicas the bundle will use the **same** underlying driver connection by default for the primary and also for replicas. This addresses an [issue](https://github.com/dmaicher/doctrine-test-bundle/issues/289) where inconsistencies happened when reading/writing to different connections. This can also be customized as follows: + +```yaml +doctrine: + dbal: + connections: + default: + url: '%database.url%' + replicas: + replica_one: + url: '%database.url_replica%' + +dama_doctrine_test: + connection_keys: + # assigning different keys will result in separate internal driver connection being used for primary and replica + default: + primary: custom_key_primary + replicas: + replica_one: custom_key_primary_replica +``` + ### Example An example usage can be seen within the functional tests included in this bundle: https://github.com/dmaicher/doctrine-test-bundle/tree/master/tests