From d15bc89b5924c8300810d9bbedc97d8125e4f10b Mon Sep 17 00:00:00 2001 From: Daniele Scibilia Date: Tue, 2 May 2023 21:46:04 +0200 Subject: [PATCH] Allow customizing URI options more --- composer.json | 3 +- docs/Documentation.md | 47 +++++++++++++++++++ phpstan-baseline.neon | 22 ++++++++- src/DependencyInjection/Configuration.php | 14 ++++++ .../MongoDbBundleExtension.php | 6 +++ src/Services/ClientRegistry.php | 22 ++++++--- .../UriOptions/UriOptionsInterface.php | 22 +++++++++ tests/Unit/Services/ClientRegistryTest.php | 6 +-- 8 files changed, 131 insertions(+), 11 deletions(-) create mode 100644 src/Services/UriOptions/UriOptionsInterface.php diff --git a/composer.json b/composer.json index d22258c0..5e8a4064 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,8 @@ "facile-it/facile-coding-standard": "^0.4.0", "phpstan/phpstan": "^0.12.88", "phpstan/extension-installer": "^1.1", - "jangregor/phpstan-prophecy": "^0.8.1" + "jangregor/phpstan-prophecy": "^0.8.1", + "phpspec/prophecy": "~1.0" }, "minimum-stability": "stable", "suggest": { diff --git a/docs/Documentation.md b/docs/Documentation.md index aae9e774..6cb1dd4d 100644 --- a/docs/Documentation.md +++ b/docs/Documentation.md @@ -90,10 +90,57 @@ mongo_db_bundle: client_name: ~ database_name: ~ + # Service reference to provide URI options - see example below + uriOptions: 'App\Services\UriOptionsProvider' # default null + # Service reference to provide driver options - see example below driverOptions: 'App\Services\DriverOptionsProvider' # default null ``` +### Uri options + +You might need to specify some URI options for constructing the `MongoDB\Client`. Read the [reference] for a complete +explanation of all the available options. + +Implement `UriOptionsInterface` and declare the class as a Symfony service. + +```php +namespace App\Services; + +use Facile\MongoDbBundle\Services\UriOptions\UriOptionsInterface; + +final class MyCustomUriOptionsProvider implements DriverOptionsInterface +{ + /** @var string */ + private $appname; + + public function __construct(string $appname) { + $this->appname = $appname; + } + + public function buildDriverOptions(array $clientConfiguration) : array { + $clientConfiguration['appname'] = $this->appname; + return $clientConfiguration; + } +} +``` + +```yaml +# config/services.yaml +App\Services\MyCustomUriOptionsProvider: + arguments: + $appname: 'APPNAME' +``` + +Then use its service id as value of `uriOptions` in the bundle configuration. + +```yml +# config/packages/facile_it_mongodb.yaml +mongo_db_bundle: + uriOptions: 'App\Services\MyCustomUriOptionsProvider' + # ... +``` + ### Driver options You might need to specify some driver options for constructing the `MongoDB\Client`. Read the [reference] for a complete diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 93345f63..d017042a 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -80,6 +80,11 @@ parameters: count: 1 path: src/Capsule/Collection.php + - + message: "#^Method Facile\\\\MongoDbBundle\\\\Capsule\\\\Collection\\:\\:distinct\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/Capsule/Collection.php + - message: "#^Method Facile\\\\MongoDbBundle\\\\Capsule\\\\Collection\\:\\:find\\(\\) has parameter \\$filter with no value type specified in iterable type array\\.$#" count: 1 @@ -430,6 +435,11 @@ parameters: count: 1 path: src/DependencyInjection/MongoDbBundleExtension.php + - + message: "#^Method Facile\\\\MongoDbBundle\\\\DependencyInjection\\\\MongoDbBundleExtension\\:\\:defineUriOptionsFactory\\(\\) has parameter \\$config with no value type specified in iterable type array\\.$#" + count: 1 + path: src/DependencyInjection/MongoDbBundleExtension.php + - message: "#^Method Facile\\\\MongoDbBundle\\\\DependencyInjection\\\\MongoDbBundleExtension\\:\\:load\\(\\) has no return typehint specified\\.$#" count: 1 @@ -446,7 +456,7 @@ parameters: path: src/DependencyInjection/MongoDbBundleExtension.php - - message: "#^Parameter \\#2 \\$debug of method Facile\\\\MongoDbBundle\\\\DependencyInjection\\\\MongoDbBundleExtension\\:\\:defineClientRegistry\\(\\) expects bool, array\\|bool\\|float\\|int\\|string\\|null given\\.$#" + message: "#^Parameter \\#2 \\$debug of method Facile\\\\MongoDbBundle\\\\DependencyInjection\\\\MongoDbBundleExtension\\:\\:defineClientRegistry\\(\\) expects bool, array\\|bool\\|float\\|int\\|string\\|UnitEnum\\|null given\\.$#" count: 1 path: src/DependencyInjection/MongoDbBundleExtension.php @@ -780,6 +790,16 @@ parameters: count: 1 path: src/Services/Loggers/MongoQueryLogger.php + - + message: "#^Method Facile\\\\MongoDbBundle\\\\Services\\\\UriOptions\\\\UriOptionsInterface\\:\\:buildUriOptions\\(\\) has parameter \\$clientConfiguration with no value type specified in iterable type array\\.$#" + count: 1 + path: src/Services/UriOptions/UriOptionsInterface.php + + - + message: "#^Method Facile\\\\MongoDbBundle\\\\Services\\\\UriOptions\\\\UriOptionsInterface\\:\\:buildUriOptions\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/Services/UriOptions/UriOptionsInterface.php + - message: "#^Class Twig_Extension not found\\.$#" count: 1 diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 3ee2da1c..96d4d469 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -28,6 +28,7 @@ public function getConfigTreeBuilder(): TreeBuilder self::addDataCollection($rootBuilder->children()); self::addClients($rootBuilder->children()); self::addConnections($rootBuilder->children()); + self::addUriOptions($rootBuilder->children()); self::addDriversOption($rootBuilder->children()); return $treeBuilder; @@ -134,4 +135,17 @@ private static function addConnections(NodeBuilder $builder): void ->isRequired() ->info('Database name'); } + + private static function addUriOptions(NodeBuilder $builder): void + { + $uriOptionsBuilder = $builder + ->arrayNode('uriOptions') + ->info('Additional connection string options') + ->children(); + + $uriOptionsBuilder + ->variableNode('context') + ->defaultValue([]) + ->info('Overwrite any options with the same name in the uri parameter'); + } } diff --git a/src/DependencyInjection/MongoDbBundleExtension.php b/src/DependencyInjection/MongoDbBundleExtension.php index dd53814f..f721976f 100644 --- a/src/DependencyInjection/MongoDbBundleExtension.php +++ b/src/DependencyInjection/MongoDbBundleExtension.php @@ -61,6 +61,7 @@ private function defineClientRegistry(array $config, bool $debug): void [ new Reference('facile_mongo_db.event_dispatcher'), $debug, + $this->defineUriOptionsFactory($config), $this->defineDriverOptionsFactory($config), ] ); @@ -114,6 +115,11 @@ private function attachDataCollectionListenerToEventManager(): void ); } + private function defineUriOptionsFactory(array $config): ?Reference + { + return isset($config['uriOptions']) ? new Reference($config['uriOptions']) : null; + } + private function defineDriverOptionsFactory(array $config): ?Reference { return isset($config['driverOptions']) ? new Reference($config['driverOptions']) : null; diff --git a/src/Services/ClientRegistry.php b/src/Services/ClientRegistry.php index 8b63a9c5..d1c6aafc 100644 --- a/src/Services/ClientRegistry.php +++ b/src/Services/ClientRegistry.php @@ -8,6 +8,7 @@ use Facile\MongoDbBundle\Event\ConnectionEvent; use Facile\MongoDbBundle\Models\ClientConfiguration; use Facile\MongoDbBundle\Services\DriverOptions\DriverOptionsInterface; +use Facile\MongoDbBundle\Services\UriOptions\UriOptionsInterface; use MongoDB\Client; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpKernel\Kernel; @@ -31,12 +32,15 @@ final class ClientRegistry /** @var EventDispatcherInterface */ private $eventDispatcher; + /** @var UriOptionsInterface */ + private $uriOptionsService; /** @var DriverOptionsInterface */ private $driverOptionsService; public function __construct( EventDispatcherInterface $eventDispatcher, bool $debug, + ?UriOptionsInterface $uriOptionsService, ?DriverOptionsInterface $driverOptionsService ) { $this->clients = []; @@ -44,6 +48,7 @@ public function __construct( $this->debug = $debug; $this->eventDispatcher = $eventDispatcher; $this->driverOptionsService = $driverOptionsService; + $this->uriOptionsService = $uriOptionsService; } public function addClientsConfigurations(array $configurations): void @@ -64,6 +69,16 @@ private function buildClientConfiguration(array $conf): ClientConfiguration $conf['uri'] = self::buildConnectionUri($conf['hosts']); } + $conf['uriOptions'] = [ + 'replicaSet' => $conf['replicaSet'], + 'ssl' => $conf['ssl'], + 'connectTimeoutMS' => $conf['connectTimeoutMS'], + 'readPreference' => $conf['readPreference'], + ]; + if ($this->uriOptionsService instanceof UriOptionsInterface) { + $conf['options'] = $this->uriOptionsService->buildUriOptions($conf['uriOptions']); + } + $conf['driverOptions'] = []; if ($this->driverOptionsService instanceof DriverOptionsInterface) { $conf['driverOptions'] = $this->driverOptionsService->buildDriverOptions($conf); @@ -74,12 +89,7 @@ private function buildClientConfiguration(array $conf): ClientConfiguration $conf['username'], $conf['password'], $conf['authSource'], - [ - 'replicaSet' => $conf['replicaSet'], - 'ssl' => $conf['ssl'], - 'connectTimeoutMS' => $conf['connectTimeoutMS'], - 'readPreference' => $conf['readPreference'], - ], + $conf['uriOptions'], $conf['driverOptions'] ); } diff --git a/src/Services/UriOptions/UriOptionsInterface.php b/src/Services/UriOptions/UriOptionsInterface.php new file mode 100644 index 00000000..731c0a89 --- /dev/null +++ b/src/Services/UriOptions/UriOptionsInterface.php @@ -0,0 +1,22 @@ +createEventDispatcherMock(), false, null); + $registry = new ClientRegistry($this->createEventDispatcherMock(), false, null, null); $testConf = [ 'test_client' => [ @@ -41,7 +41,7 @@ public function test_client_connection_url_provided_manually() public function test_client_connection_url_generation_singlehost() { - $registry = new ClientRegistry($this->createEventDispatcherMock(), false, null); + $registry = new ClientRegistry($this->createEventDispatcherMock(), false, null, null); $testConf = [ 'test_client' => [ @@ -69,7 +69,7 @@ public function test_client_connection_url_generation_singlehost() public function test_client_connection_url_generation_multihost() { - $registry = new ClientRegistry($this->createEventDispatcherMock(), false, null); + $registry = new ClientRegistry($this->createEventDispatcherMock(), false, null, null); $testConf = [ 'test_client' => [