跳转到内容

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

有时,一个包可能需要在安装过程中执行额外操作,例如在默认的vendor库之外安装包。

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

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

Section titled “Composer 2.1+的自定义安装程序替代方案”

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

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

假设你的项目已经有了针对特定模块的自定义安装程序,那么调用该安装程序只需在你的包文件中定义正确的类型即可。

有关如何创建自定义安装程序的说明,请参见下一章。

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

一个示例用例如下:

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

这样一个模板包的composer.json示例如下:

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

重要提示:为确保在安装模板包时模板安装程序已存在,模板包应依赖插件包。

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

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

  1. 包文件:composer.json
  2. Plugin 类,例如:My\Project\Composer\Plugin.php,其中包含一个实现了 Composer\Plugin\PluginInterface 的类。
  3. Installer类,例如:My\Project\Composer\Installer.php,其中包含一个实现了Composer\Installer\InstallerInterface的类。

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

  1. type属性必须为composer-plugin
  2. 额外属性必须包含一个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()方法中注册CustomInstaller。

该类可以放在任何位置,并且可以有任何名称,只要它是可自动加载的,并且与包定义中的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参数调用时所需的行为。
  • 卸载(),在这里你可以确定当软件包需要被移除时需要执行的操作。
  • 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>文件夹中。