Skip to content

Lack of a simple approach for "Database per Service" #360

Description

@DisboardTetta

Proposed new feature or change

Hi, I’d like to use your package with Symfony because I prefer it specifically due to the absence of DBAL and the general decision to forgo ORM-based auto-migration.

However, I recently ran into an issue. Here’s the situation: I use a "Database per Service" approach within a monolith because it makes it much easier to semantically separate database purposes and implement loosely coupled services.

For instance, I have a main database storing all business entities including a list of metrics with around 200 million records. But I also have a separate database containing dozens of tables with an aggregated structure; I write aggregated records there via cron jobs covering a specific number of days. This allows me to avoid the high cost of rebuilding materialized views and keeps the load within reasonable limits.

However, when I tried to migrate code like this:

$builder = new MigrationBuilder(new YiiDbConnectionFactory('maps'));

I realized there was no clean way to avoid having to manually instantiate the builder and the connector.
The downside of this approach is that the record of whether the migration was applied to Database #2 ends up being stored in the main migration itself something I’d rather avoid. Right now, I have a set of connections defined in a separate services file like this:

services:
  yii3.connections.default:
    class: Yiisoft\Db\Connection\ConnectionInterface
    factory: ['@App\Shared\Outbounding\YiiDbConnectionFactory', 'create']
    arguments:
      - 'default'
    public: true

  Yiisoft\Db\Connection\ConnectionInterface $defaultConnection: '@yii3.connections.default'
  Yiisoft\Db\Connection\ConnectionInterface: '@yii3.connections.default'
  yii3.connections.maps:
    class: Yiisoft\Db\Connection\ConnectionInterface
    factory: ['@App\Shared\Outbounding\YiiDbConnectionFactory', 'create']
    arguments: ['maps']
    public: true

Here is how I envision the implementation: In a configuration file, one could specify human-readable database names—such as "Default," "Maps," "Analytics," etc. and map them to a specific connection implementation or a name for the MigrationBuilder. This would allow autowiring to automatically inject the correct connection without altering other behaviors, such as how migration versions are stored.

When running a command like create:migration, I could pass a flag (e.g., --for) with that human-readable name. This would generate a migration class extending the appropriate base class, allowing the runner to establish the correct connection based on that choice.

For instance, I wouldn't mind creating "stub" classes for each specific database case; these would extend MigrationBuilder and override only the database connection, leaving everything else unchanged.

I am also open to your suggestions, as I am not entirely sure about this approach it is possible I simply missed a solution already present in the documentation.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions