Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Command] Calling DoctrineCommand multiple times with multiple connections #1345

Open
cavasinf opened this issue Jul 27, 2023 · 0 comments
Open

Comments

@cavasinf
Copy link

cavasinf commented Jul 27, 2023

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

    $databaseName = (string) $this->getDependencyFactory()->getConnection()->getDatabase();

  2. AND setted at the same time (if undefined)

    public function getConnection(): Connection
    {
    if ($this->connection === null) {
    $this->connection = $this->hasEntityManager()
    ? $this->getEntityManager()->getConnection()
    : $this->connectionLoader->getConnection($this->getConfiguration()->getConnectionName());
    $this->freeze();
    }
    return $this->connection;
    }

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: {  }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant