Skip to content

Commit 57d9c6e

Browse files
committed
[dbal] Add DSN support.
1 parent cdb9236 commit 57d9c6e

File tree

4 files changed

+202
-8
lines changed

4 files changed

+202
-8
lines changed

docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ services:
1111
- './:/mqdev'
1212
environment:
1313
- AMQP_DSN=amqp://guest:guest@rabbitmq:5672/mqdev
14+
- DOCTINE_DSN=mysql+doctrine://root:rootpass@mysql/mqdev
1415
- SYMFONY__RABBITMQ__HOST=rabbitmq
1516
- SYMFONY__RABBITMQ__USER=guest
1617
- SYMFONY__RABBITMQ__PASSWORD=guest

pkg/dbal/DbalConnectionFactory.php

Lines changed: 82 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,33 @@ class DbalConnectionFactory implements PsrConnectionFactory
1919
private $connection;
2020

2121
/**
22+
* The config could be an array, string DSN or null. In case of null it will attempt to connect to mysql localhost with default credentials.
23+
*
2224
* $config = [
2325
* 'connection' => [] - dbal connection options. see http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html
2426
* 'table_name' => 'enqueue', - database table name.
2527
* 'polling_interval' => '1000', - How often query for new messages (milliseconds)
2628
* 'lazy' => true, - Use lazy database connection (boolean)
27-
* ].
29+
* ]
30+
*
31+
* or
32+
*
33+
* mysql://user:pass@localhost:3606/db?charset=UTF-8
2834
*
29-
* @param $config
35+
* @param array|string|null $config
3036
*/
31-
public function __construct(array $config = [])
37+
public function __construct($config = 'mysql://')
3238
{
33-
$this->config = array_replace([
34-
'connection' => [],
35-
'lazy' => true,
36-
], $config);
39+
if (empty($config)) {
40+
$config = $this->parseDsn('mysql://');
41+
} elseif (is_string($config)) {
42+
$config = $this->parseDsn($config);
43+
} elseif (is_array($config)) {
44+
} else {
45+
throw new \LogicException('The config must be either an array of options, a DSN string or null');
46+
}
47+
48+
$this->config = $config;
3749
}
3850

3951
/**
@@ -74,4 +86,67 @@ private function establishConnection()
7486

7587
return $this->connection;
7688
}
89+
90+
/**
91+
* @param string $dsn
92+
*
93+
* @return array
94+
*/
95+
private function parseDsn($dsn)
96+
{
97+
if (false === strpos($dsn, '://')) {
98+
throw new \LogicException(sprintf('The given DSN "%s" is not valid. Must contain "://".', $dsn));
99+
}
100+
101+
list($schema, $rest) = explode('://', $dsn, 2);
102+
103+
$supported = [
104+
'db2' => true,
105+
'ibm_db2' => true,
106+
'mssql' => true,
107+
'pdo_sqlsrv' => true,
108+
'mysql' => true,
109+
'mysql2' => true,
110+
'pdo_mysql' => true,
111+
'pgsql' => true,
112+
'postgres' => true,
113+
'postgresql' => true,
114+
'pdo_pgsql' => true,
115+
'sqlite' => true,
116+
'sqlite3' => true,
117+
'pdo_sqlite' => true,
118+
'db2+doctrine' => true,
119+
'ibm_db2+doctrine' => true,
120+
'mssql+doctrine' => true,
121+
'pdo_sqlsrv+doctrine' => true,
122+
'mysql+doctrine' => true,
123+
'mysql2+doctrine' => true,
124+
'pdo_mysql+doctrine' => true,
125+
'pgsql+doctrine' => true,
126+
'postgres+doctrine' => true,
127+
'postgresql+doctrine' => true,
128+
'pdo_pgsql+doctrine' => true,
129+
'sqlite+doctrine' => true,
130+
'sqlite3+doctrine' => true,
131+
'pdo_sqlite+doctrine' => true,
132+
];
133+
134+
if (false == isset($supported[$schema])) {
135+
throw new \LogicException(sprintf(
136+
'The given DSN schema "%s" is not supported. There are supported schemes: "%s".',
137+
$schema,
138+
implode('", "', array_keys($supported))
139+
));
140+
}
141+
142+
$doctrineSchema = str_replace('+doctrine', '', $schema);
143+
$doctrineUrl = empty($rest) ?
144+
$doctrineSchema.'://root@localhost' :
145+
str_replace($schema, $doctrineSchema, $dsn)
146+
;
147+
148+
return ['connection' => [
149+
'url' => $doctrineUrl,
150+
]];
151+
}
77152
}

pkg/dbal/DbalContext.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@ public function __construct($connection, array $config = [])
4343
} elseif (is_callable($connection)) {
4444
$this->connectionFactory = $connection;
4545
} else {
46-
throw new \InvalidArgumentException('The connection argument must be either Doctrine\DBAL\Connection or callable that returns Doctrine\DBAL\Connection.');
46+
throw new \InvalidArgumentException(sprintf(
47+
'The connection argument must be either %s or callable that returns %s.',
48+
Connection::class,
49+
Connection::class
50+
));
4751
}
4852
}
4953

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
<?php
2+
3+
namespace Enqueue\Dbal\Tests;
4+
5+
use Enqueue\Dbal\DbalConnectionFactory;
6+
use Enqueue\Test\ClassExtensionTrait;
7+
use PHPUnit\Framework\TestCase;
8+
9+
/**
10+
* The class contains the factory tests dedicated to configuration.
11+
*/
12+
class DbalConnectionFactoryConfigTest extends TestCase
13+
{
14+
use ClassExtensionTrait;
15+
16+
public function testThrowNeitherArrayStringNorNullGivenAsConfig()
17+
{
18+
$this->expectException(\LogicException::class);
19+
$this->expectExceptionMessage('The config must be either an array of options, a DSN string or null');
20+
21+
new DbalConnectionFactory(new \stdClass());
22+
}
23+
24+
public function testThrowIfSchemeIsNotSupported()
25+
{
26+
$this->expectException(\LogicException::class);
27+
$this->expectExceptionMessage('The given DSN schema "http" is not supported. There are supported schemes: "db2", "ibm_db2", "mssql", "pdo_sqlsrv", "mysql", "mysql2", "pdo_mysql", "pgsql", "postgres", "postgresql", "pdo_pgsql", "sqlite", "sqlite3", "pdo_sqlite"');
28+
29+
new DbalConnectionFactory('http://example.com');
30+
}
31+
32+
public function testThrowIfDsnCouldNotBeParsed()
33+
{
34+
$this->expectException(\LogicException::class);
35+
$this->expectExceptionMessage('The given DSN "invalidDSN" is not valid. Must contain "://".');
36+
37+
new DbalConnectionFactory('invalidDSN');
38+
}
39+
40+
/**
41+
* @dataProvider provideConfigs
42+
*
43+
* @param mixed $config
44+
* @param mixed $expectedConfig
45+
*/
46+
public function testShouldParseConfigurationAsExpected($config, $expectedConfig)
47+
{
48+
$factory = new DbalConnectionFactory($config);
49+
50+
$this->assertAttributeEquals($expectedConfig, 'config', $factory);
51+
}
52+
53+
public static function provideConfigs()
54+
{
55+
yield [
56+
null,
57+
[
58+
'connection' => [
59+
'url' => 'mysql://root@localhost',
60+
],
61+
],
62+
];
63+
64+
yield [
65+
'mysql://',
66+
[
67+
'connection' => [
68+
'url' => 'mysql://root@localhost',
69+
],
70+
],
71+
];
72+
73+
yield [
74+
'mysql+doctrine://',
75+
[
76+
'connection' => [
77+
'url' => 'mysql://root@localhost',
78+
],
79+
],
80+
];
81+
82+
yield [
83+
'pgsql://',
84+
[
85+
'connection' => [
86+
'url' => 'pgsql://root@localhost',
87+
],
88+
],
89+
];
90+
91+
yield [
92+
'mysql://user:pass@host:10000/db',
93+
[
94+
'connection' => [
95+
'url' => 'mysql://user:pass@host:10000/db',
96+
],
97+
],
98+
];
99+
100+
yield [
101+
[],
102+
[
103+
'connection' => [
104+
'url' => 'mysql://root@localhost',
105+
],
106+
],
107+
];
108+
109+
yield [
110+
['table_name' => 'a_queue_table', 'connection' => ['foo' => 'fooVal', 'bar' => 'barVal']],
111+
['table_name' => 'a_queue_table', 'connection' => ['foo' => 'fooVal', 'bar' => 'barVal']],
112+
];
113+
}
114+
}

0 commit comments

Comments
 (0)