当前位置: 首页 > 文档资料 > Composer 中文文档 >

3.7. 事件和自定义脚本

优质
小牛编辑
127浏览
2023-12-01

什么是 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 对象进行操作,例如命令输入的 optionsarguments ,以此来控制命令的行为

请注意:在 install 或者update 前,Composer 对你的依赖是一无所知的,所以你不应该在 pre-update-cmd 或者 pre-install-cmd 事件中使用任何第三方依赖的命令。如果你不得不这么做,你可以在你的项目里编写逻辑,然后在 installupdate 命令触发时调用你自己的命令。

定义 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 的 installupdate 过程时,环境变量 COMPOSER_DEV_MODE 会被设置,此值来自于执行命令时的 --no-dev 参数,如果设置了为 0,每调用的情况下为 1。

事件类

当事件被触发时,PHP 的回调代码中会接收到 Composer\EventDispatcher\Event 对象。此对象会有一个 getName() 方法来让你获取到事件的名称。

取决于 script 类型 你会获取到不同的类对象以及各类型对象包含的变量:

  • 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!"
    }
}

注意:您只能设置自定义命令的自定义描述.