- Описание задачи пользовательской установки в Composer
- Альтернатива пользовательским установщикам в Composer 2.1+
- Вызов пользовательского инсталлятора в Composer
- Создание инсталлятора для Composer
Описание задачи пользовательской установки в Composer
Иногда может возникнуть необходимость в том, чтобы при установке пакета в Composer требовались дополнительные действия, например, установка пакетов за пределами библиотеки поставщика vendor по умолчанию.
В таких случаях можно рассмотреть возможность создания в Composer пользовательского установщика для обработки специфической логики.
Альтернатива пользовательским установщикам в Composer 2.1+
Начиная с версии Composer 2.1, класс Composer\InstalledVersions имеет метод getInstalledPackagesByType, который позволяет во время выполнения определить, какие плагины/модули/расширения установлены.
Настоятельно рекомендуется использовать этот метод вместо создания новых пользовательских программ установки, если вы создаете новое приложение. Преимущество этого метода в том, что весь код поставщика остается в каталоге поставщика vendor и не требует создания пользовательского инсталлятора.
Вызов пользовательского инсталлятора для Composer
Предположим, что в вашем проекте уже есть пользовательский установщик для определенных модулей, тогда вызов этого установщика - это вопрос определения правильного type в файле вашего пакета.
Инструкцию по созданию пользовательских инсталляторов смотрите в следующей главе.
Каждый пользовательский инсталлятор определяет, какой тип (type) строки он будет распознавать. После распознавания он полностью отменяет установщик по умолчанию и применяет только свою собственную логику.
В качестве примера можно привести следующий случай:
phpDocumentorимеет шаблоны (Templates), которые должны быть установлены вне стандартной структуры папок/vendor. В связи с этим разработчики решили принять тип (type)phpdocumentor-templateи создать плагин, предоставляющий Custom Installer для передачи этих шаблонов в нужную папку.
Пример composer.json такого пакета шаблонов выглядит следующим образом:
{
"name": "phpdocumentor/template-responsive",
"type": "phpdocumentor-template",
"require": {
"phpdocumentor/template-installer-plugin": "*"
}
}
ВАЖНО: Чтобы убедиться, что программа установки шаблонов присутствует в момент установки пакета шаблонов, пакеты шаблонов должны запрашивать пакет плагина.
Создание инсталлятора в Composer
Пользовательский установщик определяется как класс, который реализует интерфейс Composer\Installer\InstallerInterface и обычно поставляется в Composer Plugin.
Базовый плагин установщика, таким образом, состоит из трех файлов:
- Файл пакета:
composer.json. - Класс
Plugin, например:My\Project\Composer\Plugin.php, содержащий класс, реализующийComposer\Plugin\PluginInterface. - Класс
Installer, например:My\Project\Composer\Installer.php, содержащий класс, реализующийComposer\Installer\InstallerInterface.
composer.json
Файл пакета такой же, как и любой другой файл пакета, но со следующими требованиями:
- Атрибут
typeдолжен бытьcomposer-plugin. - Атрибут
extraдолжен содержать элементclass, определяющий имя класса плагина (включая namespace). Если пакет содержит несколько плагинов, это может быть массив имен классов.
Пример:
{
"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, например, в тестовом пакете.
Класс Plugin
Класс, определяющий плагин Composer, должен реализовать интерфейс Composer\Plugin\PluginInterface. Затем он может зарегистрировать Custom Installer в своем методе 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
Класс, выполняющий пользовательскую установку, должен реализовать интерфейс Composer\Installer\InstallerInterface (или дополнить другой установщик, реализующий этот интерфейс). Он определяет строку type, как она будет распознаваться пакетами, которые будут использовать эту программу установки в методе supports().
ПРИМЕЧАНИЕ: Выбирайте имя для
typeвнимательно, рекомендуется придерживаться формата:vendor-type. Например:phpdocumentor-template.
Класс InstallerInterface определяет следующие методы (точные характеристики смотрите в исходнике):
supports(), здесь проверяется, соответствует ли переданныйtypeтому имени, которое вы объявили для этого инсталлятора (см. пример ниже).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(
'Невозможно установить шаблон, '
.'шаблоны phpdocumentor всегда должны начинать свое имя пакета с '
.'"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>.
Перевод с английского официальной документации Composer:
https://getcomposer.org/doc/articles/custom-installers.md