Pull to refresh

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

Reading time 4 min
Views 11K
При развертывании 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'а этот класс должен имплементировать интерфейс Composer\Plugin\PluginInterface.

namespace Praxigento\Composer\Plugin\Templates;

use Composer\Composer;
use Composer\IO\IOInterface;
use Composer\Plugin\PluginInterface;

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'а. Спасибо всем, кто дочитал до конца.
Tags:
Hubs:
+13
Comments 0
Comments Leave a comment

Articles