Skip to content

Commit 770283b

Browse files
authored
Merge pull request #628 from php-enqueue/multi-client-configuration
[bundle] Multi Client Configuration
2 parents 0895695 + 22f1833 commit 770283b

File tree

5 files changed

+218
-13
lines changed

5 files changed

+218
-13
lines changed

GenericStatsStorageFactory.php

+51-11
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,58 @@
88

99
class GenericStatsStorageFactory implements StatsStorageFactory
1010
{
11-
public function create(string $dsn): StatsStorage
11+
public function create($config): StatsStorage
1212
{
13-
$schema = (new Dsn($dsn))->getScheme();
14-
15-
switch ($schema) {
16-
case 'influxdb':
17-
return new InfluxDbStorage($dsn);
18-
case 'wamp':
19-
case 'ws':
20-
return new WampStorage($dsn);
21-
default:
22-
throw new \LogicException(sprintf('Unsupported stats storage: "%s"', $dsn));
13+
if (is_string($config)) {
14+
$config = ['dsn' => $config];
2315
}
16+
17+
if (false == is_array($config)) {
18+
throw new \InvalidArgumentException('The config must be either array or DSN string.');
19+
}
20+
21+
if (false == array_key_exists('dsn', $config)) {
22+
throw new \InvalidArgumentException('The config must have dsn key set.');
23+
}
24+
25+
$dsn = new Dsn($config['dsn']);
26+
27+
if ($storageClass = $this->findStorageClass($dsn, Resources::getKnownStorages())) {
28+
return new $storageClass(1 === count($config) ? $config['dsn'] : $config);
29+
}
30+
31+
throw new \LogicException(sprintf('A given scheme "%s" is not supported.', $dsn->getScheme()));
32+
}
33+
34+
private function findStorageClass(Dsn $dsn, array $factories): ?string
35+
{
36+
$protocol = $dsn->getSchemeProtocol();
37+
38+
if ($dsn->getSchemeExtensions()) {
39+
foreach ($factories as $storageClass => $info) {
40+
if (empty($info['supportedSchemeExtensions'])) {
41+
continue;
42+
}
43+
44+
if (false == in_array($protocol, $info['schemes'], true)) {
45+
continue;
46+
}
47+
48+
$diff = array_diff($info['supportedSchemeExtensions'], $dsn->getSchemeExtensions());
49+
if (empty($diff)) {
50+
return $storageClass;
51+
}
52+
}
53+
}
54+
55+
foreach ($factories as $storageClass => $info) {
56+
if (false == in_array($protocol, $info['schemes'], true)) {
57+
continue;
58+
}
59+
60+
return $storageClass;
61+
}
62+
63+
return null;
2464
}
2565
}

Resources.php

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
namespace Enqueue\Monitoring;
4+
5+
final class Resources
6+
{
7+
/**
8+
* @var array
9+
*/
10+
private static $knownStorages = null;
11+
12+
private function __construct()
13+
{
14+
}
15+
16+
public static function getKnownSchemes(): array
17+
{
18+
$map = self::getKnownStorages();
19+
20+
$schemes = [];
21+
foreach ($map as $storageClass => $item) {
22+
foreach ($item['schemes'] as $scheme) {
23+
$schemes[$scheme] = $storageClass;
24+
}
25+
}
26+
27+
return $schemes;
28+
}
29+
30+
public static function getKnownStorages(): array
31+
{
32+
if (null === self::$knownStorages) {
33+
$map = [];
34+
35+
$map[WampStorage::class] = [
36+
'schemes' => ['wamp', 'ws'],
37+
'supportedSchemeExtensions' => [],
38+
];
39+
40+
$map[InfluxDbStorage::class] = [
41+
'schemes' => ['influxdb'],
42+
'supportedSchemeExtensions' => [],
43+
];
44+
45+
self::$knownStorages = $map;
46+
}
47+
48+
return self::$knownStorages;
49+
}
50+
}

StatsStorageFactory.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@
66

77
interface StatsStorageFactory
88
{
9-
public function create(string $dsn): StatsStorage;
9+
public function create($config): StatsStorage;
1010
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
<?php
2+
3+
namespace Enqueue\Monitoring\Symfony\DependencyInjection;
4+
5+
use Enqueue\Monitoring\ClientMonitoringExtension;
6+
use Enqueue\Monitoring\ConsumerMonitoringExtension;
7+
use Enqueue\Monitoring\GenericStatsStorageFactory;
8+
use Enqueue\Monitoring\Resources;
9+
use Enqueue\Monitoring\StatsStorage;
10+
use Enqueue\Monitoring\StatsStorageFactory;
11+
use Enqueue\Symfony\DiUtils;
12+
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
13+
use Symfony\Component\DependencyInjection\ContainerBuilder;
14+
use Symfony\Component\DependencyInjection\Reference;
15+
16+
/**
17+
* @internal
18+
*/
19+
final class MonitoringFactory
20+
{
21+
/**
22+
* @var DiUtils
23+
*/
24+
private $diUtils;
25+
26+
public function __construct(string $name)
27+
{
28+
if (empty($name)) {
29+
throw new \InvalidArgumentException('The name could not be empty.');
30+
}
31+
32+
$this->diUtils = DiUtils::create('monitoring', $name);
33+
}
34+
35+
public static function getConfiguration(string $name = 'monitoring'): ArrayNodeDefinition
36+
{
37+
$builder = new ArrayNodeDefinition($name);
38+
39+
$builder
40+
->info(sprintf('The "%s" option could accept a string DSN, an array with DSN key, or null. It accept extra options. To find out what option you can set, look at stats storage constructor doc block.', $name))
41+
->beforeNormalization()
42+
->always(function ($v) {
43+
if (is_array($v)) {
44+
if (isset($v['storage_factory_class']) && isset($v['storage_factory_service'])) {
45+
throw new \LogicException('Both options storage_factory_class and storage_factory_service are set. Please choose one.');
46+
}
47+
48+
return $v;
49+
}
50+
51+
if (is_string($v)) {
52+
return ['dsn' => $v];
53+
}
54+
55+
return $v;
56+
})
57+
->end()
58+
->ignoreExtraKeys(false)
59+
->children()
60+
->scalarNode('dsn')
61+
->cannotBeEmpty()
62+
->isRequired()
63+
->info(sprintf('The stats storage DSN. These schemes are supported: "%s".', implode('", "', array_keys(Resources::getKnownSchemes()))))
64+
->end()
65+
->scalarNode('storage_factory_service')
66+
->info(sprintf('The factory class should implement "%s" interface', StatsStorageFactory::class))
67+
->end()
68+
->scalarNode('storage_factory_class')
69+
->info(sprintf('The factory service should be a class that implements "%s" interface', StatsStorageFactory::class))
70+
->end()
71+
->end()
72+
;
73+
74+
return $builder;
75+
}
76+
77+
public function buildStorage(ContainerBuilder $container, array $config): void
78+
{
79+
$storageId = $this->diUtils->format('storage');
80+
$storageFactoryId = $this->diUtils->format('storage.factory');
81+
82+
if (isset($config['storage_factory_service'])) {
83+
$container->setAlias($storageFactoryId, $config['storage_factory_service']);
84+
} elseif (isset($config['storage_factory_class'])) {
85+
$container->register($storageFactoryId, $config['storage_factory_class']);
86+
} else {
87+
$container->register($storageFactoryId, GenericStatsStorageFactory::class);
88+
}
89+
90+
unset($config['storage_factory_service'], $config['storage_factory_class']);
91+
92+
$container->register($storageId, StatsStorage::class)
93+
->setFactory([new Reference($storageFactoryId), 'create'])
94+
->addArgument($config)
95+
;
96+
}
97+
98+
public function buildClientExtension(ContainerBuilder $container, array $config): void
99+
{
100+
$container->register($this->diUtils->format('client_extension'), ClientMonitoringExtension::class)
101+
->addArgument($this->diUtils->reference('storage'))
102+
->addArgument(new Reference('logger'))
103+
->addTag('enqueue.client_extension', ['client' => $this->diUtils->getConfigName()])
104+
;
105+
}
106+
107+
public function buildConsumerExtension(ContainerBuilder $container, array $config): void
108+
{
109+
$container->register($this->diUtils->format('consumer_extension'), ConsumerMonitoringExtension::class)
110+
->addArgument($this->diUtils->reference('storage'))
111+
->addTag('enqueue.consumption_extension', ['client' => $this->diUtils->getConfigName()])
112+
->addTag('enqueue.transport.consumption_extension', ['transport' => $this->diUtils->getConfigName()])
113+
;
114+
}
115+
}

Tests/GenericStatsStorageFactoryTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public function testShouldCreateWampStorage()
3535
public function testShouldThrowIfStorageIsNotSupported()
3636
{
3737
$this->expectException(\LogicException::class);
38-
$this->expectExceptionMessage('Unsupported stats storage: "unsupported:"');
38+
$this->expectExceptionMessage('A given scheme "unsupported" is not supported.');
3939

4040
(new GenericStatsStorageFactory())->create('unsupported:');
4141
}

0 commit comments

Comments
 (0)