Skip to content

Feature: Connection-targeted migrations and seeders #149

@usernane

Description

@usernane

Summary

Add a getTargetConnections(): array method to DatabaseChange (base class for migrations and seeders) that allows restricting a migration/seeder to specific database connections. This enables multi-tenant and multi-database architectures where certain schema changes should only apply to specific databases.

Motivation

In multi-tenant applications or systems with multiple databases (e.g., one for users, another for business data), not all migrations should apply to every database. Currently, running migrations:run --connection=tenant-a applies all discovered migrations. There's no way to declare that a migration belongs to a specific connection.

The framework already has getEnvironments() for environment-based filtering — this feature follows the same pattern for connection-based filtering.

Proposed API

// In DatabaseChange base class:
public function getTargetConnections(): array {
    return []; // Empty = applies to all connections (backward compatible)
}

// Usage in a migration:
class CreateTenantReportsTable extends AbstractMigration {
    public function getTargetConnections(): array {
        return ['reporting-db']; // Only applies when running against 'reporting-db' connection
    }
}

Implementation Considerations

1. Rollback behavior

Recommendation: If a migration was recorded as skipped (connection mismatch), rollback should also skip it. The existing status column in schema_changes already supports this — check status before rolling back.

2. Cross-connection dependencies

Recommendation: If MigrationB targets db-b and depends on MigrationA which targets db-a, treat the dependency as satisfied when running against db-b. The dependency only means ordering — if MigrationA targets a different connection, it's irrelevant to the current run. Alternatively, disallow cross-connection dependencies and throw a clear error during discovery.

3. Filter by connection name (not database name)

Recommendation: Use the logical connection name (e.g., master-data, reporting-db) rather than the physical database name (e.g., mdm_prod). Connection names are stable across environments while database names change between dev/staging/prod.

4. Seeders

Recommendation: Since getTargetConnections() is on DatabaseChange, it applies to both migrations and seeders automatically. The $db parameter passed to run() remains the current connection. If a seeder needs to read from another connection, it should instantiate that connection explicitly (same as today).

5. CLI output

Recommendation: Show skipped migrations with a clear message, consistent with environment filtering:

Warning: Skipped: App\Migrations\CreateReportsTable (Connection mismatch)

6. Fresh/reset commands

Recommendation: migrations:fresh should only drop and re-apply migrations that target the current connection (or target all connections). Migrations targeting other connections should be skipped entirely — not dropped, not re-applied.

7. Discovery

Recommendation: Discover all migration classes, then filter by connection at apply-time. This is consistent with how getEnvironments() works and avoids needing directory-based conventions.

Backward Compatibility

Fully backward compatible. Default return value is [] (empty array = applies to all connections), so existing migrations are unaffected.

Related

  • getEnvironments(): array — existing pattern for environment-based filtering
  • schema_changes.status column — already supports 'skipped' status

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions