3.7. 事件和自定义脚本
什么是 script
?
script
被定义在 composer.json
里,可以是 PHP 类静态方法,也可以是可执行的命令行调用。script
是用来 Composer 执行时执行扩展包里的自定义代码,或者扩展包专属的命令行。
注:只有项目里的
composer.json
会被执行,很多时候我们的项目会依赖于多个扩展,这些扩展里的里composer.json
配置的script
将不会被执行。译者注:Laravel 中利用 Composer 的 Script 来执行安装完后的动作,请见代码 https://github.com/laravel/laravel/blob/master/composer.json 。
事件名称
Composer 在执行的过程中会触发这些事件,你可以通过监控这些事件来控制 scirpt
的执行顺序。
命令事件
- pre-install-cmd: 当项目里有
composer.lock
文件的情况下调用install
命令执行前 - post-install-cmd: 当项目里有
composer.lock
文件的情况下调用install
命令执行后 - pre-update-cmd: 当
update
命令被执行前,或者当项目里没有composer.lock
文件的情况下调用install
命令执行前 - post-update-cmd: 当
update
命令被执行后,或者当项目里没有composer.lock
文件的情况下调用install
命令执行后 - post-status-cmd: 当
status
命令被执行后 - pre-archive-cmd: 当
archive
命令被执行前 - post-archive-cmd: 当
archive
命令被执行后 - pre-autoload-dump: 当自动加载器 dump 成功了前触发,调用
install
/update
或者dump-autoload
命令时都会触发此事件 - post-autoload-dump: 当自动加载器 dump 成功了后触发,调用
install
/update
或者dump-autoload
命令时都会触发此事件 - post-root-package-install: 当执行
create-project
命令时,在根项目安装成功后 - post-create-project-cmd: 当
create-project
命令被执行后
安装器事件
- pre-dependencies-solving: 当依赖被解析前
- post-dependencies-solving: 当依赖被解析后
扩展包事件
- pre-package-install: 当扩展包被安装前
- post-package-install: 当扩展包被安装后
- pre-package-update: 当扩展包被更新前
- post-package-update: 当扩展包被更新后
- pre-package-uninstall: 当扩展包被移除前
- post-package-uninstall: 当扩展包被移除后
插件事件
- init: 当 Composer 实例初始化成功后触发
- command: 在命令行里执行任何 Composer 命令前都会调用,提供了一个可读取程序输入和输出对象的接口
- pre-file-download: 在文件还未被下载前,允许你操作
RemoteFilesystem
文件下载对象 - pre-command-run: 当命令一个命令被执行前,允许你对
InputInterface
对象进行操作,例如命令输入的options
和arguments
,以此来控制命令的行为
请注意:在
install
或者update
前,Composer 对你的依赖是一无所知的,所以你不应该在pre-update-cmd
或者pre-install-cmd
事件中使用任何第三方依赖的命令。如果你不得不这么做,你可以在你的项目里编写逻辑,然后在install
或update
命令触发时调用你自己的命令。
定义 scripts
我们需要在项目的 composer.json
定义一个叫 "scripts"
的选项,在此选项里,设置事件名称和对应的要执行的命令或脚本。命令和脚本的值可以是字符串的名称,也可以是数组(单个或者多个)。
对于每一个事件:
- Scripts 执行的顺序遵循事件触发的顺序;
- 事件对于的值为数组的,数组里的每个项可以是 PHP 脚本或者是命令行;
- PHP 类定义的回调,必须由 Composer 的加载器价值;
- 回调可以是 psr-0, psr-4 或者 classmap 定义。如果你的脚本需要外部依赖,你需要自己加载这些类依赖。
例子:
{
"scripts": {
"post-update-cmd": "MyVendor\\MyClass::postUpdate",
"post-package-install": [
"MyVendor\\MyClass::postPackageInstall"
],
"post-install-cmd": [
"MyVendor\\MyClass::warmCache",
"phpunit -c app/"
],
"post-autoload-dump": [
"MyVendor\\MyClass::postAutoloadDump"
],
"post-create-project-cmd": [
"php -r \"copy('config/local-example.php', 'config/local.php');\""
]
}
}
照着上面的定义,我们来编写 MyVendor\MyClass
类,此类的作用是来执行这些回调(注意都是静态方法):
<?php
namespace MyVendor;
use Composer\Script\Event;
use Composer\Installer\PackageEvent;
class MyClass
{
public static function postUpdate(Event $event)
{
$composer = $event->getComposer();
// do stuff
}
public static function postAutoloadDump(Event $event)
{
$vendorDir = $event->getComposer()->getConfig()->get('vendor-dir');
require $vendorDir . '/autoload.php';
some_function_from_an_autoloaded_file();
}
public static function postPackageInstall(PackageEvent $event)
{
$installedPackage = $event->getOperation()->getPackage();
// do stuff
}
public static function warmCache(Event $event)
{
// make cache toasty
}
}
请注意:在 Composer 的 install
和 update
过程时,环境变量 COMPOSER_DEV_MODE
会被设置,此值来自于执行命令时的 --no-dev
参数,如果设置了为 0,每调用的情况下为 1。
事件类
当事件被触发时,PHP 的回调代码中会接收到 Composer\EventDispatcher\Event
对象。此对象会有一个 getName()
方法来让你获取到事件的名称。
取决于 script 类型 你会获取到不同的类对象以及各类型对象包含的变量:
- 基类:
Composer\EventDispatcher\Event
- 事件类:
Composer\Script\Event
- 安装器事件:
Composer\Installer\InstallerEvent
- 扩展事件:
Composer\Installer\PackageEvent
- 插件事件:
- init: [`Composer\EventDispatcher\Event`](https://getcomposer.org/apidoc/master/Composer/EventDispatcher/Event.html) * command: [`Composer\Plugin\CommandEvent`](https://getcomposer.org/apidoc/master/Composer/Plugin/CommandEvent.html) * pre-file-download: [`Composer\Plugin\PreFileDownloadEvent`](https://getcomposer.org/apidoc/master/Composer/Plugin/PreFileDownloadEvent.html)
手动执行 scripts
如果你想要手动执行一个事件对应的 scripts
,语法如下:
composer run-script [--dev] [--no-dev] script
例如 composer run-script post-install-cmd
会运行 post-install-cmd
对应的 scripts
。
你可以使用 --
来给 scripts
传参,例如 composer run-script post-install-cmd -- --check
,scripts
是命令的情况下,会如正常传参那样接收到 --check
参数,而使用 PHP 脚本的情况下,你可以使用 $event->getArguments()
来获取到相同的传参。
编写自定义命令
如果你的自定义 scripts
逻辑与所有事件名称都不匹配的话,你也可以自定义自己的 Composer 命令。如下面的定义允许你新增 composer test
命令:
{
"scripts": {
"test": "phpunit"
}
}
这种模式与 run-script
命令一样可以接收参数,如: composer test -- --filter
会将参数 --filter
传到 phpunit
脚本中。
注意:在执行脚本前,你需要知道,按照一般情况下的配置 Composer 的
bin
目录会放到系统 PATH 前面,所以以上命令phpunit
无论是在vendor/bin/phpunit
或者在bin/phpunit
中,都能够被执行到。
引用脚本
为了重新使用脚本以及避免重复启用脚本,可以通过在命令前面加上一个 @
来调用另外一个脚本:
{
"scripts": {
"test": [
"@clearCache",
"phpunit"
],
"clearCache": "rm -rf cache/*"
}
}
调用 Composer 命令
要调用 Composer 命令,可以使用 @composer
,它会自动解析到当前正在使用的 composer.phar 上面:
{
"scripts": {
"test": [
"@composer install",
"phpunit"
]
}
}
这样做的一个限制是,你不能像 @composer install && @composer foo
这样在一行调用多个 composer 命令。你必须把他们分隔成一个 JSON 命令数组。
执行 PHP 脚本
要执行 PHP 脚本,您可以使用 @php
它将自动解析为当前正在使用的 PHP 进程:
{
"scripts": {
"test": [
"@php script.php",
"phpunit"
]
}
}
这样做的局限是您不能像 @php install && @php foo
这样调用多个命令。您必须将它们拆分为 JSON 命令数组。
自定义说明
您可以在 composer.json
文件中使用以下内容来设置自定义脚本描述:
{
"scripts-descriptions": {
"test": "Run all tests!"
}
}
注意:您只能设置自定义命令的自定义描述.