Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Doctrine Migrations Multiple Database Bundle Laravel Package

corytech/doctrine-migrations-multiple-database-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:
    composer require avaibooksports/doctrine-migrations-multiple-database-bundle
    
  2. Register Bundle: Add to config/bundles.php:
    AvaiBookSports\Bundle\MigrationsMutlipleDatabase\DoctrineMigrationsMultipleDatabaseBundle::class => ['all' => true],
    
  3. Configure Migrations: Create config/packages/doctrine_migrations_multiple_database.yaml:
    doctrine_migrations_multiple_database:
        entity_managers:
            default:
                migrations_paths:
                    DoctrineMigrations\Main: '%kernel.project_dir%/migrations/Main'
            geonames:
                migrations_paths:
                    DoctrineMigrations\Geonames: '%kernel.project_dir%/migrations/Geonames'
    
  4. First Migration: Generate a migration for a specific EM:
    php bin/console make:migration --em=geonames
    
    Run migrations for a specific EM:
    php bin/console doctrine:migrations:migrate --em=geonames
    

Implementation Patterns

Workflow Integration

  1. Multi-Database Projects:

    • Use default EM for primary DB (e.g., users, posts).
    • Use geonames EM for read-only or specialized DBs (e.g., geonames, analytics).
    • Example structure:
      migrations/
      ├── Main/       # Default EM migrations
      │   └── VersionYYYYMMDDHMS.php
      └── Geonames/   # Geonames EM migrations
          └── VersionYYYYMMDDHMS.php
      
  2. Command-Line Patterns:

    • Targeted Migrations:
      # Migrate only the 'geonames' EM
      php bin/console doctrine:migrations:migrate --em=geonames
      
      # Execute a specific migration for 'default' EM
      php bin/console doctrine:migrations:execute --em=default --query="ALTER TABLE users ADD COLUMN active BOOLEAN"
      
    • Dry Runs:
      php bin/console doctrine:migrations:diff --em=geonames --dry-run
      
  3. CI/CD Pipelines:

    • Run migrations for all EMs in parallel (if supported by your environment):
      # Run in parallel (e.g., GitHub Actions)
      php bin/console doctrine:migrations:migrate --em=default & php bin/console doctrine:migrations:migrate --em=geonames
      
    • Use --allow-no-migration to skip EMs with no pending migrations:
      php bin/console doctrine:migrations:migrate --em=default,geonames --allow-no-migration
      
  4. Entity Manager Awareness:

    • Doctrine Config: Ensure your config/packages/doctrine.yaml defines all EMs:
      doctrine:
          dbal:
              connections:
                  default: { url: '%env(DATABASE_URL)' }
                  geonames: { url: '%env(GEONAMES_DATABASE_URL)' }
          orm:
              entity_managers:
                  default:
                      connection: default
                      mappings: [App]
                  geonames:
                      connection: geonames
                      mappings: [App\Geonames]
      
  5. Migration Dependencies:

    • Use --em with doctrine:migrations:execute for cross-EM dependencies:
      # Create a lookup table in 'default' EM first
      php bin/console doctrine:migrations:execute --em=default --query="CREATE TABLE em_lookups (...)"
      
      # Reference it in 'geonames' EM migrations
      php bin/console doctrine:migrations:execute --em=geonames --query="ALTER TABLE geonames ADD CONSTRAINT (...) FOREIGN KEY (...) REFERENCES em_lookups(id)"
      

Gotchas and Tips

Pitfalls

  1. Command Fallback:

    • If --em is omitted, the bundle falls back to doctrine_migrations.yaml. Ensure this file exists and is configured for the default EM to avoid silent failures.
    • Fix: Always specify --em or ensure doctrine_migrations.yaml is properly set up.
  2. Migration Path Conflicts:

    • If DoctrineMigrations\Main or DoctrineMigrations\Geonames already exist in vendor/, the bundle will overwrite them. This can cause issues if you’re using custom migration namespaces.
    • Fix: Use unique namespaces (e.g., App\Migrations\Main) and update the config:
      doctrine_migrations_multiple_database:
          entity_managers:
              default:
                  migrations_paths:
                      App\Migrations\Main: '%kernel.project_dir%/migrations/Main'
      
  3. Connection Order:

    • The bundle processes EMs in the order they are defined in doctrine_migrations_multiple_database.yaml. If migrations depend on connection state (e.g., sequences, triggers), define dependencies explicitly in the config or use doctrine:migrations:execute.
  4. Schema Validation:

    • Running doctrine:schema:validate without --em will skip the bundle’s configuration. Always specify --em for multi-EM setups:
      php bin/console doctrine:schema:validate --em=default,geonames
      
  5. Migration Generation:

    • Generated migrations for a specific EM only include entities mapped to that EM. Double-check your orm.entity_managers config in doctrine.yaml to avoid "entity not found" errors.

Debugging Tips

  1. Check Active EM:

    • Verify the active EM during a command:
      php bin/console doctrine:migrations:migrate --em=geonames --verbose
      
    • Look for lines like:
      [DoctrineMigrationsMultipleDatabaseBundle] Using EntityManager 'geonames'
      
  2. Inspect Migration Paths:

    • Temporarily add debug output to the bundle’s EntityManagerAwareMigrationCommand (e.g., in src/Command/MigrationCommand.php) to confirm paths are resolved correctly.
  3. Connection Issues:

    • If migrations fail with connection errors, test connections manually:
      php bin/console doctrine:query:sql "SELECT 1" --em=geonames
      
  4. Lock File Conflicts:

    • The bundle uses separate lock files per EM (e.g., migrations/Geonames/Version*.php.lock). If migrations hang, manually delete the .lock files for the problematic EM.

Extension Points

  1. Custom Migration Namespaces:

    • Extend the bundle to support custom namespaces by overriding the MigrationPathsResolver service. Example:
      # config/services.yaml
      AvaiBookSports\Bundle\MigrationsMutlipleDatabase\DependencyInjection\Compiler\MigrationPathsResolverPass:
          arguments:
              - ['App\Migrations\Main', '%kernel.project_dir%/migrations/Main']
              - ['App\Migrations\Geonames', '%kernel.project_dir%/migrations/Geonames']
      
  2. Dynamic EM Configuration:

    • Load EM configurations dynamically (e.g., from environment variables) by implementing a custom EntityManagerConfigLoader:
      // src/DependencyInjection/EntityManagerConfigLoader.php
      class DynamicEntityManagerConfigLoader implements EntityManagerConfigLoaderInterface
      {
          public function load(): array
          {
              return [
                  'default' => ['migrations_paths' => ['App\Migrations\Main' => $this->getPath('Main')]],
                  'geonames' => ['migrations_paths' => ['App\Migrations\Geonames' => $this->getPath('Geonames')]],
              ];
          }
      }
      
  3. Post-Migration Hooks:

    • Add post-migration logic (e.g., data seeding) by extending the PostMigrationEventSubscriber:
      // src/EventSubscriber/PostGeonamesMigrationSubscriber.php
      class PostGeonamesMigrationSubscriber implements EventSubscriberInterface
      {
          public static function getSubscribedEvents(): array
          {
              return [PostMigrationEvent::NAME => ['onPostMigration', 0]];
          }
      
          public function onPostMigration(PostMigrationEvent $event): void
          {
              if ($event->getEntityManagerName() === 'geonames') {
                  $this->seedGeonamesData();
              }
          }
      }
      
  4. Parallel Migration Execution:

    • For large projects, implement parallel migration execution using Symfony’s Process component. Example:
      // src/Command/ParallelMigrationsCommand.php
      class ParallelMigrationsCommand extends Command
      {
          protected function execute(InputInterface $input, OutputInterface $output): int
          {
              $processes = [];
              foreach ($this->getEntityManagers() as $em) {
                  $process = new Process(['php', 'bin/console', 'doctrine:migrations:migrate', '--em='.$em]);
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle