Skip to content

Commit 265e8e9

Browse files
committed
add ability to override url
1 parent a1268d4 commit 265e8e9

10 files changed

+187
-9
lines changed

ConnectionFactory.php

+27-1
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,16 @@ public function createConnection(array $params, Configuration $config = null, Ev
4545
$this->initializeTypes();
4646
}
4747

48-
if (! isset($params['pdo']) && ! isset($params['charset'])) {
48+
$connectionOverrideOptions = [];
49+
50+
if (isset($params['connection_override_options'])) {
51+
$connectionOverrideOptions = $params['connection_override_options'];
52+
unset($params['connection_override_options']);
53+
}
54+
55+
if (! isset($params['pdo']) && (! isset($params['charset']) || (! empty($connectionOverrideOptions) && isset($params['url'])))) {
4956
$wrapperClass = null;
57+
5058
if (isset($params['wrapperClass'])) {
5159
if (! is_subclass_of($params['wrapperClass'], Connection::class)) {
5260
if (class_exists(DBALException::class)) {
@@ -64,6 +72,24 @@ public function createConnection(array $params, Configuration $config = null, Ev
6472
$params = $connection->getParams();
6573
$driver = $connection->getDriver();
6674

75+
if (! empty($connectionOverrideOptions)) {
76+
$supportedOverrideParams = [
77+
'dbname',
78+
'host',
79+
'port',
80+
'user',
81+
'password',
82+
];
83+
84+
foreach ($supportedOverrideParams as $paramKey) {
85+
if (! array_key_exists($paramKey, $connectionOverrideOptions)) {
86+
continue;
87+
}
88+
89+
$params[$paramKey] = $connectionOverrideOptions[$paramKey];
90+
}
91+
}
92+
6793
if ($driver instanceof AbstractMySQLDriver) {
6894
$params['charset'] = 'utf8mb4';
6995

DependencyInjection/Configuration.php

+5-4
Original file line numberDiff line numberDiff line change
@@ -217,10 +217,11 @@ private function configureDbalDriverNode(ArrayNodeDefinition $node): void
217217
->children()
218218
->scalarNode('url')->info('A URL with connection information; any parameter value parsed from this string will override explicitly set parameters')->end()
219219
->scalarNode('dbname')->end()
220-
->scalarNode('host')->defaultValue('localhost')->end()
221-
->scalarNode('port')->defaultNull()->end()
222-
->scalarNode('user')->defaultValue('root')->end()
223-
->scalarNode('password')->defaultNull()->end()
220+
->scalarNode('host')->info('Defaults to "localhost" at runtime.')->end()
221+
->scalarNode('port')->info('Default to null at runtime.')->end()
222+
->scalarNode('user')->info('Default to "root" at runtime.')->end()
223+
->scalarNode('password')->info('Default to null at runtime.')->end()
224+
->booleanNode('override_url')->info('Allows overriding URL parameters with dbname, host, port, user, and/or password parameters.')->end()
224225
->scalarNode('application_name')->end()
225226
->scalarNode('charset')->end()
226227
->scalarNode('path')->end()

DependencyInjection/DoctrineExtension.php

+65
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Doctrine\DBAL\SQLParserUtils;
1616
use Doctrine\DBAL\Tools\Console\Command\ImportCommand;
1717
use Doctrine\DBAL\Tools\Console\ConnectionProvider;
18+
use Doctrine\Deprecations\Deprecation;
1819
use Doctrine\ORM\EntityManagerInterface;
1920
use Doctrine\ORM\Id\AbstractIdGenerator;
2021
use Doctrine\ORM\Proxy\Autoloader;
@@ -254,6 +255,54 @@ protected function getConnectionOptions($connection)
254255
{
255256
$options = $connection;
256257

258+
$options['connection_override_options'] = [];
259+
260+
$connectionDefaults = [
261+
'dbname' => null,
262+
'host' => 'localhost',
263+
'port' => null,
264+
'user' => 'root',
265+
'password' => null,
266+
];
267+
268+
$allowOverrideUrl = $options['override_url'] ?? false;
269+
270+
if (! $allowOverrideUrl && isset($options['url'])) {
271+
Deprecation::trigger(
272+
'doctrine/doctrineBundle',
273+
'https://github.com/doctrine/DoctrineBundle/pull/1290',
274+
'Not setting doctrine.dbal.override_url to true is deprecated. True is the only value that will be supported in doctrine-bundle 3.0.'
275+
);
276+
}
277+
278+
if ($allowOverrideUrl) {
279+
foreach (array_keys($connectionDefaults) as $paramName) {
280+
if (! array_key_exists($paramName, $options)) {
281+
continue;
282+
}
283+
284+
$options['connection_override_options'][$paramName] = $options[$paramName];
285+
}
286+
}
287+
288+
unset($options['override_url'], $connectionDefaults['dbname']);
289+
290+
$nestedConnections = ['shards', 'replicas', 'slaves'];
291+
292+
foreach ($connectionDefaults as $defaultKey => $defaultValue) {
293+
if (! array_key_exists($defaultKey, $options)) {
294+
$options[$defaultKey] = $defaultValue;
295+
}
296+
297+
foreach ($nestedConnections as $connectionKey) {
298+
if (! array_key_exists($connectionKey, $options)) {
299+
continue;
300+
}
301+
302+
$options[$connectionKey] = $this->setDefaultOnNestedConnectionOption($options[$connectionKey], $defaultKey, $defaultValue);
303+
}
304+
}
305+
257306
if (isset($options['platform_service'])) {
258307
$options['platform'] = new Reference($options['platform_service']);
259308
unset($options['platform_service']);
@@ -975,4 +1024,20 @@ private function createArrayAdapterCachePool(ContainerBuilder $container, string
9751024

9761025
return $id;
9771026
}
1027+
1028+
/**
1029+
* @return array<string|int, array<string|int, mixed>>
1030+
*/
1031+
private function setDefaultOnNestedConnectionOption(array $connectionOptions, string $paramName, $defaultValue): array
1032+
{
1033+
foreach ($connectionOptions as $connectionKey => $connection) {
1034+
if (array_key_exists($paramName, $connection)) {
1035+
continue;
1036+
}
1037+
1038+
$connectionOptions[$connectionKey][$paramName] = $defaultValue;
1039+
}
1040+
1041+
return $connectionOptions;
1042+
}
9781043
}

Resources/config/schema/doctrine-1.0.xsd

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
<xsd:attribute name="port" type="xsd:string" />
5252
<xsd:attribute name="user" type="xsd:string" />
5353
<xsd:attribute name="password" type="xsd:string" />
54+
<xsd:attribute name="override-url" type="xsd:boolean" />
5455
<xsd:attribute name="application-name" type="xsd:string" />
5556
<xsd:attribute name="path" type="xsd:string" />
5657
<xsd:attribute name="unix-socket" type="xsd:string" />

Resources/doc/configuration.rst

+9-4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ Configuration Reference
2222
connections:
2323
# A collection of different named connections (e.g. default, conn2, etc)
2424
default:
25+
# If true, allows overriding url parameters with explicitly set parameters.
26+
# "dbname", "host", "port", "user", and/or "password" can be overridden.
27+
override_url: ~
2528
dbname: ~
2629
host: localhost
2730
port: ~
@@ -914,10 +917,11 @@ Doctrine DBAL Configuration
914917
.. note::
915918

916919
When specifying a ``url`` parameter, any information extracted from that
917-
URL will override explicitly set parameters. An example database URL
918-
would be ``mysql://snoopy:redbaron@localhost/baseball``, and any explicitly
919-
set driver, user, password and dbname parameter would be overridden by
920-
this URL. See the Doctrine `DBAL documentation`_ for more information.
920+
URL will override explicitly set parameters unless ``override_url`` is set
921+
to ``true``. An example database URL would be
922+
``mysql://snoopy:redbaron@localhost/baseball``, and any explicitly set driver,
923+
user, password and dbname parameter would be overridden by this URL.
924+
See the Doctrine `DBAL documentation`_ for more information.
921925

922926
Besides default Doctrine options, there are some Symfony-related ones that you
923927
can configure. The following block shows all possible configuration keys:
@@ -928,6 +932,7 @@ can configure. The following block shows all possible configuration keys:
928932
929933
doctrine:
930934
dbal:
935+
override_url: true
931936
url: mysql://user:secret@localhost:1234/otherdatabase # this would override the values below
932937
dbname: database
933938
host: localhost

Tests/ConnectionFactoryTest.php

+25
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,31 @@ public function testDefaultCharsetMySql(): void
7171

7272
$this->assertSame('utf8mb4', $connection->getParams()['charset']);
7373
}
74+
75+
public function testUrlOverride(): void
76+
{
77+
$factory = new ConnectionFactory([]);
78+
$url = 'mysql://root:password@database:3306/main?serverVersion=mariadb-10.5.8';
79+
80+
$params = [
81+
'dbname' => 'main_test',
82+
'host' => 'db_test',
83+
'port' => 5432,
84+
'user' => 'tester',
85+
'password' => 'wordpass',
86+
];
87+
88+
$connection = $factory->createConnection([
89+
'url' => $url,
90+
'connection_override_options' => $params,
91+
]);
92+
93+
$result = $connection->getParams();
94+
95+
foreach ($params as $paramKey => $expectedValue) {
96+
self::assertSame($expectedValue, $result[$paramKey]);
97+
}
98+
}
7499
}
75100

76101
/**

Tests/DependencyInjection/AbstractDoctrineExtensionTest.php

+30
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,31 @@ public function testDbalLoadFromXmlSingleConnections(): void
113113
$this->assertEquals('5.6.20', $config['serverVersion']);
114114
}
115115

116+
public function testDbalLoadUrlOverride(): void
117+
{
118+
$container = $this->loadContainer('dbal_allow_url_override');
119+
120+
// doctrine.dbal.mysql_connection
121+
$config = $container->getDefinition('doctrine.dbal.default_connection')->getArgument(0);
122+
123+
$this->assertSame('mysql://root:password@database:3306/main?serverVersion=mariadb-10.5.8', $config['url']);
124+
125+
$expectedOverrides = [
126+
'dbname' => 'main_test',
127+
'host' => 'docker',
128+
'port' => 4321,
129+
'user' => 'tester',
130+
'password' => 'wordpass',
131+
];
132+
133+
foreach ($expectedOverrides as $param => $value) {
134+
$this->assertSame($value, $config[$param]);
135+
}
136+
137+
$this->assertSame($expectedOverrides, $config['connection_override_options']);
138+
$this->assertFalse(isset($config['override_url']));
139+
}
140+
116141
public function testDbalLoadSingleMasterSlaveConnection(): void
117142
{
118143
$container = $this->loadContainer('dbal_service_single_master_slave_connection');
@@ -135,6 +160,7 @@ class_exists(PrimaryReadReplicaConnection::class) ?
135160
'dbname' => 'mysql_db',
136161
'host' => 'localhost',
137162
'unix_socket' => '/path/to/mysqld.sock',
163+
'connection_override_options' => [],
138164
],
139165
$param['primary'] ?? $param['master'] // TODO: Remove 'master' support here when we require dbal >= 2.11
140166
);
@@ -169,6 +195,7 @@ public function testDbalLoadPoolShardingConnection(): void
169195
'dbname' => 'mysql_db',
170196
'host' => 'localhost',
171197
'unix_socket' => '/path/to/mysqld.sock',
198+
'connection_override_options' => [],
172199
],
173200
$param['global']
174201
);
@@ -223,6 +250,7 @@ public function testLoadSimpleSingleConnection(): void
223250
'driver' => 'pdo_mysql',
224251
'driverOptions' => [],
225252
'defaultTableOptions' => [],
253+
'connection_override_options' => [],
226254
],
227255
new Reference('doctrine.dbal.default_connection.configuration'),
228256
new Reference('doctrine.dbal.default_connection.event_manager'),
@@ -262,6 +290,7 @@ public function testLoadSimpleSingleConnectionWithoutDbName(): void
262290
'driver' => 'pdo_mysql',
263291
'driverOptions' => [],
264292
'defaultTableOptions' => [],
293+
'connection_override_options' => [],
265294
],
266295
new Reference('doctrine.dbal.default_connection.configuration'),
267296
new Reference('doctrine.dbal.default_connection.event_manager'),
@@ -302,6 +331,7 @@ public function testLoadSingleConnection(): void
302331
'dbname' => 'sqlite_db',
303332
'memory' => true,
304333
'defaultTableOptions' => [],
334+
'connection_override_options' => [],
305335
],
306336
new Reference('doctrine.dbal.default_connection.configuration'),
307337
new Reference('doctrine.dbal.default_connection.event_manager'),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" ?>
2+
3+
<srv:container xmlns="http://symfony.com/schema/dic/doctrine"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xmlns:srv="http://symfony.com/schema/dic/services"
6+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
7+
http://symfony.com/schema/dic/doctrine http://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd">
8+
9+
<config>
10+
<dbal override-url="true" dbname="main_test" user="tester" password="wordpass" host="docker" port="4321" url="mysql://root:password@database:3306/main?serverVersion=mariadb-10.5.8" />
11+
</config>
12+
</srv:container>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
doctrine:
2+
dbal:
3+
override_url: true
4+
url: 'mysql://root:password@database:3306/main?serverVersion=mariadb-10.5.8'
5+
dbname: main_test
6+
user: tester
7+
password: wordpass
8+
host: docker
9+
port: 4321

UPGRADE-2.3.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
UPGRADE FROM 2.2 to 2.3
22
=======================
33

4+
Configuration
5+
--------
6+
* Not setting `doctrine.dbal.override_url` to `true` when using a `url` parameter in a connection is deprecated.
7+
48
DependencyInjection
59
--------
610

0 commit comments

Comments
 (0)