如何在 DoctrineMigrationsBundle 3 中处理多个实体管理器的迁移

How to handle migrations with multiple entity managers in DoctrineMigrationsBundle 3

doctrine/doctrine-migrations-bundle 2.* 这相对简单 - 使用 --em 选项(并使用 ContainerAwareInterface 跳过来自不同 em/connection 的任何迁移)。

现在(在 doctrine/doctrine-migrations-bundle 3.2.2 上),似乎忽略了 --em 选项,并且始终指定默认的 em/connection,这意味着默认 em 的迁移是适用于每个数据库。编辑:正如评论中指出的那样 - --em 没有被忽略,它直接通过,而是我们的 ContainerAwareInterface 方法不再有效。

关于如何设置它有很多相互矛盾的信息,一些建议它应该“正常工作”(Symfony 文档)和其他描述解决方法(问题):

https://symfony.com/doc/current/doctrine/multiple_entity_managers.html https://github.com/doctrine/DoctrineMigrationsBundle/issues/38

如何配置 doctrine/doctrine-migrations-bundle 的这个新版本 (3) 以仅将迁移应用于匹配的 entity/db?

编辑:我在升级前的配置下面包含了它,连同 ContainerAwareInterface 连接过滤方法,允许过滤迁移到 运行 仅针对适当的实体管理器。

我们现有的 "doctrine/doctrine-bundle": "1.12.8" 配置(缩短,但显示多个实体管理器):

doctrine:
    dbal:
        connections:
            default:
                charset: utf8mb4
                default_table_options:
                    charset: utf8mb4
                    collate: utf8mb4_unicode_ci
                driver: '%database_driver%'
                server_version: mariadb-10.4.11
                host: '%database_host%'
                port: '%database_port%'
                dbname: autotempest
                user: '%database_user%'
                password: '%database_password%'
                mapping_types:
                    enum: string
            model:
                charset: utf8mb4
                default_table_options:
                    charset: utf8mb4
                    collate: utf8mb4_unicode_ci
                driver: '%database_driver%'
                server_version: mariadb-10.4.11
                host: '%database_host%'
                port: '%database_port%'
                dbname: autotempest_models
                user: '%database_user%'
                password: '%database_password%'
                mapping_types:
                    enum: string
                wrapper_class: App\Doctrine\ConnectionWrapper\ConnectionModel
            persistent: true

    orm:
        auto_generate_proxy_classes: '%kernel.debug%'
        entity_managers:
            default:
                connection: default
                mappings:
                    App:
                        type: 'annotation'
                        dir: '%kernel.project_dir%/src/Entity/Main'
                        prefix: 'App\Entity\Main'
            model:
                connection: model
                mappings:
                    TempestModelBundle:
                        type: 'annotation'
                        dir: 'Entity'
                        prefix: 'Tempest\Bundle\ModelBundle\Entity'

我们的 "doctrine/doctrine-migrations-bundle": "2.1.2" 配置:

doctrine_migrations:
    dir_name: '%kernel.project_dir%/src/Migrations'
    namespace: Application\Migrations

我的问题中还提到,2012 年 DoctrineMigrationsBundle 上有一个未解决的问题,描述了使用多个实体管理器时处理迁移的问题:https://github.com/doctrine/DoctrineMigrationsBundle/issues/38。如此处所述,似乎有多种解决此问题的方法,我们只需要挖掘并尝试每一种方法,以找到最适合我们情况的方法。

容器感知迁移

在 Symfony 3 上,我们使用的是 ContainerAwareInterface 方法。上期描述:

Currently this can be achieved by using Container Aware Migrations. If one can have the service container injected, he can obtain an instance of some entity manager and its connection.

然而,当迁移到 Symfony 4 时,这不再是一个真正有效的解决方案,因为 ContainerAware 类 被弃用以支持依赖注入。

直接传配置

上述 github 问题中提到的另一种方法。这里的想法是为每个实体管理器创建一个单独的配置文件,如下所示:

# config/packages/migrations/base.yaml
em: default
transactional: false
migrations_paths:
    Hyra\Migrations\Base: src/Migrations/Base
table_storage:
    table_name: migration_versions

这与实体管理器一起直接传递给命令,如下所示:bin/console doctrine:migrations:migrate --em default --configuration config/packages/migrations/base.yaml。这些单独的配置文件替换了单个 config/packages/doctrine_migrations.yaml 配置文件。

这对我们来说也不可行,因为我们仍然需要使用 DoctrineMigrationsBundleservices 配置选项将服务注入我们的迁移,而 --configuration 仅直接传递配置选项一直到 doctrine/migrations,它不支持 services 配置选项。

最初在 DoctrineMigrationsBundle 3.0 上,由于 --em--conn 选项被完全删除,这种方法变得复杂,因此还需要在顶部创建一个包装器DoctrineMigrationsBundle 命令中的 re-implement 这些选项 (described in more detail here)。这在 DoctrineMigrationsBundle 3.1+(恢复了这些选项)上不再需要。

使用DoctrineMigrationsMultipleDatabaseBundle

在 github 问题线程中也提到,this bundle 实现了我们所需要的(并最终使用)- DoctrineMigrationsBundle 的 per-entity 配置,因此我们可以还包括我们用于迁移依赖注入的 services 配置。最初我配置错误 - 重要的是基本 doctrine_migrations.yaml 配置只包含默认实体管理器的配置。包作者(版本 0.3.3)提供的示例工作配置:

# doctrine.yaml
doctrine:
    dbal:
        default_connection: default
        connections:
            default:
                url: '%env(resolve:DATABASE_URL)%'
                server_version: mariadb-10.1.26
                charset: utf8mb4
                default_table_options:
                    charset: utf8mb4
                    collate: utf8mb4_unicode_ci
                mapping_types:
                    enum: string
            geonames:
                url: '%env(resolve:GEONAMES_DATABASE_URL)%'
                server_version: mariadb-10.1.26
                charset: utf8mb4
                default_table_options:
                    charset: utf8mb4
                    collate: utf8mb4_unicode_ci
                mapping_types:
                    enum: string

        # IMPORTANT: You MUST configure your server version,
        # either here or in the DATABASE_URL env var (see .env file)
        #server_version: '5.7'
    orm:
        auto_generate_proxy_classes: true
        default_entity_manager: default
        entity_managers:
            default:
                connection: default
                naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
                mappings:
                    Main:
                        is_bundle: false
                        type: annotation
                        dir: '%kernel.project_dir%/src/App/Entity/Main'
                        prefix: 'App\Entity\Main'
                        alias: Main
            geonames:
                naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
                connection: geonames
                mappings:
                    Geonames:
                        is_bundle: false
                        type: annotation
                        dir: '%kernel.project_dir%/src/App/Entity/Geonames'
                        prefix: 'App\Entity\Geonames'
                        alias: Geonames
# doctrine_migrations.yaml
doctrine_migrations:
    em: default
    migrations_paths:
        DoctrineMigrations: '%kernel.project_dir%/migrations/Main'
# 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'