Создание плагина для PHP Composer’а

в 11:06, , рубрики: composer plugin, php, Программирование

При развертывании Magento-приложений с использованием Magento Composer столкнулись с проблемой, что различные экземпляры одного и того же приложения (девелоперский, тестовый и т.д.) должны использовать различные локальные настройки (например, параметры подключения к БД). До этого, в другом проекте, использовался подход, когда в приложении (под контролем версий) находятся шаблоны конфигурационных файлов с placeholder'ами и скрипт, замещающий placeholder'ы локальными значениями и копирующий результат в нужное место. Локальные значения хранились отдельно для каждого экземпляра по месту развертывания. Хотелось привычный подход сохранить и для нового метода развертывания. Поиск устраивающего плагина на packagist.org/ завершился ненахождением, в силу чего и родилась идея сделать подобный плагин самостоятельно. При создании плагина пришлось надергать информацию из различных источников — информации с сайта Composer'а по плагинам оказалось недостаточно. Что и привело к написанию этой статьи.

composer.json

Основной файл плагин-пакета выглядит примерно так:

{
  "name": "praxigento/composer_plugin_templates",
  "type": "composer-plugin",
  "require": {
    "composer-plugin-api": "1.0.0"
  },
  "autoload": {
    "psr-4": {
      "\Praxigento\Composer\Plugin\Templates\": "src/"
    }
  },
  "extra": {
    "class": "\Praxigento\Composer\Plugin\Templates\"
  },
  "scripts": {
    "test": "phpunit"
  }
}

Параметр name заполняется по своему вкусу, у меня получился praxigento/composer_plugin_templates.

С параметрами type и require все достаточно однозначно — они должны быть и быть именно такими.

Параметр autoload.psr-4 определяет настройку автозагрузки классов плагина в соответствии с PSR-4 (рекомендуется использовать именно этот стандарт, т.к. PSR-0 устарел 21 октября 2014 года). Согласно этой настройки наши исходники располагаются в подкаталоге ./src/.

Параметр extra.class определяет основной класс плагина, который подгружается Composer'ом (или набор классов, если значение параметра — массив).

Параметр scripts.test позволяет запускать тестирование плагина из командной строки: "$ composer test".

Точка входа

Класс, заданный в extra.class, является точкой входа Composer'а в наш плагин. Согласно требованиям Composer'а этот класс должен имплементировать интерфейс ComposerPluginPluginInterface.

namespace PraxigentoComposerPluginTemplates;

use ComposerComposer;
use ComposerIOIOInterface;
use ComposerPluginPluginInterface;

class Main implements PluginInterface {
	protected $composer;
	protected $io;

	public function activate(Composer $composer, IOInterface $io) {
		$this->composer = $composer;
		$this->io       = $io;
	}
}

Доступ к параметрам

Конфигурация параметров работы плагина осуществляется через секцию extra в composer.json основного пакета, в котором используется наш плагин.

{
  "name": "vendor/package",
  "type": "project",
  "repositories": [
    {
      "type": "vcs",
      "url": "https://github.com/praxigento/composer_plugin_templates"
    }
  ],
  "require": {
    "praxigento/composer_plugin_templates": "*"
  },
  "extra": {
    "praxigento_templates_config": "./instance_cfg.json"
  }
}

Плагин должен взять настройки для своей работы из файла, который задается через параметр extra.praxigento_templates_config конфигурационного файла проекта (composer.json). Мы это делаем при инициализации плагина:

class Main implements PluginInterface, EventSubscriberInterface {

	public function activate(Composer $composer, IOInterface $io) {
		$this->composer = $composer;
		$this->io       = $io;
		$extra          = $composer->getPackage()->getExtra();
		$configFile = $extra['praxigento_templates_config'];
	}

}

Обработка событий

В своей реализации плагина мы хотели, чтобы он реагировал на события:

  • post-install-cmd
  • post-update-cmd

Для этого наша точка входа должна также имплементировать интерфейс EventSubscriberInterface, подписаться на соответствующие события и зарегистрировать обработчки:

class Main implements PluginInterface, EventSubscriberInterface {
	public static function getSubscribedEvents() {
		$result = array(
			ScriptEvents::POST_INSTALL_CMD => array(
				array( 'onPostInstallCmd', 0 )
			),
			ScriptEvents::POST_UPDATE_CMD  => array(
				array( 'onPostUpdateCmd', 0 )
			),
		);
		return $result;
	}

	public function onPostInstallCmd(CommandEvent $event) {

	}

	public function onPostUpdateCmd(CommandEvent $event) {

	}
}

Запуск тестов

Подключение PhpUnit осуществляется в composer.json:

{
  "require-dev": {
    "phpunit/phpunit": "4.4.*"
  }
}

Настройки юнит-тестирования — в файле phpunit.xml.dist:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false"
         syntaxCheck="false"
         bootstrap="phpunit.bootstrap.php"
        >

    <testsuites>
        <testsuite name="Plugin Test Suite">
            <directory suffix="_Test.php">./src/</directory>
        </testsuite>
    </testsuites>
</phpunit>

Загрузка autoloader'а, совместимого с PSR-4 (без него не запускаются тесты через IDE PhpStorm) в скрипте phpunit.bootstrap.php:

require __DIR__.'/vendor/autoload.php';

Запуск тестов через composer:

$ composer test

Заключение

Данной информации должно хватить для создания собственного плагина для Composer'а. Спасибо всем, кто дочитал до конца.

Автор: flancer

Источник

Поделиться

* - обязательные к заполнению поля