自定义安装程序的设置和使用#

概述#

有时,包可能需要在安装期间执行额外的操作,例如在默认的 vendor 库之外安装包。

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

Composer 2.1+ 中自定义安装程序的替代方案#

从 Composer 2.1 开始,Composer\InstalledVersions 类有一个 getInstalledPackagesByType 方法,该方法可以让你在运行时确定哪些插件/模块/扩展已安装。

如果您正在构建一个新的应用程序,强烈建议您使用它而不是构建新的自定义安装程序。这具有将所有供应商代码保留在供应商目录中的优点,并且不需要自定义安装程序代码。

调用自定义安装程序#

假设您的项目已经为特定模块创建了自定义安装程序,那么调用该安装程序只需在您的包文件中定义正确的 类型

请参阅下一章了解如何创建自定义安装程序的说明。

每个自定义安装程序都会定义它将识别的 类型 字符串。一旦被识别,它将完全覆盖默认的安装程序,并且只应用它自己的逻辑。

一个用例示例是

phpDocumentor 的特性模板需要安装在默认的 /vendor 文件夹结构之外。因此,他们选择采用 phpdocumentor-template 类型 并创建一个插件,该插件提供自定义安装程序将这些模板发送到正确的文件夹。

此类模板包的 composer.json 示例:

{
    "name": "phpdocumentor/template-responsive",
    "type": "phpdocumentor-template",
    "require": {
        "phpdocumentor/template-installer-plugin": "*"
    }
}

重要提示:为了确保模板安装程序在模板包安装时存在,模板包应该需要插件包。

创建安装程序#

自定义安装程序被定义为一个类,该类实现了 Composer\Installer\InstallerInterface,通常在 Composer 插件中分发。

因此,一个基本的安装程序插件将由三个文件组成

  1. 包文件:composer.json
  2. 插件类,例如:My\Project\Composer\Plugin.php,包含一个实现 Composer\Plugin\PluginInterface 的类。
  3. 安装程序类,例如:My\Project\Composer\Installer.php,包含一个实现 Composer\Installer\InstallerInterface 的类。

composer.json#

包文件与任何其他包文件相同,但具有以下要求

  1. 类型 属性必须为 composer-plugin
  2. extra 属性必须包含一个元素 class,定义插件的类名(包括命名空间)。如果一个包包含多个插件,则可以是一个类名数组。

示例

{
    "name": "phpdocumentor/template-installer-plugin",
    "type": "composer-plugin",
    "license": "MIT",
    "autoload": {
        "psr-0": {"phpDocumentor\\Composer": "src/"}
    },
    "extra": {
        "class": "phpDocumentor\\Composer\\TemplateInstallerPlugin"
    },
    "require": {
        "composer-plugin-api": "^1.0"
    },
    "require-dev": {
        "composer/composer": "^1.3"
    }
}

上面的示例在其 require-dev 中有 Composer 本身,这允许您在测试套件中使用 Composer 类,例如。

插件类#

定义 Composer 插件的类必须实现 Composer\Plugin\PluginInterface。然后它可以在其 activate() 方法中注册自定义安装程序。

该类可以放置在任何位置,并具有任何名称,只要它可自动加载并且与包定义中的 extra.class 元素匹配即可。

示例

<?php

namespace phpDocumentor\Composer;

use Composer\Composer;
use Composer\IO\IOInterface;
use Composer\Plugin\PluginInterface;

class TemplateInstallerPlugin implements PluginInterface
{
    public function activate(Composer $composer, IOInterface $io)
    {
        $installer = new TemplateInstaller($io, $composer);
        $composer->getInstallationManager()->addInstaller($installer);
    }
}

自定义安装程序类#

执行自定义安装的类应该实现 Composer\Installer\InstallerInterface(或扩展实现该接口的另一个安装程序)。它定义了 类型 字符串,因为将在 supports() 方法中被使用此安装程序的包识别。

注意请仔细选择您的 类型 名称,建议遵循格式:vendor-type。例如:phpdocumentor-template

InstallerInterface 类定义了以下方法(有关确切签名,请参阅源代码)

  • supports(),在这里您测试传递的 类型 是否与您为此安装程序声明的名称匹配(参见示例)。
  • isInstalled(),确定支持的包是否已安装。
  • install(),在这里您可以确定安装时需要执行的操作。
  • update(),在这里您定义 Composer 使用 update 参数调用时所需的行为。
  • uninstall(),在这里您可以确定包需要删除时需要执行的操作。
  • getInstallPath(),此方法应返回包将安装到的绝对路径。路径不能以斜杠结尾。

示例

<?php

namespace phpDocumentor\Composer;

use Composer\Package\PackageInterface;
use Composer\Installer\LibraryInstaller;

class TemplateInstaller extends LibraryInstaller
{
    /**
     * @inheritDoc
     */
    public function getInstallPath(PackageInterface $package)
    {
        $prefix = substr($package->getPrettyName(), 0, 23);
        if ('phpdocumentor/template-' !== $prefix) {
            throw new \InvalidArgumentException(
                'Unable to install template, phpdocumentor templates '
                .'should always start their package name with '
                .'"phpdocumentor/template-"'
            );
        }

        return 'data/templates/'.substr($package->getPrettyName(), 23);
    }

    /**
     * @inheritDoc
     */
    public function supports($packageType)
    {
        return 'phpdocumentor-template' === $packageType;
    }
}

该示例演示了可以扩展 Composer\Installer\LibraryInstaller 类以剥离前缀 (phpdocumentor/template-) 并使用剩余部分来组装一个完全不同的安装路径。

任何使用此安装程序安装的包都不会安装在 /vendor 中,而是放在 /data/templates/<stripped name> 文件夹中。

发现错别字?此文档中有什么错误? 分支并编辑 它!