Drupal的每一次迭代都带来了大量的安全改进、可访问性改进,以及Drupal社区创建的一系列新功能。2022年12月发布的Drupal 10带来了令人印象深刻的UI改进,为管理界面和默认主题提供了漂亮的视觉体验。
自2015年8月发布Drupal 8以来,Drupal一直在不断发展并添加新功能,使其与现代开发实践保持同步。Drupal 8中的最大变化之一是Composer的集成,Composer是一个基于PHP的依赖管理器。Composer是一个功能强大的工具,可用于安装模块、升级Drupal,甚至检查整个项目中使用的模块和依赖项之间的兼容性。了解如何利用Composer升级Drupal代码库是绝对必要的。幸运的是,Composer很容易掌握。
在本文中,我们将简要概述Composer如何在Composer.json和Composer.lock中跟踪项目的依赖关系。然后我们将讨论如何利用Composer和社区构建的工具来确保代码与最新更新之间的兼容性。最后,我们将介绍使用Composer命令来升级Drupal并解决冲突。
如果您运行的是Drupal的较旧版本,如Drupal 7,请查看长风drupal开发官网的文章,有关将网站从Drupal 7升级到Drupal9的提示。
一、使用composer升级Drupal网站的原则
Composer是一个基于PHP的依赖管理器,用于跟踪和下载Drupal模块、Symphony库,甚至Drupal内核本身。Composer使用语义版本控制来传达不同包版本之间的兼容性。主要版本的更改(例如从Drupal 9.x更改为10.x)意味着开发人员在升级项目时可能需要解决潜在的不兼容问题。
Composer使用Composer.json文件来跟踪我们项目的显式依赖关系作为语义版本范围。例如,您的项目可能需要drupal/core:>=9.4,这将告诉Composer安装drupal核心版本9.4或更高版本。项目使用的每个模块和主题都将在composer.json中有一行对应的内容。
我们项目的每个依赖项都有自己的依赖项。例如,Drupal Commerce模块需要Address模块以及用于货币格式化的非Drupal PHP库。当我们下载商务模块时,Composer还将下载地址模块和货币格式库。
当Composer递归地解析每个依赖项时,它会构建整个项目中使用的第三方依赖项的完整列表(包括依赖项的依赖项)。然后将完全解析的依赖关系树存储在composer.lock文件中。此文件包含每个依赖项的元数据,包括下载包的位置、任何PSR-4自动加载信息以及引用依赖项的确切版本的哈希。当其他开发人员和CI管道运行composer install命令时,composer会检查composer.lock文件并将列出的所有依赖项下载到项目中。
二、评估使用composer升级Drupal网站的兼容性
不兼容可以采取几种不同的形式。在Drupal10的例子中,有8个模块,一个主题从核心中删除(一些被移到contrib空间,另一些被删除)。我们还看到从核心中完全删除了各种已弃用的函数。如果您的项目依赖于其中任何一项,您需要采取措施解决不兼容问题。
Drupal社区维护一个名为“升级状态”的模块,可用于为您提供升级路径的全貌。本模块为您提供了一系列工具,可用于扫描Drupal安装中不推荐使用的模块。它还扫描您的代码库,查找对不推荐使用的函数的调用,或者info.yml和composer.json文件中的不兼容性。
# Install the latest dev version of Upgrade Status
composer require drupal/upgrade_status:4.x-dev --dev
升级状态中最强大的工具之一叫做“Drupal Check”。Drupal Check使用PHPStan的静态分析来查找对不推荐使用的函数的调用。Drupal检查是一个很好的工具,可以帮助以高性能的方式查找代码中的错误,并且是您应该在CI管道中内置的工具类型。如果我不叫Acquia BLT,那我就太粗心了,它内置了Drupal Check!
升级状态依赖于Drupal检查。这意味着Composer将在Composer-require命令期间自动安装Drupal Check和Upgrade Status。我们也可以通过类似的composer-require命令明确要求Drupal Check。
# Require Drupal Check explicitly
composer require mglaman/drupal-check
# Run drupal-check
php vendor/bin/drupal-check
运行Drupal Check将输出一个潜在代码问题列表,供您在执行升级之前检查和解决。任何对弃用代码的调用都可以使用Drupal的更改记录来解决。Drupal的代码库通常也会发出PHP通知,其中包含如何解决未来的弃用问题的详细信息。
三、PHP版本升级
Drupal10最低要求为PHP 8.1,这与Drupal 9最低要求的7.4相去甚远。PHP8为语言结构带来了令人印象深刻的优化和更改。Composer允许我们将PHP版本指定为项目依赖项,就像我们需要其他依赖项一样。这迫使Composer检查我们的包是否与PHP8兼容。
composer require php:"^8.1" --no-update
我们还可以要求在主机上运行特定版本的PHP。如果在他们的系统上运行的PHP版本没有升级到合适的版本,这将给开发人员一个警告。
composer config platform.php 8.1
大多数PHP7.4代码都与8.x兼容,但最好通过更改通知和上面概述的工具检查向后兼容性。
四、使用Composer升级Drupal Core
最后,是时候升级Drupal了!使用Composer,我们可以使用Composer-require命令显式地要求Drupal10。这将更新composer.json并添加Drupal10作为显式依赖项。我们还传递--no更新标志,以防止完全依赖关系解析过程运行。这为我们在开始升级过程之前提供了一个“保存工作”的好地方。
composer require drupal/core:"^10.0" --no-update
这个require命令告诉Composer Drupal core的最低可接受版本是10.0。放置明确版本要求的包将因项目而异。如果您的项目是使用Drupal.org上的说明设置的,那么这个版本要求将在Drupal/core推荐的包中进行。通过检查composer.json文件,可以找到要放置版本约束的包。
composer require drupal/core-recommended:"^10.0" --no-update
最后,我们可以通过运行以下命令来升级所有依赖项:
composer update
该命令获取composer.json文件中的信息,并尝试解析依赖关系树。在执行此操作时,它将分析项目的所有依赖项,包括PHP版本,并确定是否有满足所有依赖项的方法。这一过程通常并不简单,最终可能会产生冲突。这没问题!事实上,这意味着Composer在发现冲突方面做得很好。
冲突输出如下所示:
- Root composer.json requires drupal/devel ^4.0 -> satisfiable by drupal/devel[4.0.0-rc1, ..., 4.x-dev].
- drupal/core-recommended[10.0.0-alpha4, ..., 10.0.0-alpha5] require symfony/var-dumper v6.0.8 -> satisfiable by symfony/var-dumper[v6.0.8].
- Conclusion: don't install symfony/var-dumper v6.0.8 (conflict analysis result)
在本例中,Composer告诉我们,devel正在与Drupal核心的一个相互依赖项symfony/var-dumper发生冲突。在访问Devel模块页面后,我们可以看到一个与Drupal10兼容的较新版本的Devel。我们可以需要此模块的新版本,然后重新运行更新过程。
composer require drupal/devel:^5.0 --no-update
composer update
这解决了devel模块的版本不兼容问题,我们将继续解决更新过程中出现的其他冲突。解决这些冲突可能需要一些不同的方法。有时需要使用模块的开发版本,有时可能需要向Drupal.org提交您自己的补丁。升级状态模块为我们做了很多这方面的工作,但理解和解决Composer冲突是现代Drupal开发中的一项重要技能。
从这里开始,流程是冲洗和重复运行Composer更新、分析冲突,并使用适当的方法解决。
历史上,Drupal版本之间的升级充满了挑战,需要大量的开发和测试。自从推出Composer和社区工具(如UpgradeStatus和Drupal Check)以来,升级变得更加容易。通过一点点配置和诀窍,Composer可以用来升级从PHP版本和contrib模块到Drupal内核本身的所有内容,同时发现不兼容和潜在问题。
正确理解和使用Composer是成功升级和维护现代Drupal项目的关键。