doctrine/DoctrineMongoDBBundle

How to get default_database when using Client without passing the parameter manually?

webdevilopers opened this issue · 6 comments

We mostly pass the @doctrine.dbal.default_connection as argument to our symfony services. A service may look like this:

services:
    Rewotec\PersonnelManagement\Infrastructure\Projection\Mongo\PersonListProjection: ~
    Rewotec\PersonnelManagement\Infrastructure\Projection\Mongo\PersonListReadModel:
        arguments: ['@doctrine_mongodb.odm.default_connection']
use MongoDB\Client;
use MongoDB\Collection;
use Prooph\EventStore\Projection\AbstractReadModel;

final class PersonListReadModel extends AbstractReadModel
{
    /** @var Client */
    private $client;

    /** @var Collection */
    private $collection;

    public function __construct(Client $client)
    {
        $this->client = $client;
        $this->collection = $client->selectCollection('acme_foo_db', CollectionName::PERSON_LIST);
    }

As you can see we have to pass the database to the selectCollection method.

The default_database is already defined in doctrine_mongodb.yaml:

doctrine_mongodb:
    auto_generate_proxy_classes: true
    auto_generate_hydrator_classes: true
    connections:
        default:
            server: '%env(resolve:MONGODB_URL)%'
            options: {}
    default_database: '%env(resolve:MONGODB_DB)%'
    document_managers:
        default:
            auto_mapping: true

We could of course pass the config parameter to our service:

services:
    Rewotec\PersonnelManagement\Infrastructure\Projection\Mongo\PersonListProjection: ~
    Rewotec\PersonnelManagement\Infrastructure\Projection\Mongo\PersonListReadModel:
        arguments: ['@doctrine_mongodb.odm.default_connection', '%env(resolve:MONGODB_DB)%']
final class PersonListReadModel extends AbstractReadModel
{
    /** @var Client */
    private $client;

    /** @var Collection */
    private $collection;

    public function __construct(Client $client, string $database)
    {
        $this->client = $client;
        $this->collection = $client->selectCollection($database, CollectionName::PERSON_LIST);
    }

I just wonder if there is any way to get the default database from the client? The name is at least registered:

$client->listDatabases():

MongoDB\Model\DatabaseInfoLegacyIterator#L35�\^�]8;;�\ {#96
  -databases: array:4 [
    0 => array:3 [
      "name" => "admin"
      "sizeOnDisk" => 32768.0
      "empty" => false
    ]
    1 => array:3 [
      "name" => "config"
      "sizeOnDisk" => 73728.0
      "empty" => false
    ]
    2 => array:3 [
      "name" => "local"
      "sizeOnDisk" => 77824.0
      "empty" => false
    ]
    3 => array:3 [
      "name" => "acme_foo_db"
      "sizeOnDisk" => 1626112.0
      "empty" => false
    ]
  ]
}

$client->listDatabaseNames():

ArrayIterator {#93
  -storage: array:4 [
    0 => "admin"
    1 => "config"
    2 => "local"
    3 => "acme_foo_db"
  ]

As far as I understand the default_database was originally designed to be passed to the document manager(s).

Recently I've seen solutions that pass a db to the connection. Would this then be available inside the @doctrine_mongodb.odm.default_connection? If yes, where to get it to pass it to the selectCollection method - or is there a way to skip the argument?

Thanks in advance.

Possibly related:

I tried the following config:

doctrine_mongodb:
    auto_generate_proxy_classes: true
    auto_generate_hydrator_classes: true
    connections:
        default:
            server: '%env(resolve:MONGODB_URL)%'
            options:
                db: '%env(resolve:MONGODB_DB)%'

Removing the default_database option the methods listDatabases and listDatabaseNames still show it. But still not hinted as default or similar.

  -manager: MongoDB\Driver\Manager {#234}
  -readConcern: MongoDB\Driver\ReadConcern {#233}
  -readPreference: MongoDB\Driver\ReadPreference {#232
    +"mode": "primary"
  }
  -uri: "mongodb://localhost:27017"
  -typeMap: array:2 [
    "root" => "array"
    "document" => "array"
  ]
  -writeConcern: MongoDB\Driver\WriteConcern {#231}
  manager: MongoDB\Driver\Manager {#234}
  uri: "mongodb://localhost:27017"
  typeMap: array:2 [
    "root" => "array"
    "document" => "array"
  ]
  writeConcern: MongoDB\Driver\WriteConcern {#231}
}

I also tried multiple connections e.g.:

doctrine_mongodb:
    auto_generate_proxy_classes: true
    auto_generate_hydrator_classes: true
    connections:
        default:
            server: '%env(resolve:MONGODB_URL)%'
            options:
                db: '%env(resolve:MONGODB_DB)%'
        default2:
            server: '%env(resolve:MONGODB_URL)%'
            options:
                db: '%env(resolve:MONGODB_DB)%'

But the only connection I can inject stays @doctrine_mongodb.odm.default_connection.

Maybe I'm mixing up some MongoDB with ODM features? Or are connections only related to document managers?

We are not using the latter at all.

Instead of passing Client to your services you could pass a Database object which also has selectCollection method but requires only a collection's name. With Symfony you could define a database service with a factory using Client and database name.

stale commented

This issue has been automatically marked as stale because it has not had any recent activity. It will be closed in a week if no further activity occurs. Thank you for your contributions.

Looks like the bundle does not offer it directly. But thank you @malarzm for the nice suggestion.

Closing.

@webdevilopers yes, the bundle was always focued on ODM and never really exposed anything for pure mongo, even in times of doctrine/mongodb. There was once a plan to change it but we never got to it.