Миграция динамической схемы Doctrine (в конкретной базе данных)

В настоящее время я столкнулся с проблемой миграции с доктриной и моей множественной базой данных (db_name).


У меня есть несколько баз данных внутри одного экземпляра MYSQL: одна для компании, а другая для каждого клиента (сущности).

Каждая база данных создается внутри операции postPersit (я запускаю специальную команду, которая переопределяет базу данных: создание доктрины, чтобы создать базу данных с uuid клиента, это работает).

Я хочу сделать то же самое с миграцией, но вижу ошибку "конфигурация не найдена", и когда я ставлю общую конфигурацию, она не находит того, что ей нужно.

Я создал WrapperConnection и добавил возможность выбора базы данных. Я использую эту оболочку перед запуском запроса платформы API (внутри ApiNormalizer).

Мой код...

#[AsCommand(name: 'custom:migration:migrate')]
final class MigrationCommand extends DoctrineCommand
{
    use EntityManagerTrait;
    use ParameterBagTrait;

    protected function configure(): void
    {
        $this
            ->setAliases(['migrate'])
            ->setDescription(
                'Execute a migration to a specified version or the latest available version.',
            )
            ->addArgument(
                'name',
                InputArgument::REQUIRED,
                'The database name'
            )
        ;

        parent::configure();
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $databaseName = $input->getArgument('name');

        if (null === $databaseName) {
            // return Command::FAILURE;
        }

        /** @var MultiDbConnectionWrapper */
        $connection = $this->em->getConnection();
        $connection->selectDatabase($databaseName);
        
        // Doctrine code is below.

        $migrateCmd = new DoctrineMigrateCommand($this->getDependencyFactory());

        $migrateInput = new ArrayInput([
            '--configuration' => $this->parameterBag->get('kernel.project_dir').'/config/packages/doctrine.yaml',
        ]);

        $migrateCmd->run($migrateInput, $output);
     }
}

Я попытался скопировать/вставить напрямую код класса, чтобы отредактировать его... Мне это не удалось...

Я хочу использовать миграцию по динамической схеме, но я новичок в коде доктрины и миграции. Вы можете мне помочь ?


Если бы я знал, как работает конфигурация, я мог бы создать копии файлов миграции с хорошей схемой, я думаю, и запустить ее... что вы думаете?

Извините за мой приблизительный английский.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Symfony Station Communiqué - 17 февраля 2023 г
Symfony Station Communiqué - 17 февраля 2023 г
Это коммюнике первоначально появилось на Symfony Station , вашем источнике передовых новостей Symfony, PHP и кибербезопасности.
Управление ответами api для исключений на Symfony с помощью KernelEvents
Управление ответами api для исключений на Symfony с помощью KernelEvents
Много раз при создании api нам нужно возвращать клиентам разные ответы в зависимости от возникшего исключения.
0
0
80
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я нашел это.

Вот решение

<?php

namespace App\Command\Doctrine;

use App\Service\Trait\ParameterBagTrait;
use Doctrine\Migrations\Tools\Console\Command\MigrateCommand as DoctrineMigrateCommand;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Yaml\Yaml;

// the name of the command is what users type after "php bin/console"
#[AsCommand(name: 'alx:migration:migrate', aliases: ['alx:mi:mi', 'alx-migrate'])]
final class MigrationCommand extends Command
{
    use ParameterBagTrait;

    protected function configure(): void
    {
        $this
            ->setAliases(['migrate'])
            ->setDescription(
                'Execute a migration on a specific database',
            )
            ->addArgument(
                'name',
                InputArgument::REQUIRED,
                'The database name'
            )
        ;

        parent::configure();
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $databaseName = $input->getArgument('name');

        if (null === $databaseName) {
            return Command::FAILURE;
        }

        // Create the tmp file.
        $dbPath = $this->getDatabaseConfigPath($databaseName);
        $migrationPath = $this->getMigrationConfigPath();

        $migrateCmd = new DoctrineMigrateCommand();
        $migrateInput = new ArrayInput([
            '--db-configuration' => $dbPath,
            '--configuration' => $migrationPath,
        ]);

        // I dont want it to ask the question.
        $migrateInput->setInteractive(false);
        // execute the migration.
        $migrateCmd->run($migrateInput, $output);

        // Delete the tmp file.
        unlink($dbPath);
        unlink($migrationPath);

        return 0;
    }

    public function getDatabaseConfigPath(string $dbName): string
    {
        $urlDb = $this->parameterBag->get('database_url');
        $url = str_replace('bastion', $dbName, $urlDb);

        $phpContent = "<?php return ['url' => '$url']; ?>";

        return $this->createTmpFile('db_'.$dbName.'_'.uniqid().'.php', $phpContent);
    }

    public function getMigrationConfigPath(): string
    {
        /** @var string $directory */
        $directory = $this->parameterBag->get('kernel.project_dir');
        $migrationPath = $directory.'/migrations';
        $content = Yaml::dump([
            'migrations_paths' => [
                'DoctrineMigrations' => $migrationPath,
            ],
            'table_storage' => [
                'table_name' => 'doctrine_migration_versions',
                'version_column_name' => 'version',
                'version_column_length' => '191',
            ],
        ]);

        $name = uniqid('migration_');

        return $this->createTmpFile($name.'.yaml', $content);
    }

    private function createTmpFile(string $filename, string $content): string
    {
        $filesystem = new Filesystem();
        $tempFilePath = sys_get_temp_dir().'/'.$filename;
        $filesystem->dumpFile($tempFilePath, $content);

        return $tempFilePath;
    }
}

файл базы данных

<?php 

return [
    'url' => 'mysql://USER:PWD@database:3306/myDatabaseName?serverVersion=10.5.15-MariaDB&charset=utf8mb4'
];

Файл миграции (yaml)


migrations_paths:
        # namespace is arbitrary but should be different from App\Migrations
        # as migrations classes should NOT be autoloaded
        'DoctrineMigrations': '/app/migrations'
table_storage:
  table_name: 'doctrine_migration_versions'
  version_column_name: 'version'
  version_column_length: '191'

Привет, не могли бы вы отредактировать свой ответ, чтобы отобразить содержимое метода getTmpDatabaseFile?

loicfavory 13.06.2024 10:54

@loicfavory Я заменил код на последнюю версию.

Sake 14.06.2024 11:13

Другие вопросы по теме