Skip to content

Commit 4bbc5da

Browse files
authored
Merge pull request #104 from php-enqueue/doctrine-dsn
[dbal] Add DSN support.
2 parents cdb9236 + 74c60a4 commit 4bbc5da

15 files changed

+298
-20
lines changed

Diff for: docker-compose.yml

+1
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://root:rootpass@mysql/mqdev
1415
- SYMFONY__RABBITMQ__HOST=rabbitmq
1516
- SYMFONY__RABBITMQ__USER=guest
1617
- SYMFONY__RABBITMQ__PASSWORD=guest

Diff for: pkg/dbal/DbalConnectionFactory.php

+65-7
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,50 @@ 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+
];
119+
120+
if (false == isset($supported[$schema])) {
121+
throw new \LogicException(sprintf(
122+
'The given DSN schema "%s" is not supported. There are supported schemes: "%s".',
123+
$schema,
124+
implode('", "', array_keys($supported))
125+
));
126+
}
127+
128+
return [
129+
'lazy' => true,
130+
'connection' => [
131+
'url' => empty($rest) ? $schema.'://root@localhost' : $dsn,
132+
],
133+
];
134+
}
77135
}

Diff for: pkg/dbal/DbalContext.php

+5-1
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

Diff for: pkg/dbal/Symfony/DbalTransportFactory.php

+12
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,16 @@ public function __construct($name = 'dbal')
3333
public function addConfiguration(ArrayNodeDefinition $builder)
3434
{
3535
$builder
36+
->beforeNormalization()
37+
->ifString()
38+
->then(function ($v) {
39+
return ['dsn' => $v];
40+
})
41+
->end()
3642
->children()
43+
->scalarNode('dsn')
44+
->info('The Doctrine DBAL DSN. Other parameters are ignored if set')
45+
->end()
3746
->variableNode('connection')
3847
->treatNullLike([])
3948
->info('Doctrine DBAL connection options. See http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html')
@@ -66,6 +75,9 @@ public function createConnectionFactory(ContainerBuilder $container, array $conf
6675
if (false == empty($config['dbal_connection_name'])) {
6776
$factory = new Definition(ManagerRegistryConnectionFactory::class);
6877
$factory->setArguments([new Reference('doctrine'), $config]);
78+
} elseif (false == empty($config['dsn'])) {
79+
$factory = new Definition(DbalConnectionFactory::class);
80+
$factory->setArguments([$config['dsn']]);
6981
} elseif (false == empty($config['connection'])) {
7082
$factory = new Definition(DbalConnectionFactory::class);
7183
$factory->setArguments([$config]);

Diff for: pkg/dbal/Tests/DbalConnectionFactoryConfigTest.php

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
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+
'lazy' => true,
59+
'connection' => [
60+
'url' => 'mysql://root@localhost',
61+
],
62+
],
63+
];
64+
65+
yield [
66+
'mysql://',
67+
[
68+
'lazy' => true,
69+
'connection' => [
70+
'url' => 'mysql://root@localhost',
71+
],
72+
],
73+
];
74+
75+
yield [
76+
'pgsql://',
77+
[
78+
'lazy' => true,
79+
'connection' => [
80+
'url' => 'pgsql://root@localhost',
81+
],
82+
],
83+
];
84+
85+
yield [
86+
'mysql://user:pass@host:10000/db',
87+
[
88+
'lazy' => true,
89+
'connection' => [
90+
'url' => 'mysql://user:pass@host:10000/db',
91+
],
92+
],
93+
];
94+
95+
yield [
96+
[],
97+
[
98+
'lazy' => true,
99+
'connection' => [
100+
'url' => 'mysql://root@localhost',
101+
],
102+
],
103+
];
104+
105+
yield [
106+
['table_name' => 'a_queue_table', 'connection' => ['foo' => 'fooVal', 'bar' => 'barVal']],
107+
['table_name' => 'a_queue_table', 'connection' => ['foo' => 'fooVal', 'bar' => 'barVal']],
108+
];
109+
}
110+
}

Diff for: pkg/dbal/Tests/DbalConnectionFactoryTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public function testCouldBeConstructedWithEmptyConfiguration()
2323

2424
$this->assertAttributeEquals([
2525
'lazy' => true,
26-
'connection' => [],
26+
'connection' => ['url' => 'mysql://root@localhost'],
2727
], 'config', $factory);
2828
}
2929

Diff for: pkg/dbal/Tests/Symfony/DbalTransportFactoryTest.php

+39
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,25 @@ public function testShouldAllowAddConfiguration()
6161
], $config);
6262
}
6363

64+
public function testShouldAllowAddConfigurationAsString()
65+
{
66+
$transport = new DbalTransportFactory();
67+
$tb = new TreeBuilder();
68+
$rootNode = $tb->root('foo');
69+
70+
$transport->addConfiguration($rootNode);
71+
$processor = new Processor();
72+
$config = $processor->process($tb->buildTree(), ['mysqlDSN']);
73+
74+
$this->assertEquals([
75+
'dsn' => 'mysqlDSN',
76+
'dbal_connection_name' => null,
77+
'table_name' => 'enqueue',
78+
'polling_interval' => 1000,
79+
'lazy' => true,
80+
], $config);
81+
}
82+
6483
public function testShouldCreateDbalConnectionFactory()
6584
{
6685
$container = new ContainerBuilder();
@@ -89,6 +108,26 @@ public function testShouldCreateDbalConnectionFactory()
89108
], $factory->getArgument(0));
90109
}
91110

111+
public function testShouldCreateConnectionFactoryFromDsnString()
112+
{
113+
$container = new ContainerBuilder();
114+
115+
$transport = new DbalTransportFactory();
116+
117+
$serviceId = $transport->createConnectionFactory($container, [
118+
'dsn' => 'theDSN',
119+
'connection' => [],
120+
'lazy' => true,
121+
'table_name' => 'enqueue',
122+
'polling_interval' => 1000,
123+
]);
124+
125+
$this->assertTrue($container->hasDefinition($serviceId));
126+
$factory = $container->getDefinition($serviceId);
127+
$this->assertEquals(DbalConnectionFactory::class, $factory->getClass());
128+
$this->assertSame('theDSN', $factory->getArgument(0));
129+
}
130+
92131
public function testShouldCreateManagerRegistryConnectionFactory()
93132
{
94133
$container = new ContainerBuilder();

Diff for: pkg/enqueue-bundle/DependencyInjection/EnqueueExtension.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public function load(array $configs, ContainerBuilder $container)
7070
$this->factories[$name]->createDriver($container, $transportConfig);
7171
}
7272

73-
if (false == isset($config['transport'][$config['transport']['default']['alias']])) {
73+
if (isset($config['transport']['default']['alias']) && false == isset($config['transport'][$config['transport']['default']['alias']])) {
7474
throw new \LogicException(sprintf('Transport is not enabled: %s', $config['transport']['default']['alias']));
7575
}
7676

@@ -82,7 +82,7 @@ public function load(array $configs, ContainerBuilder $container)
8282
$config['client']['router_queue'],
8383
$config['client']['default_processor_queue'],
8484
$config['client']['router_processor'],
85-
$config['transport'][$config['transport']['default']['alias']],
85+
isset($config['transport']['default']['alias']) ? $config['transport'][$config['transport']['default']['alias']] : [],
8686
]);
8787

8888
$container->setParameter('enqueue.client.router_queue_name', $config['client']['router_queue']);

Diff for: pkg/enqueue-bundle/Tests/Functional/App/CustomAppKernel.php

+5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
66
use Symfony\Component\Config\Loader\LoaderInterface;
77
use Symfony\Component\DependencyInjection\ContainerBuilder;
8+
use Symfony\Component\Filesystem\Filesystem;
89
use Symfony\Component\HttpKernel\Kernel;
910
use Symfony\Component\Routing\RouteCollectionBuilder;
1011

@@ -24,6 +25,10 @@ class CustomAppKernel extends Kernel
2425

2526
public function setEnqueueConfig(array $config)
2627
{
28+
$fs = new Filesystem();
29+
$fs->remove(sys_get_temp_dir().'/EnqueueBundleCustom/cache');
30+
$fs->mkdir(sys_get_temp_dir().'/EnqueueBundleCustom/cache');
31+
2732
$this->enqueueConfig = array_replace_recursive($this->enqueueConfig, $config);
2833
}
2934

0 commit comments

Comments
 (0)