ezsystems / ezmigrationbundle
Kaliop eZ-Migration Bundle
Requires
- php: ^7.3
- ext-pdo: *
- ezsystems/doctrine-dbal-schema: ^1.0
- ezsystems/ezplatform-kernel: ^1.0
- mtdowling/jmespath.php: 2.*
- nikic/php-parser: ^4.2.2
- symfony/process: *
- symfony/swiftmailer-bundle: *
- symfony/validator: *
- symfony/var-dumper: *
Requires (Dev)
- mikey179/vfsstream: ^2.0
- phpunit/phpunit: ^7.5
- roave/security-advisories: dev-disablechecks as dev-master
Suggests
- php-http/httplug-bundle: Required for usage of HTTP/CALL migration steps
README
这是kaliop迁移bundle的内部分支,用于我们的演示。它不受支持,将在未来被完全替换。
Kaliop eZ-Migration Bundle
此bundle使得以编程方式部署eZPlatform / eZPublish 5数据库结构和内容变得简单。
它受到DoctrineMigrationsBundle的启发。
你可以将其视为旧版ezxmlinstaller扩展的孙子。
要求
-
PHP 5.6或更高版本。
-
eZPlatform或eZPublish Enterprise 5.4或eZPublish Community 2014.11或更高版本。
安装
在composer.json文件中bundle列表的末尾添加到require
或require-dev
"kaliop/ezmigrationbundle": "^5.0"
保存并运行
composer update --dev kaliop/ezmigrationbundle
这将安装bundle及其所有依赖项。
请确保在kernel中也注册了bundle。检查app/appKernel.php
(对于eZPublish ezpublish/EzPublishKernel.php
)
注册Bundles方法应类似
public function registerBundles()
{
$bundles = array(
... more stuff here ...
new \Kaliop\eZMigrationBundle\eZMigrationBundle()
);
}
检查bundle是否正确安装
如果你运行php bin/console
(对于eZPublish php ezpublish/console
),你应该在列表中看到以下新命令
kaliop
kaliop:migration:generate
kaliop:migration:status
kaliop:migration:migrate
kaliop:migration:migration
这表明bundle已正确安装和注册。
注意:命令kaliop:migration:update
保留以保持兼容性,将在未来版本中删除。
更新bundle
要获取最新版本,可以使用composer
将bundle更新到最新可用版本
composer update kaliop/ezmigrationbundle
从版本4.x升级到版本5
-
请仔细阅读发行说明中的所有BC注意事项
-
除非你有以下之一,否则无需其他操作
- 扩展迁移bundle代码或apis的代码
- 旧的迁移,你希望与更新的bundle一起重新运行,其中包含包含字符串'[reference:xxx]'的文本值,其中'xxx'代表任何字符序列
对于这两种情况,修复方法是手动修改你的代码/迁移。
从版本3.x升级到版本4
-
请仔细阅读发行说明中的所有BC注意事项
-
除非你有以下之一,否则无需其他操作
- 扩展迁移bundle代码或apis的代码
- 依赖于解析
migrate
命令输出并依赖于其精确格式的代码
对于这两种情况,修复方法是手动修改你的代码。
从版本2.x升级到版本3
-
请仔细阅读发行说明中的所有BC注意事项
-
除非你有以下之一,否则无需其他操作
- 使用扩展版本1.x或2.x生成的迁移定义,尚未应用
- 扩展迁移bundle代码或apis的代码
对于这两种情况,修复方法是手动修改你的代码/迁移。
从版本1.x升级到版本2
请阅读专门的文档页面
入门
所有命令都接受标准的Symfony/eZPublish 5选项,尽管它们中的一些可能对命令执行没有影响。
生成一个新的、空的迁移定义文件
此bundle提供了一个命令,可以轻松生成一个新的空白迁移定义文件,并将其存储在特定的bundle中。
例如
php ezpublish/console kaliop:migration:generate --format=yml MyProjectBundle
上述命令将在MyProjectBundle包的MigrationVersions
目录中放置一个新的yml骨架文件。
如果目录不存在,则命令将为您创建它,前提是包存在并且已注册。如果命令执行成功,它将创建一个名为以下模式的新yml文件:YYYYMMDDHHMMSS_placeholder.yml
。建议您重命名文件并将placeholder
部分改为更有意义的内容,但请保留时间戳部分和下划线,以及扩展名。
(骨架Yaml文件的內容以twig模板形式存储)
列出所有迁移及其状态
要查看系统中所有可用的迁移定义以及它们是否已被应用,只需在eZPublish 5根目录中运行status命令即可。
php ezpublish/console kaliop:migration:status
已应用的迁移列表存储在名为kaliop_migrations
的数据库表中。如果需要,包将自动创建该表。如果您需要使用该表的另一个名称,可以更改Symfony参数ez_migration_bundle.table_name
。
应用迁移
要应用所有可用的迁移,请在eZPublish 5根目录中运行migrate命令。
php ezpublish/console kaliop:migration:migrate
注意:如果您刚刚执行了上述命令并收到错误消息,因为您刚刚生成的迁移定义文件无效,请不要担心——这是设计意图。请继续阅读下一段...
注意:迁移默认以ID为14的管理用户执行。如果没有这个用户账户在数据库中,您必须通过传递-a
标志来指定使用另一个管理账户。
应用单个迁移文件
要应用单个迁移,请运行带有其定义路径的migrate命令,如下所示
php ezpublish/console kaliop:migration:migrate --path=src/MyNamespace/MyBundle/MigrationVersions/20160803193400_a_migration.yml
注意:您还可以通过--path
标志指定一个文件夹,在这种情况下,将执行该文件夹中包含的所有迁移定义。
编辑迁移文件
到目前为止,但您可以使用迁移执行哪些类型的操作呢?
每个迁移定义由一系列步骤组成,其中每个步骤定义一个操作。
创建一个“文件夹”内容的迁移的简单示例:
-
mode: create
type: content
content_type: folder
parent_location: 2
attributes:
name: hello world
在Yaml迁移中,您可以定义以下类型的操作:
- 内容的创建、更新和删除
- 内容类型的创建、更新和删除
- 内容类型组的创建、更新和删除
- 内容版本的删除
- 语言创建和删除
- 位置创建、更新和删除
- 对象状态创建、更新和删除
- 对象状态组创建、更新和删除
- 角色创建、更新和删除
- 节创建、更新和删除
- 标签(来自Netgen Tags Bundle)的创建和删除
- 用户创建、更新和删除
- 用户组创建、更新和删除
- 从垃圾桶中清理和恢复内容
- 文件创建、追加、复制、重命名和删除
- 执行SQL查询
- 执行命令行脚本
- 执行symfony服务的方法
- 执行HTTP调用
- 发送电子邮件
- 取消、推迟或暂停迁移本身
描述所有支持参数的文档在DSL语言描述中
自定义迁移
对于更具体的需求,您还可以使用另外两种类型的迁移
- SQL迁移
- PHP迁移
SQL迁移
生成SQL迁移定义的示例命令
php ezpublish/console kaliop:migration:generate MyBundle create-new-table --format=sql
这将创建以下文件,您可以自由编辑
.../MyBundle/Migrations/2016XXYYHHMMSS_mysql_create-new-table.sql
注意 如果你重命名sql文件,请记住该文件应应用于哪种类型的数据库是由文件名中第一和第二个下划线字符之间的部分决定的。如果你稍后尝试在PostgreSQL等数据库上执行该迁移,迁移将失败。当然,你可以自由地为不同的数据库类型创建特定的SQL迁移。
迁移包本身不对支持的数据库类型施加限制,但由于它基于Doctrine DBAL,它只能在Doctrine支持的数据库上运行。
注意 如果你迁移中的SQL命令(或命令)太长,迁移可能会失败或只部分应用,在某些情况下(例如使用MySQL)甚至不会报告错误。如果你需要执行多个长查询,最好是将它们拆分,要么是多个.sql迁移,要么是单个.yml迁移,其中包含sql步骤。
PHP迁移
如果你需要进行的操作对于YML或SQL来说太复杂,你可以使用php类作为迁移定义。要生成PHP迁移定义,执行
php ezpublish/console kaliop:migration:generate MyBundle AMigrationClass --format=php
这将创建以下文件,您可以自由编辑
.../MyBundle/Migrations/2016XXYYHHMMSS_AMigrationClass.php
如你所见,用于迁移的php类需要实现一个特定的接口。Symfony DIC容器传递给迁移类,以便它可以从中访问它需要的所有服务、参数和其他东西。
有关使用PHP完成的迁移定义的更详细示例,请查看此包的MigrationVersions文件夹。
注意 如果你重命名php文件,请记住文件名和其中包含的类名是绑定的 - 应用程序的标准自动加载机制在加载迁移定义时不适用。这也是为什么用作迁移的php类不应使用命名空间的原因。
注意 自版本4.5以来,还可以通过在yaml迁移中将它声明为迁移步骤来运行任何现有Symfony服务的任何方法。有关详细信息,请参阅相关DSL。
重新执行失败的迁移
重新执行状态为'失败'的迁移的最简单方法是将其从迁移表中删除
php ezpublish/console kaliop:migration:migration migration_name --delete
从迁移表中删除迁移信息后,运行migrate
命令将再次执行它。
事务/回滚更改的使用
默认情况下,该包在每个数据库事务中运行每个迁移。这意味着如果某个步骤失败,所有之前的步骤都会回滚,数据库将保持在原始状态。这是一个内置的安全功能;
- 如果你希望迁移步骤在单独的事务中执行,最简单的方法是为每个步骤创建一个单独的迁移文件
- 你可以使用命令行标志
-u
来禁用migrate命令的事务使用
请注意,默认情况下,migrate
命令在第一个失败的迁移处停止,但可以通过标志执行,允许它在失败的情况下继续执行所有可用的迁移。
至于回滚更改:鉴于eZPublish API的性质,回滚内容更改并非易事。因此,该包不提供内置支持以将数据库回滚到应用给定迁移之前的状态。我们建议在应用迁移之前始终采取数据库快照,并在需要回滚更改时使用它。另一种方法是在写入单独的迁移来撤销更改。
通过事件监听器自定义迁移逻辑
将自定义逻辑连接到迁移执行的一种简单方法 - 而无需实现自己的自定义操作执行器 - 是使用事件监听器。
在执行迁移过程中,每个步骤都会触发两个事件
* ez_migration.before_execution => listeners receive a BeforeStepExecutionEvent event instance
* ez_migration.step_executed => listeners receive a StepExecutedEvent event instance
仅在迁移失败并且步骤抛出特定的迁移中止异常时,才会触发事件
* ez_migration.migration_aborted => listeners receive a MigrationAbortedEvent event instance
当使用 kaliop:migration:generate
命令生成迁移时,会触发事件,允许修改将要序列化为迁移步骤的数据
* ez_migration.migration_generated => listeners receive a MigrationGeneratedEvent event instance
为了响应这些事件,您需要声明标记化的服务,例如
my.step_executed_listener:
class: my\helper\StepExecutedListener
tags:
- { name: kernel.event_listener, event: ez_migration.step_executed, method: onStepExecuted }
以及相应的PHP类
use Kaliop\eZMigrationBundle\API\Event\StepExecutedEvent;
class StepExecutedListener
{
public function onStepExecuted(StepExecutedEvent $event)
{
// do something...
}
}
已知问题和限制
-
与Doctrine Migrations Bundle不同,此Bundle不支持更改回滚。请参阅上述原因。
-
如果您正在使用Doctrine Migrations Bundle来管理您的架构,您将得到一些无用的SQL语句来处理属于Kaliop Migrations Bundle的数据库表。目前,最好的解决方案是在运行
doctrine:migrations:diff
和其他命令时,使用命令行上的filter-expression
参数,其值为kaliop_migrations_*
-
如果在运行迁移时遇到致命错误,指出未找到节点或对象,这很可能是与eZPublish中双内核的工作方式有关,以及遗留的和Symfony内核使用单独的数据库连接的事实。由于迁移Bundle默认将迁移的所有数据库更改包装在数据库事务中,当触发允许遗留内核清除其缓存的槽时,遗留内核无法看到Symfony内核应用的数据更改,并且,具体取决于使用的槽,可能会出现致命错误。最简单的解决方案是通过将
-u
标志传递给migrate
命令来禁用事务的使用。 -
当您使用Solr搜索引擎Bundle时,也可能出现类似的症状。在这种情况下,问题更加复杂,因为,即使节点或对象在数据库事务中发送到Solr,Solr搜索索引可能配置为仅在短时间内延迟后提交接收到的数据。一个已知的解决方案包括
- 将迁移步骤分离到单独的迁移中
- 通过使用
-p
标志将每个迁移单独在事务(和进程)中运行,即对migrate
命令 - 在迁移2 .. N中添加
sleep
迁移步骤 - 以及/或者配置Solr始终立即提交更改到索引(例如,禁用
commitwithin
)
-
当在多核心配置中使用SOLR并遇到
java.lang.NegativeArraySizeException
错误时,您必须将ez_migration_bundle.query_limit
参数的默认值2147483647设置得更低 -
如果在运行涉及大量内容更改的迁移时遇到无任何错误信息的致命错误,例如更改具有许多内容的contentType,那么您可能正在耗尽PHP进程的内存。已知的解决方案包括
- 通过以选项 '-d memory_limit=-1' 运行来增加允许PHP脚本使用的最大内存量
- 使用具有减少日志记录和禁用内核调试的Symfony环境执行迁移命令:已知
dev
环境的默认配置会泄漏内存
-
如果您收到带有消息 '您不能创建一个属于非活动作用域("request")的服务("request")' 的致命错误,请查看以下问题以获取可能的解释和解决方案思路: https://jira.ez.no/browse/EZP-24691
-
如果您正在使用2015.9之前的eZPublish版本,您将无法创建/更新包含对自定义模块/函数有限制的策略的角色定义。已知的解决方案是接管RoleService并修改其构造函数,将其所需的限制注入其中。
-
在更新角色时,您必须在迁移中指定其所有策略。任何未在yml文件中的现有策略都将被删除。为了便于创建更新角色的迁移,请使用带有
--type=role
标志的migration:generate
命令。 -
创建内容类型时请注意:迁移包内部使用的eZPublish API允许您在内容类型标识符中使用破折号,即使生成的内容类型将变得不可用,例如。
无效定义示例
type: ezstring name: Topbar-hover-color identifier: topbar-hover-color
常见问题
如何更新具有不同Id的特定内容,该内容在开发、测试和生产环境中使用不同的Id?
A: 使用'reference/set'迁移步骤来定义所需内容Id的引用,并使用Symfony参数为每个Symfony环境存储不同的值。例如
-
type: reference
mode: set
identifier: content_id_ref
value: '%a.parameter.name%'
-
type: content
mode: update
match:
content_id: "reference:content_id_ref"
etc: ...
如何更新现有角色以更改其策略?
当使用迁移来更新角色时,您必须定义其所有策略。任何未定义的策略都将被删除。确保您不会忘记任何现有策略的最安全且最简单的方法是首先生成一个更新迁移,该迁移具有当前定义的角色完整规范,然后手动编辑。
创建此类迁移的示例命令
php ezpublish/console kaliop:migration:generate --type=role --mode=update --match-type=identifier --match-value=Anonymous bundleName
通过generate
命令将内容导出到yml迁移时,属性列表为空
A: 这很可能是由于使用了错误的语言配置。
扩展包
支持自定义迁移
该包已被设计为可以轻松以多种方式扩展,例如
- 添加对自定义/复杂字段类型的支持
- 添加对Yml定义中完全新动作的支持
- 添加对存储迁移定义的新文件格式的支持
- 添加对迁移定义中自定义引用的新解析器的支持
- 接管从文件系统加载迁移定义或将其存储在数据库中的方式
- 等等...
遵循Symfony最佳实践,对于上述列表中的前4个选项,您只需要创建一个服务并为其指定适当的标签(当然,实现该服务的类应实现适当的接口)。
要找出您需要实现的标签名称,以及其他您可以覆盖的所有服务,请查看services.yml文件。
运行测试
该包使用PHPUnit来运行功能测试。
在运行中的eZPublish / eZPlatform安装上运行测试
要运行测试
export KERNEL_DIR=ezpublish (or 'app' for ezplatform setups)
export SYMFONY_ENV=behat (or whatever your environment is)
bin/phpunit --stderr -c vendor/kaliop/ezmigrationbundle/phpunit.xml.dist
注意测试不模拟与数据库的交互,但在其中创建/修改/删除许多类型的数据。因此,运行测试可能会留下陈旧/损坏的数据。建议使用专门的eZPublish安装或至少使用专门的数据库来运行测试套件。
为该包设置专门的测试环境
运行该包测试的一个更安全的选项是设置一个专用环境,类似于在Travis上运行测试套件时使用的环境。优点是您可以以任何版本的eZPublish开始;另一方面,您将更有信心测试在Travis上仍然通过。缺点是您需要Docker和Docker-compose,并且您将使用的环境将非常不同于标准的eZPublish设置!
设置专用测试环境并运行其中的测试步骤
# if you have a github auth token, it is a good idea to copy it now to Tests/docker/data/.composer/auth.json
./Tests/teststack.sh build
./Tests/teststack.sh runtests
./Tests/teststack.sh stop
如果您想运行手动命令,例如symfony控制台
./Tests/teststack.sh exec php vendor/ezsystems/ezplatform/bin/console cache:clear
注意:第一次运行此操作需要一些时间,但之后的运行将会更快。注意:请确保有足够的磁盘空间。注意:Docker容器中的测试将针对文件containers.env
中指定的eZPlatform内核版本进行。如果您想测试其他版本,请随意修改它并重新构建容器。