doctrine / DoctrineMongoDBBundle

Integrates Doctrine MongoDB ODM with Symfony
http://symfony.com/doc/current/bundles/DoctrineMongoDBBundle/index.html
MIT License
379 stars 229 forks source link

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

Closed webdevilopers closed 3 years ago

webdevilopers commented 3 years ago

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:

webdevilopers commented 3 years ago

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}
}
webdevilopers commented 3 years ago

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.

malarzm commented 3 years ago

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[bot] commented 3 years ago

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.

webdevilopers commented 3 years ago

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

Closing.

malarzm commented 3 years ago

@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.