2013-09-05 18:08:17 +00:00
<!--
tagline: Modify and extend Composer's functionality
-->
# Setting up and using plugins
## Synopsis
You may wish to alter or expand Composer's functionality with your own. For
example if your environment poses special requirements on the behaviour of
Composer which do not apply to the majority of its users or if you wish to
accomplish something with composer in a way that is not desired by most users.
In these cases you could consider creating a plugin to handle your
specific logic.
## Creating a Plugin
2015-06-02 18:09:57 +00:00
A plugin is a regular Composer package which ships its code as part of the
2013-09-05 18:08:17 +00:00
package and may also depend on further packages.
### Plugin Package
The package file is the same as any other package file but with the following
requirements:
2015-06-02 18:09:57 +00:00
1. The [type][1] attribute must be `composer-plugin` .
2. The [extra][2] attribute must contain an element `class` defining the
2013-09-05 18:08:17 +00:00
class name of the plugin (including namespace). If a package contains
2015-06-02 18:09:57 +00:00
multiple plugins, this can be array of class names.
3. You must require the special package called `composer-plugin-api`
to define which Plugin API versions your plugin is compatible with.
2013-09-05 18:08:17 +00:00
2015-06-02 18:09:57 +00:00
The required version of the `composer-plugin-api` follows the same [rules][7]
2015-06-08 21:45:20 +00:00
as a normal package's.
2013-09-05 18:08:17 +00:00
2015-06-02 18:09:57 +00:00
The current composer plugin API version is 1.0.0.
An example of a valid plugin `composer.json` file (with the autoloading
part omitted):
2013-09-05 18:08:17 +00:00
2014-05-19 10:17:07 +00:00
```json
{
"name": "my/plugin-package",
"type": "composer-plugin",
"require": {
2015-06-11 14:02:59 +00:00
"composer-plugin-api": "^1.0"
2015-06-02 18:09:57 +00:00
},
"extra": {
"class": "My\\Plugin"
2013-09-05 18:08:17 +00:00
}
2014-05-19 10:17:07 +00:00
}
```
2013-09-05 18:08:17 +00:00
### Plugin Class
Every plugin has to supply a class which implements the
[`Composer\Plugin\PluginInterface`][3]. The `activate()` method of the plugin
is called after the plugin is loaded and receives an instance of
[`Composer\Composer`][4] as well as an instance of
[`Composer\IO\IOInterface`][5]. Using these two objects all configuration can
be read and all internal objects and state can be manipulated as desired.
Example:
2014-05-19 10:17:07 +00:00
```php
< ?php
2013-09-05 18:08:17 +00:00
2014-05-19 10:17:07 +00:00
namespace phpDocumentor\Composer;
2013-09-05 18:08:17 +00:00
2014-05-19 10:17:07 +00:00
use Composer\Composer;
use Composer\IO\IOInterface;
use Composer\Plugin\PluginInterface;
class TemplateInstallerPlugin implements PluginInterface
{
public function activate(Composer $composer, IOInterface $io)
2013-09-05 18:08:17 +00:00
{
2014-05-19 10:17:07 +00:00
$installer = new TemplateInstaller($io, $composer);
$composer->getInstallationManager()->addInstaller($installer);
2013-09-05 18:08:17 +00:00
}
2014-05-19 10:17:07 +00:00
}
```
2013-09-05 18:08:17 +00:00
## Event Handler
Furthermore plugins may implement the
[`Composer\EventDispatcher\EventSubscriberInterface`][6] in order to have its
event handlers automatically registered with the `EventDispatcher` when the
plugin is loaded.
2016-01-26 11:38:12 +00:00
To register a method to an event, implement the method `getSubscribedEvents()` and have it return an array. The array key must be the event name ([listed here](https://getcomposer.org/doc/articles/scripts.md#event-names)) and the value is the name of the method in this class to be called.
2013-11-27 11:55:12 +00:00
2016-01-26 11:38:12 +00:00
```php
public static function getSubscribedEvents()
{
return array(
'post-autoload-dump' => 'methodToBeCalled',
// ^ event name ^ ^ method name ^
);
}
```
By default, the priority of an event handler is set to 0. The priorty can be changed by attaching a tuple where the first value is the method name, as before, and the second value is an integer representing the priority. Higher integers represent higher priorityes therefore, priortity 2 is called before priority 1, etc.
```php
public static function getSubscribedEvents()
{
return array(
// Will be called before events with priority 0
'post-autoload-dump' => array('methodToBeCalled', 1)
);
}
```
If multiple methods should be called, then an array of tupples can be attached to each event. The tupples do not need to include the priority. If it is omitted, it will default to 0.
```php
public static function getSubscribedEvents()
{
2016-01-26 11:47:36 +00:00
return array(
2016-01-26 11:38:12 +00:00
'post-autoload-dump' => array(
array('methodToBeCalled' ), // Priority defaults to 0
array('someOtherMethodName', 1), // This fires first
)
2016-01-26 11:47:36 +00:00
);
2016-01-26 11:38:12 +00:00
}
```
Here's a complete example:
2013-09-05 18:08:17 +00:00
2014-05-19 10:17:07 +00:00
```php
< ?php
2013-09-05 18:08:17 +00:00
2014-05-19 10:17:07 +00:00
namespace Naderman\Composer\AWS;
2013-09-05 18:08:17 +00:00
2014-05-19 10:17:07 +00:00
use Composer\Composer;
use Composer\EventDispatcher\EventSubscriberInterface;
use Composer\IO\IOInterface;
use Composer\Plugin\PluginInterface;
use Composer\Plugin\PluginEvents;
use Composer\Plugin\PreFileDownloadEvent;
2013-09-05 18:08:17 +00:00
2014-05-19 10:17:07 +00:00
class AwsPlugin implements PluginInterface, EventSubscriberInterface
{
protected $composer;
protected $io;
2013-09-05 18:08:17 +00:00
2014-05-19 10:17:07 +00:00
public function activate(Composer $composer, IOInterface $io)
{
$this->composer = $composer;
$this->io = $io;
}
public static function getSubscribedEvents()
{
return array(
PluginEvents::PRE_FILE_DOWNLOAD => array(
array('onPreFileDownload', 0)
),
);
}
2013-09-05 18:08:17 +00:00
2014-05-19 10:17:07 +00:00
public function onPreFileDownload(PreFileDownloadEvent $event)
{
$protocol = parse_url($event->getProcessedUrl(), PHP_URL_SCHEME);
2013-09-05 18:08:17 +00:00
2014-05-19 10:17:07 +00:00
if ($protocol === 's3') {
$awsClient = new AwsClient($this->io, $this->composer->getConfig());
$s3RemoteFilesystem = new S3RemoteFilesystem($this->io, $event->getRemoteFilesystem()->getOptions(), $awsClient);
$event->setRemoteFilesystem($s3RemoteFilesystem);
2013-09-05 18:08:17 +00:00
}
}
2014-05-19 10:17:07 +00:00
}
```
2013-09-05 18:08:17 +00:00
## Using Plugins
Plugin packages are automatically loaded as soon as they are installed and will
be loaded when composer starts up if they are found in the current project's
list of installed packages. Additionally all plugin packages installed in the
`COMPOSER_HOME` directory using the composer global command are loaded before
local project plugins are loaded.
> You may pass the `--no-plugins` option to composer commands to disable all
2015-03-04 23:50:10 +00:00
> installed plugins. This may be particularly helpful if any of the plugins
2013-09-05 18:08:17 +00:00
> causes errors and you wish to update or uninstall it.
[1]: ../04-schema.md#type
[2]: ../04-schema.md#extra
[3]: https://github.com/composer/composer/blob/master/src/Composer/Plugin/PluginInterface.php
[4]: https://github.com/composer/composer/blob/master/src/Composer/Composer.php
[5]: https://github.com/composer/composer/blob/master/src/Composer/IO/IOInterface.php
[6]: https://github.com/composer/composer/blob/master/src/Composer/EventDispatcher/EventSubscriberInterface.php
2015-06-02 18:09:57 +00:00
[7]: ../01-basic-usage.md#package-versions