设置和使用自定义安装类型

概要

有时需要在包的安装过程中执行其它的动作,例如:将它安装在默认的 vendor 以外的其它目录。

在这些情况下,你可以考虑创建一个自定义安装程序来处理特定的逻辑。

调用自定义安装程序

假设你的项目已经有了一个自定义的安装模块,那么如何根据 安装类型 正确调用你包文件中的安装程序就成为了一个问题。

参见见下一章,如何通过指令创建自定义安装程序。

任何自定义安装程序都要通过 type 属性来识别。一旦被确认,它将完全覆盖默认的安装程序,并执行自己的安装逻辑。

一个实际用例:

phpDocumentor 的特殊模板需要安装在 /vendor 以外的其它目录中。因此他们选择 phpdocumentor-template 安装类型 并为此类型创建了一个插件,以便将他们的模板发送到正确的目录中。

在这样一个模板包的例子中 composer.json 将使用以下设置:

  1. {
  2. "name": "phpdocumentor/template-responsive",
  3. "type": "phpdocumentor-template",
  4. "require": {
  5. "phpdocumentor/template-installer-plugin": "*"
  6. }
  7. }
重要提示: 为了确保这个模板安装程序在安装模板包之前就已存在,模板包必须写入对此安装程序包的依赖。

创建一个安装程序

一个自定义安装程序通常是以 Composer 插件的形式存在,并包含有一个类,它实现了 Composer\Installer\InstallerInterface 这个接口。

一个基本的安装程序插件必须由3个文件组成:

  • 包文件:composer.json
  • 插件类,例如:My\Project\Composer\Plugin.php,其中的类必须实现 Composer\Plugin\PluginInterface 接口。
  • 安装程序类,例如:My\Project\Composer\Installer.php,其中的类必须实现 Composer\Installer\InstallerInterface 接口。

    composer.json

此处的包文件和普通资源包是相同的,但需要满足以下条件:

  • type 属性必须是 composer-plugin。
  • extra 属性必须包含 class 元素,它定义了插件类的名称(包含命名空间)。如果这个包有多个插件类,可以使用数组的形式进行定义。
    实例:
  1. {
  2. "name": "phpdocumentor/template-installer-plugin",
  3. "type": "composer-plugin",
  4. "license": "MIT",
  5. "autoload": {
  6. "psr-0": {"phpDocumentor\\Composer": "src/"}
  7. },
  8. "extra": {
  9. "class": "phpDocumentor\\Composer\\TemplateInstallerPlugin"
  10. },
  11. "require": {
  12. "composer-plugin-api": "1.0.0"
  13. }
  14. }

插件类

这个类定义了 Composer 的插件,它必须实现 Composer\Plugin\PluginInterface 这个接口。它可以在 activate() 方法中注册自定义安装程序。

这个类可以被放在任何位置、使用任何名字,只要能够根据 extra.class 中的定义被自动加载即可。

实例:

  1. <?php
  2. namespace phpDocumentor\Composer;
  3. use Composer\Composer;
  4. use Composer\IO\IOInterface;
  5. use Composer\Plugin\PluginInterface;
  6. class TemplateInstallerPlugin implements PluginInterface
  7. {
  8. public function activate(Composer $composer, IOInterface $io)
  9. {
  10. $installer = new TemplateInstaller($io, $composer);
  11. $composer->getInstallationManager()->addInstaller($installer);
  12. }
  13. }

自定义安装程序类

这个类用于执行自定义的安装过程,它必须实现 Composer\Installer\InstallerInterface 这个接口(或者继承了另一个实现此接口的安装程序类)。它将会对 安装类型 中定义的字符串执行 supports() 方法验证,一旦通过就采用对应的安装程序。

注意: 请慎重选择你的 安装类型 名称,建议遵循这样的格式:vendor-type。例如:phpdocumentor-template

InstallerInterface 类定义了以下方法(请查阅源码以获得更详细的信息):

  • supports() 在这里测试你发布的这个安装程序名称是否通过 安装类型 匹配(参见示例)。只有正确匹配的资源包才会使用此安装程序进行安装。
  • isInstalled() 确定支持的资源包是否已安装。
  • install() 这里你可以定义在安装时需要执行的动作。
  • update() 这里你可以定义在更新时需要执行的动作。当 Composer 调用更新参数时这是必须的。
  • uninstall() 这里你可以定义在移除一个包时需要执行的动作。
  • getInstallPath() 这个方法需要返回一个资源包将要安装的位置。相对于 composer.json 文件的位置。
    实例:
  1. <?php
  2. namespace phpDocumentor\Composer;
  3. use Composer\Package\PackageInterface;
  4. use Composer\Installer\LibraryInstaller;
  5. class TemplateInstaller extends LibraryInstaller
  6. {
  7. /**
  8. * {@inheritDoc}
  9. */
  10. public function getPackageBasePath(PackageInterface $package)
  11. {
  12. $prefix = substr($package->getPrettyName(), 0, 23);
  13. if ('phpdocumentor/template-' !== $prefix) {
  14. throw new \InvalidArgumentException(
  15. 'Unable to install template, phpdocumentor templates '
  16. .'should always start their package name with '
  17. .'"phpdocumentor/template-"'
  18. );
  19. }
  20. return 'data/templates/'.substr($package->getPrettyName(), 23);
  21. }
  22. /**
  23. * {@inheritDoc}
  24. */
  25. public function supports($packageType)
  26. {
  27. return 'phpdocumentor-template' === $packageType;
  28. }
  29. }

这个例子演示了,简单的继承 Composer\Installer\LibraryInstaller 类来剥离 phpdocumentor/template- 前缀,并用剩余的部分重新组装了一个完全不同的安装路径。

并非安装在 /vendor 目录,任何使用这个安装程序的资源包,将被放置在 /data/templates/<stripped name> 目录中。

如果您发现文档中有错误,或者能够帮我们完善文档,请提交到我们的 Github 仓库吧

原文: https://docs.phpcomposer.com/articles/custom-installers.html