Настройка, написание и запуск скриптов во время работы Composer
Как делать собственные скрипты для Composer

Как работают исполняемые скрипты в Composer.

  1. Что такое скрипт в Composer?
  2. Название событий Composer
    1. События команд Composer
    2. События установщика Composer
    3. События пакета Composer
    4. События плагина Composer
  3. Настройка сценариев Composer
  4. Классы событий Composer
  5. Запуск скриптов вручную в Composer
  6. Написание пользовательских команд Composer
  7. Управление временем ожидания процесса Composer
  8. Ссылки на скрипты Composer
  9. Вызов команд Composer
  10. Выполнение PHP-скриптов Composer
  11. Установка переменных окружения в Composer
  12. Пользовательские описания Composer
  13. Пользовательские алиасы Composer


Что такое скрипт в Composer?

В терминах Composer скрипт (сценарий) может быть как обратным вызовом PHP (определяемым как статический метод), так и любой исполняемой командой командной строки. Скрипты полезны для выполнения пользовательского кода пакета или специфических для пакета команд в процессе выполнения Composer.

Начиная с версии Composer 2.5 скрипты также могут быть классами Symfony Console Command, что позволяет легко запускать их, передавая параметры. Тем не менее, это не рекомендуется для обработки событий.

Примечание:
Выполняются только скрипты, определенные в composer.json корневого пакета. Если зависимость корневого пакета указывает свои собственные скрипты, Composer не будет выполнять дополнительные скрипты.

Название событий Composer.

В процессе выполнения Composer вызывает следующие именованные события:

События команд Composer.

  • pre-install-cmd:
    • происходит до выполнения команды install при наличии файла блокировки.
  • post-install-cmd:
    • происходит после выполнения команды install при наличии файла блокировки.
  • pre-update-cmd:
    • происходит перед выполнением команды update или перед выполнением команды install в отсутствие файла блокировки.
  • post-update-cmd:
    • происходит после выполнения команды update или после выполнения команды install в отсутствие файла блокировки.
  • pre-status-cmd:
    • происходит до выполнения команды status.
  • post-status-cmd:
    • происходит после выполнения команды status.
  • pre-archive-cmd:
    • происходит перед выполнением команды archive.
  • post-archive-cmd:
    • происходит после выполнения команды archive.
  • pre-autoload-dump:
    • происходит перед дампом автозагрузчика, либо во время install/update, либо с помощью команды dump-autoload.
  • post-autoload-dump:
    • происходит после сброса автозагрузки, либо во время install/update, либо с помощью команды dump-autoload.
  • post-root-package-install:
    • происходит после установки корневого пакета в ходе выполнения команды create-project (но до установки его зависимостей).
  • post-create-project-cmd:
    • происходит после выполнения команды create-project.

События установщика Composer.

  • pre-operations-exec:
    • происходит перед выполнением операций install/upgrade/... при установке файла блокировки. Плагины, которым нужно подключиться к этому событию, должны быть установлены глобально, чтобы их можно было использовать, так как в противном случае они не будут загружены при свежей установке проекта.

События пакета Composer.

  • pre-package-install:
    • происходит до установки пакета.
  • post-package-install:
    • происходит после установки пакета.
  • pre-package-update:
    • происходит перед обновлением пакета.
  • post-package-update:
    • происходит после обновления пакета.
  • pre-package-uninstall:
    • происходит перед удалением пакета.
  • post-package-uninstall:
    • происходит после удаления пакета.

События плагина Composer.

  • init:
    • происходит после завершения инициализации экземпляра Composer.
  • command:
    • происходит перед выполнением любой команды Composer в CLI. Она предоставляет доступ к объектам ввода и вывода программы.
  • pre-file-download:
    • происходит перед загрузкой файлов и позволяет манипулировать объектом HttpDownloader перед загрузкой файлов на основе URL-адреса для загрузки.
  • post-file-download:
    • происходит после загрузки файлов пакета дистрибутива и позволяет выполнить дополнительные проверки файла, если это необходимо.
  • pre-command-run:
    • происходит перед выполнением команды и позволяет манипулировать параметрами и аргументами объекта InputInterface, чтобы изменить поведение команды.
  • pre-pool-create:
    • происходит перед созданием пула пакетов и позволяет отфильтровать список пакетов, которые попадут в Solver.

Примечание:
Composer не делает никаких предположений о состоянии ваших зависимостей перед командами install или update. Поэтому не следует указывать скрипты, требующие управляемых Composer зависимостей, в сценариях pre-update-cmd или pre-install-cmd. Если требуется выполнить скрипты перед процессами install или update, убедитесь, что они находятся в корневом пакете.

Настройка сценариев Composer.

Корневой объект JSON в composer.json должен иметь свойство "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:

<?php

namespace MyVendor;

use Composer\Script\Event;
use Composer\Installer\PackageEvent;

class MyClass
{
    public static function postUpdate(Event $event)
    {
        $composer = $event->getComposer();
        // что-то сделать ещё
    }

    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();
        // что-то сделать ещё
    }

    public static function warmCache(Event $event)
    {
        // сделать кэш вкусным
    }
}

Примечание:
Во время выполнения команды install или update Composer в окружение будет добавлена переменная COMPOSER_DEV_MODE. Если команда была запущена с флагом --no-dev, эта переменная будет установлена в 0, в противном случае она будет установлена в 1. Переменная также доступна во время выполнения dump-autoload, и она будет установлена в то же значение, в котором была запущена последняя команда install или update.

Классы событий Composer.

Когда происходит событие, в качестве первого аргумента ваш обратный вызов PHP получает объект Composer\EventDispatcher\Event. Этот объект имеет метод getName(), который позволяет получить название события.

В зависимости от типа сценария вы получите различные подклассы событий, содержащие различные геттеры с соответствующими данными и связанными с ними объектами:

Запуск скриптов вручную в Composer.

Если требуется запустить скрипты для события вручную, синтаксис будет следующим:

php composer.phar run-script [--dev] [--no-dev] script

Например, composer run-script post-install-cmd запустит все скрипты и плагины post-install-cmd, которые были определены.

Обработчику скриптов также можно передать дополнительные аргументы, добавив -- после аргументов обработчика. Например, composer run-script post-install-cmd -- --check передаст обработчику скриптов аргумент --check. Эти аргументы принимаются как аргументы CLI обработчиками CLI, и могут быть получены как массив через $event->getArguments() обработчиками PHP.

Написание пользовательских команд Composer.

Если добавляются пользовательские сценарии, которые не подходят ни под одно из предопределенных выше названий событий, их можно запустить с помощью run-script или как собственные команды Composer. Например, обработчик, определенный ниже, выполняется при запуске команды composer test:

{
    "scripts": {
        "test": "phpunit",
        "do-something": "MyVendor\\MyClass::doSomething"
        "my-cmd": "MyVendor\\MyCommand"
    }
}

Аналогично команде run-script можно передавать дополнительные аргументы скриптам, например, composer test -- --filter <pattern> передаст --filter <pattern> скрипту phpunit.

Использование метода PHP через composer do-something arg позволяет выполнить статическую функцию doSomething(\Composer\Script\Event $event) и arg становится доступным в $event->getArguments(). Однако это не позволяет с легкостью передавать пользовательские параметры в виде --flags.

Используя класс Command из symfony/console, можно определить и получить доступ к аргументам и параметрам более легко.

Например, с командой показанной ниже, можно просто вызвать composer my-cmd --arbitrary-flag без разделителя --. Чтобы команды были распознаны как команды symfony/console, имя класса должно заканчиваться на Command и расширять класс Command symfony. Также обратите внимание, что для запуска будет использоваться встроенная в Composer версия symfony/console, которая может не совпадать с той, что требуется в вашем проекте, и может меняться между минорными выпусками Composer. Если требуется больше гарантий безопасности, лучше использовать собственный бинарный файл, который запускает вашу собственную версию symfony/console изолированно в собственном процессе.

<?php

namespace MyVendor;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class MyCommand extends Command
{
    protected function configure(): void
    {
        $this->setDefinition([
            new InputOption('arbitrary-flag', null, InputOption::VALUE_NONE, 'Example flag'),
            new InputArgument('foo', InputArgument::OPTIONAL, 'Optional arg'),
        ]);
    }

    public function execute(InputInterface $input, OutputInterface $output): int
    {
        if ($input->getOption('arbitrary-flag')) {
            $output->writeln('The flag was used')
        }

        return 0;
    }
}

Примечание:
Перед выполнением скриптов bin-dir Composer временно помещается поверх переменной окружения PATH, чтобы двоичные файлы зависимостей были доступны напрямую. В данном примере неважно, находится ли двоичный файл phpunit в vendor/bin/phpunit или bin/phpunit, он будет найден и выполнен.

Управление временем ожидания процесса Composer.

Хотя Composer не предназначен для управления длительными процессами и другими подобными моментами в PHP-проектах, иногда бывает полезно отключить таймаут процесса в пользовательских командах. По умолчанию этот таймаут составляет 300 секунд и может быть переопределен различными способами в зависимости от требуемого эффекта:

  • отключить его для всех команд с помощью config-ключа process-timeout,
  • отключить его для текущего или будущих вызовов Composer с помощью переменной окружения COMPOSER_PROCESS_TIMEOUT,
  • для конкретного вызова с помощью флага --timeout команды run-script,
  • с помощью статического помощника для отдельных скриптов.

Чтобы отключить таймаут для конкретных скриптов, используйте статический помощник непосредственно в composer.json:

{
    "scripts": {
        "test": [
            "Composer\\Config::disableProcessTimeout",
            "phpunit"
        ]
    }
}

Чтобы отключить таймаут для каждого скрипта в конкретном проекте, можно воспользоваться конфигурацией composer.json:

{
    "config": {
        "process-timeout": 0
    }
}

Также можно установить глобальную переменную окружения, чтобы отключить тайм-аут всех следующих скриптов в текущем окружении терминала:

export COMPOSER_PROCESS_TIMEOUT=0

Чтобы отключить тайм-аут для одного вызова сценария, необходимо использовать команду run-script composer и указать параметр --timeout:

php composer.phar run-script --timeout=0 test

Ссылки на скрипты Composer.

Чтобы обеспечить повторное использование сценария и избежать дублирования, его можно вызвать из другого сценария, добавив к имени команды префикс @:

{
    "scripts": {
        "test": [
            "@clearCache",
            "phpunit"
        ],
        "clearCache": "rm -rf cache/*"
    }
}

Можно также обратиться к скрипту и передать ему новые аргументы:

{
    "scripts": {
        "tests": "phpunit",
        "testsVerbose": "@tests -vvv"
    }
}

Вызов команд Composer.

Для вызова команд Composer можно использовать @composer, который автоматически перейдет к тому composer.phar, который используется в данный момент:

{
    "scripts": {
        "test": [
            "@composer install",
            "phpunit"
        ]
    }
}

Одно из ограничений заключается в том, что невозможно вызвать несколько команд composer подряд, например @composer install && @composer foo. Их необходимо разделить в JSON-массиве команд.

Выполнение PHP-скриптов Composer.

Для выполнения PHP-скриптов можно использовать @php, который автоматически переадресуется на тот процесс php, который используется в данный момент:

{
    "scripts": {
        "test": [
            "@php script.php",
            "phpunit"
        ]
    }
}

Одно из ограничений заключается в том, что нельзя вызывать несколько команд подряд, например @php install && @php foo. Их нужно разделить в JSON-массиве команд.

Также можно вызвать скрипт shell/bash, в котором путь к исполняемому файлу PHP будет доступен в качестве переменной окружения PHP_BINARY.

Установка переменных окружения в Composer.

Чтобы установить переменную окружения кроссплатформенным способом, используется @putenv:

{
    "scripts": {
        "install-phpstan": [
            "@putenv COMPOSER=phpstan-composer.json",
            "composer install --prefer-dist"
        ]
    }
}

Пользовательские описания Composer.

В файле composer.json можно задать пользовательские описания скриптов:

{
    "scripts-descriptions": {
        "test": "Запуск всех тестов!"
    }
}

Описания используются в командах composer list или composer run -l для описания того, что делают скрипты при выполнении команды.

Примечание:
Настроить пользовательские описания можно только для пользовательских команд.

Пользовательские алиасы Composer.

В файле composer.json можно задать пользовательские псевдонимы скриптов с помощью следующих параметров:

{
    "scripts-aliases": {
        "phpstan": ["stan", "analyze"]
    }
}

Алиасы представляют собой альтернативные имена команд.

Примечание:
Установить пользовательские псевдонимы можно только для пользовательских команд.

Перевод с английского официальной документации Composer:
https://getcomposer.org/doc/articles/scripts.md

Заберите ссылку на статью к себе, чтобы потом легко её найти!
Раз уж досюда дочитали, то может может есть желание рассказать об этом месте своим друзьям, знакомым и просто мимо проходящим?
Не надо себя сдерживать! ;)

Старт! Горячий старт на просторы интернета
Старт! Горячий старт на просторы интернета
Старт! Меню