Skip to content

Commit 75adbe9

Browse files
committed
Allow to use dbal logging middleware
instead of deprecated SQLLogger
1 parent b75fb15 commit 75adbe9

File tree

5 files changed

+155
-0
lines changed

5 files changed

+155
-0
lines changed

DependencyInjection/Configuration.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,9 @@ private function getDbalConnectionsNode(): ArrayNodeDefinition
187187
->useAttributeAsKey('name')
188188
->prototype('scalar')->end()
189189
->end()
190+
->booleanNode('use_middlewares')
191+
->defaultFalse()
192+
->end()
190193
->end();
191194

192195
// dbal < 2.11

DependencyInjection/DoctrineExtension.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepositoryInterface;
1414
use Doctrine\DBAL\Connection;
1515
use Doctrine\DBAL\Connections\PrimaryReadReplicaConnection;
16+
use Doctrine\DBAL\Driver\Middleware;
1617
use Doctrine\DBAL\Logging\LoggerChain;
1718
use Doctrine\DBAL\Tools\Console\Command\ImportCommand;
1819
use Doctrine\DBAL\Tools\Console\ConnectionProvider;
@@ -37,6 +38,7 @@
3738
use Symfony\Bridge\Doctrine\Validator\DoctrineLoader;
3839
use Symfony\Component\Cache\Adapter\ArrayAdapter;
3940
use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
41+
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
4042
use Symfony\Component\Config\FileLocator;
4143
use Symfony\Component\DependencyInjection\Alias;
4244
use Symfony\Component\DependencyInjection\ChildDefinition;
@@ -156,6 +158,7 @@ protected function loadDbalConnection($name, array $connection, ContainerBuilder
156158
$configuration = $container->setDefinition(sprintf('doctrine.dbal.%s_connection.configuration', $name), new ChildDefinition('doctrine.dbal.connection.configuration'));
157159
$logger = null;
158160
if ($connection['logging']) {
161+
$this->useMiddlewaresIfAvailable($connection, $container, $name, $configuration);
159162
$logger = new Reference('doctrine.dbal.logger');
160163
}
161164

@@ -1066,4 +1069,29 @@ private function createArrayAdapterCachePool(ContainerBuilder $container, string
10661069

10671070
return $id;
10681071
}
1072+
1073+
/** @param array<string, mixed> $connection */
1074+
protected function useMiddlewaresIfAvailable(array $connection, ContainerBuilder $container, string $name, Definition $configuration): void
1075+
{
1076+
if (! $connection['use_middlewares']) {
1077+
return;
1078+
}
1079+
1080+
/** @psalm-suppress UndefinedClass */
1081+
if (! interface_exists(Middleware::class)) {
1082+
throw new InvalidConfigurationException(sprintf('%s must exist to set use_middlewares to true', Middleware::class));
1083+
}
1084+
1085+
$container
1086+
->getDefinition('doctrine.dbal.logger')
1087+
->replaceArgument(0, null);
1088+
1089+
$loggingMiddlewareDef = $container->setDefinition(
1090+
sprintf('doctrine.dbal.%s_connection.logging_middleware', $name),
1091+
new ChildDefinition('doctrine.dbal.logging_middleware')
1092+
);
1093+
$loggingMiddlewareDef->addTag('monolog.logger', ['channel' => 'doctrine']);
1094+
1095+
$configuration->addMethodCall('setMiddlewares', [[$loggingMiddlewareDef]]);
1096+
}
10691097
}

Resources/config/dbal.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
<argument type="service" id="debug.stopwatch" on-invalid="null" />
3737
</service>
3838

39+
<service id="doctrine.dbal.logging_middleware" class="Doctrine\DBAL\Logging\Middleware" abstract="true">
40+
<argument type="service" id="logger" on-invalid="null" />
41+
</service>
42+
3943
<service id="data_collector.doctrine" class="%doctrine.data_collector.class%" public="false">
4044
<tag name="data_collector" template="@Doctrine/Collector/db.html.twig" id="db" priority="250" />
4145
<argument type="service" id="doctrine" />

Tests/DependencyInjection/AbstractDoctrineExtensionTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ public function testDbalLoadSingleMasterSlaveConnection(): void
197197
'dbname' => 'mysql_db',
198198
'host' => 'localhost',
199199
'unix_socket' => '/path/to/mysqld.sock',
200+
'use_middlewares' => false,
200201
],
201202
$param['primary'] ?? $param['master'] // TODO: Remove 'master' support here when we require dbal >= 2.11
202203
);
@@ -229,6 +230,7 @@ public function testDbalLoadPoolShardingConnection(): void
229230
'dbname' => 'mysql_db',
230231
'host' => 'localhost',
231232
'unix_socket' => '/path/to/mysqld.sock',
233+
'use_middlewares' => false,
232234
],
233235
$param['global']
234236
);
@@ -283,6 +285,7 @@ public function testLoadSimpleSingleConnection(): void
283285
'driver' => 'pdo_mysql',
284286
'driverOptions' => [],
285287
'defaultTableOptions' => [],
288+
'use_middlewares' => false,
286289
],
287290
new Reference('doctrine.dbal.default_connection.configuration'),
288291
new Reference('doctrine.dbal.default_connection.event_manager'),
@@ -322,6 +325,7 @@ public function testLoadSimpleSingleConnectionWithoutDbName(): void
322325
'driver' => 'pdo_mysql',
323326
'driverOptions' => [],
324327
'defaultTableOptions' => [],
328+
'use_middlewares' => false,
325329
],
326330
new Reference('doctrine.dbal.default_connection.configuration'),
327331
new Reference('doctrine.dbal.default_connection.event_manager'),
@@ -362,6 +366,7 @@ public function testLoadSingleConnection(): void
362366
'dbname' => 'sqlite_db',
363367
'memory' => true,
364368
'defaultTableOptions' => [],
369+
'use_middlewares' => false,
365370
],
366371
new Reference('doctrine.dbal.default_connection.configuration'),
367372
new Reference('doctrine.dbal.default_connection.event_manager'),

Tests/DependencyInjection/DoctrineExtensionTest.php

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
1414
use Doctrine\DBAL\Connection;
1515
use Doctrine\DBAL\Driver\Connection as DriverConnection;
16+
use Doctrine\DBAL\Driver\Middleware;
1617
use Doctrine\DBAL\Sharding\PoolingShardManager;
1718
use Doctrine\DBAL\Sharding\SQLAzure\SQLAzureShardManager;
1819
use Doctrine\ORM\EntityManagerInterface;
@@ -24,6 +25,7 @@
2425
use Symfony\Bridge\Doctrine\Messenger\DoctrineClearEntityManagerWorkerSubscriber;
2526
use Symfony\Component\Cache\Adapter\ArrayAdapter;
2627
use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
28+
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
2729
use Symfony\Component\DependencyInjection\ChildDefinition;
2830
use Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass;
2931
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -33,6 +35,7 @@
3335
use Symfony\Component\HttpKernel\Kernel;
3436
use Symfony\Component\Messenger\MessageBusInterface;
3537

38+
use function array_filter;
3639
use function array_values;
3740
use function class_exists;
3841
use function interface_exists;
@@ -1143,6 +1146,118 @@ public function testAsEntityListenerAttribute()
11431146
$this->assertSame([$expected], $definition->getTag('doctrine.orm.entity_listener'));
11441147
}
11451148

1149+
public function testUseMiddlewaresNotActivated(): void
1150+
{
1151+
$container = $this->getContainer();
1152+
$extension = new DoctrineExtension();
1153+
1154+
$config = BundleConfigurationBuilder::createBuilderWithBaseValues()
1155+
->addConnection([
1156+
'connections' => [
1157+
'default' => [
1158+
'password' => 'foo',
1159+
'logging' => true,
1160+
],
1161+
],
1162+
])
1163+
->addBaseEntityManager()
1164+
->build();
1165+
1166+
$extension->load([$config], $container);
1167+
1168+
$loggerDef = $container->getDefinition('doctrine.dbal.logger');
1169+
$tags = $loggerDef->getTag('monolog.logger');
1170+
$doctrineLoggerTags = array_filter($tags, static function (array $tag): bool {
1171+
return ($tag['channel'] ?? null) === 'doctrine';
1172+
});
1173+
$this->assertCount(1, $doctrineLoggerTags);
1174+
1175+
$this->assertInstanceOf(Reference::class, $loggerDef->getArgument(0));
1176+
$this->assertSame('logger', (string) $loggerDef->getArgument(0));
1177+
1178+
$this->assertFalse($container->hasDefinition('doctrine.dbal.default_connection.logging_middleware'));
1179+
}
1180+
1181+
public function testUseMiddlewaresActivated(): void
1182+
{
1183+
/** @psalm-suppress UndefinedClass */
1184+
if (! interface_exists(Middleware::class)) {
1185+
$this->markTestSkipped(sprintf('%s needs %s to exist', __METHOD__, Middleware::class));
1186+
}
1187+
1188+
$container = $this->getContainer();
1189+
$extension = new DoctrineExtension();
1190+
1191+
$config = BundleConfigurationBuilder::createBuilderWithBaseValues()
1192+
->addConnection([
1193+
'connections' => [
1194+
'default' => [
1195+
'password' => 'foo',
1196+
'logging' => true,
1197+
'use_middlewares' => true,
1198+
],
1199+
],
1200+
])
1201+
->addBaseEntityManager()
1202+
->build();
1203+
1204+
$extension->load([$config], $container);
1205+
1206+
$loggerDef = $container->getDefinition('doctrine.dbal.logger');
1207+
$this->assertNull($loggerDef->getArgument(0));
1208+
1209+
$loggingMiddlewareDef = $container->getDefinition('doctrine.dbal.default_connection.logging_middleware');
1210+
$tags = $loggingMiddlewareDef->getTag('monolog.logger');
1211+
$doctrineLoggerTags = array_filter($tags, static function (array $tag): bool {
1212+
return ($tag['channel'] ?? null) === 'doctrine';
1213+
});
1214+
$this->assertCount(1, $doctrineLoggerTags);
1215+
1216+
$this->assertInstanceOf(ChildDefinition::class, $loggingMiddlewareDef);
1217+
$parentDef = $container->getDefinition($loggingMiddlewareDef->getParent());
1218+
$this->assertInstanceOf(Reference::class, $parentDef->getArgument(0));
1219+
$this->assertSame('logger', (string) $parentDef->getArgument(0));
1220+
1221+
$connectionConfiguration = $container->getDefinition('doctrine.dbal.default_connection.configuration');
1222+
$setMiddlewareCalls = array_filter($connectionConfiguration->getMethodCalls(), static function (array $call) {
1223+
return $call[0] === 'setMiddlewares';
1224+
});
1225+
$this->assertCount(1, $setMiddlewareCalls);
1226+
$callArgs = $setMiddlewareCalls[0][1];
1227+
$this->assertCount(1, $callArgs);
1228+
$this->assertCount(1, $callArgs[0]);
1229+
$this->assertInstanceOf(Definition::class, $callArgs[0][0]);
1230+
}
1231+
1232+
public function testUseMiddlewaresWithoutMiddlewareInterface(): void
1233+
{
1234+
/** @psalm-suppress UndefinedClass */
1235+
if (interface_exists(Middleware::class)) {
1236+
$this->markTestSkipped(sprintf('%s needs %s to not exist', __METHOD__, Middleware::class));
1237+
}
1238+
1239+
$this->expectException(InvalidConfigurationException::class);
1240+
$this->expectExceptionMessage(sprintf('%s must exist to set use_middlewares to true', Middleware::class));
1241+
1242+
$container = $this->getContainer();
1243+
$extension = new DoctrineExtension();
1244+
1245+
$config = BundleConfigurationBuilder::createBuilderWithBaseValues()
1246+
->addConnection([
1247+
'connections' => [
1248+
'default' => [
1249+
'password' => 'foo',
1250+
'logging' => true,
1251+
'use_middlewares' => true,
1252+
],
1253+
],
1254+
])
1255+
->addBaseEntityManager()
1256+
->build();
1257+
1258+
$extension->load([$config], $container);
1259+
}
1260+
11461261
// phpcs:enable
11471262

11481263
/** @param list<string> $bundles */

0 commit comments

Comments
 (0)