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
Summary
Add a
getTargetConnections(): arraymethod toDatabaseChange(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-aapplies 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
Implementation Considerations
1. Rollback behavior
Recommendation: If a migration was recorded as
skipped(connection mismatch), rollback should also skip it. The existingstatuscolumn inschema_changesalready supports this — check status before rolling back.2. Cross-connection dependencies
Recommendation: If MigrationB targets
db-band depends on MigrationA which targetsdb-a, treat the dependency as satisfied when running againstdb-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 onDatabaseChange, it applies to both migrations and seeders automatically. The$dbparameter passed torun()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:
6. Fresh/reset commands
Recommendation:
migrations:freshshould 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 filteringschema_changes.statuscolumn — already supports'skipped'status