migrations icon indicating copy to clipboard operation
migrations copied to clipboard

[Command] Calling `DoctrineCommand` multiple times with multiple connections

Open cavasinf opened this issue 2 years ago • 0 comments

Bug Report

Q A
BC Break no
Version 3.6.0

Summary

Using Multiple Database in a single Symfony Application. We need to trigger the MigrateCommand x times for x databases from a cron/hook when deploying a new version.

Current behavior

Note : Running this Command with the --conn option seems to not works. So we use the --em option.

When calling the MigrateCommand multiple times FROM Command/Code the connection will be:

  1. getted https://github.com/doctrine/migrations/blob/2f4b14968df1cb1c6e8beb724d142c4a8ddf2842/lib/Doctrine/Migrations/Tools/Console/Command/MigrateCommand.php#L132

  2. AND setted at the same time (if undefined) https://github.com/doctrine/migrations/blob/2f4b14968df1cb1c6e8beb724d142c4a8ddf2842/lib/Doctrine/Migrations/DependencyFactory.php#L158-L168

Because of this, the connection will always be the first "implemented". In the end, calling this command in a loop and changing the connection/entityManager at each iteration won't work as untended.

How to reproduce

  1. Have multiple connections
  2. Have multiple EntityManagers
  3. Run this command
<?php

namespace App\Command;

use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

#[AsCommand(
    name: 'app:test',
)]
class TestCommand extends Command
{
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $entityManagers = [
            'client1',
            'client2',
        ];

        foreach ($entityManagers as $entityManager) {
            $commandToCall = $this->getApplication()->find('d:m:m');
            $commandInput  = new ArrayInput(
                [
                    '--em' => $entityManager,
                ]
            );

            $commandToCall->run(
                $commandInput,
                $output
            );
        }

        return Command::SUCCESS;
    }
}
  1. Output a. First loop : WARNING! You are about to execute a migration in database "client1" that could result in schema changes and data loss. Are you sure you wish to continue? (yes/no) [yes] b. Second loop: WARNING! You are about to execute a migration in database "client1" that could result in schema changes and data loss. Are you sure you wish to continue? (yes/no) [yes]

Expected behavior

The first loop should be client1 and the second client2.

Note : Running single command from CLI is working php bin/console d:m:m --em=client1 or php bin/console d:m:m --em=client2

Doctrine config

php bin/console debug:config doctrine
Current configuration for extension with alias "doctrine"
=========================================================

doctrine:
  orm:
      resolve_target_entities:
          Allsoftware\SymfonyBundle\Model\FichierInterface: App\Entity\Fichier
          Allsoftware\SymfonyBundle\Model\DossierInterface: App\Entity\Dossier
      auto_generate_proxy_classes: true
      entity_managers:
          default:
              dql:
                  string_functions:
                      regexp: DoctrineExtensions\Query\Mysql\Regexp
                  numeric_functions: {  }
                  datetime_functions: {  }
              naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
              auto_mapping: true
              mappings:
                  App:
                      is_bundle: false
                      type: attribute
                      dir: /var/www/html/src/Entity
                      prefix: App\Entity
                      alias: App
                      mapping: true
                  AllsoftwareSymfonyBundle:
                      type: attribute
                      dir: src/Model
                      prefix: Allsoftware\SymfonyBundle\Model
                      mapping: true
              query_cache_driver:
                  type: null
              result_cache_driver:
                  type: null
              class_metadata_factory_name: Doctrine\ORM\Mapping\ClassMetadataFactory
              default_repository_class: Doctrine\ORM\EntityRepository
              quote_strategy: doctrine.orm.quote_strategy.default
              entity_listener_resolver: null
              repository_factory: doctrine.orm.container_repository_factory
              schema_ignore_classes: {  }
              report_fields_where_declared: false
              validate_xml_mapping: false
              hydrators: {  }
              filters: {  }
          client1:
              dql:
                  string_functions:
                      regexp: DoctrineExtensions\Query\Mysql\Regexp
                  numeric_functions: {  }
                  datetime_functions: {  }
              naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
              mappings:
                  App:
                      is_bundle: false
                      type: attribute
                      dir: /var/www/html/src/Entity
                      prefix: App\Entity
                      alias: App
                      mapping: true
              connection: client1
              query_cache_driver:
                  type: null
              result_cache_driver:
                  type: null
              class_metadata_factory_name: Doctrine\ORM\Mapping\ClassMetadataFactory
              default_repository_class: Doctrine\ORM\EntityRepository
              auto_mapping: false
              quote_strategy: doctrine.orm.quote_strategy.default
              entity_listener_resolver: null
              repository_factory: doctrine.orm.container_repository_factory
              schema_ignore_classes: {  }
              report_fields_where_declared: false
              validate_xml_mapping: false
              hydrators: {  }
              filters: {  }
          client2:
              dql:
                  string_functions:
                      regexp: DoctrineExtensions\Query\Mysql\Regexp
                  numeric_functions: {  }
                  datetime_functions: {  }
              naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
              mappings:
                  App:
                      is_bundle: false
                      type: attribute
                      dir: /var/www/html/src/Entity
                      prefix: App\Entity
                      alias: App
                      mapping: true
              connection: client2
              query_cache_driver:
                  type: null
              result_cache_driver:
                  type: null
              class_metadata_factory_name: Doctrine\ORM\Mapping\ClassMetadataFactory
              default_repository_class: Doctrine\ORM\EntityRepository
              auto_mapping: false
              quote_strategy: doctrine.orm.quote_strategy.default
              entity_listener_resolver: null
              repository_factory: doctrine.orm.container_repository_factory
              schema_ignore_classes: {  }
              report_fields_where_declared: false
              validate_xml_mapping: false
              hydrators: {  }
              filters: {  }
      enable_lazy_ghost_objects: false
      proxy_dir: /var/www/html/var/cache/dev/doctrine/orm/Proxies
      proxy_namespace: Proxies
      controller_resolver:
          enabled: true
          auto_mapping: true
          evict_cache: false
  dbal:
      connections:
          default:
              url: '%env(resolve:DATABASE_URL)%'
              wrapper_class: App\DBAL\MultiDbConnectionWrapper
              driver: pdo_mysql
              logging: true
              profiling: true
              profiling_collect_backtrace: false
              profiling_collect_schema_errors: true
              options: {  }
              mapping_types: {  }
              default_table_options: {  }
              schema_manager_factory: doctrine.dbal.legacy_schema_manager_factory
              slaves: {  }
              replicas: {  }
          client1:
              url: 'mysql://root:root@mysqlhost:3306/nils_client1'
              driver: pdo_mysql
              logging: true
              profiling: true
              profiling_collect_backtrace: false
              profiling_collect_schema_errors: true
              options: {  }
              mapping_types: {  }
              default_table_options: {  }
              schema_manager_factory: doctrine.dbal.legacy_schema_manager_factory
              slaves: {  }
              replicas: {  }
          client2:
              url: 'mysql://root:root@mysqlhost:3306/nils_client2'
              driver: pdo_mysql
              logging: true
              profiling: true
              profiling_collect_backtrace: false
              profiling_collect_schema_errors: true
              options: {  }
              mapping_types: {  }
              default_table_options: {  }
              schema_manager_factory: doctrine.dbal.legacy_schema_manager_factory
              slaves: {  }
              replicas: {  }
      types:
          uuid:
              class: Ramsey\Uuid\Doctrine\UuidType
      driver_schemes: {  }

cavasinf avatar Jul 27 '23 15:07 cavasinf