# zend-component-installer

Composer plugin for injecting modules and configuration providers into application configuration.

    $ composer require --dev zendframework/zend-component-installer

## Installable Packages

How do you define a package for which zend-component-installer will install configuration?

### Components

Components are Zend Framework modules that deliver low-level functionality; examples include the various Zend Framework components themselves. These require the following:

- A `Module` class in the package namespace.
- An `extra.zf.component` entry listing the package namespace in your `composer.json`.

    "extra": {
      "zf": {
        "component": "Some\\Component"
      }
    }

You may also specify multiple components as an array:

    "extra": {
      "zf": {
        "component": [
          "Some\\Component",
          "Other\\Component"
        ]
      }
    }

Your application will need to have one or more of the following configuration files, from which you will be prompted to choose which one in which to inject the component:

- `config/application.config.php` (vanilla ZF2 application)
- `config/modules.config.php` (Apigility application)
- `config/development.config.php.dist` and `config/development.config.php` (applications using zend-development-mode)

Components are added at the top of the application's list of modules.

### Modules

Zend Framework modules typically deliver functionality around the zend-mvc workflow, including MVC event listeners, controllers, etc. To enable the installer workflow, they require the following:

- A `Module` class in the package namespace.
- An `extra.zf.module` entry listing the package namespace in your `composer.json`.

    "extra": {
      "zf": {
        "module": "Some\\Component"
      }
    }

You may also specify multiple modules as an array:

    "extra": {
      "zf": {
        "module": [
          "Some\\Component",
          "Other\\Component"
        ]
      }
    }

Your application will need to have one or more of the following configuration files, from which you will be prompted to choose which one in which to inject the module:

- `config/application.config.php` (vanilla ZF2 application)
- `config/modules.config.php` (Apigility application)
- `config/development.config.php.dist` and `config/development.config.php` (applications using zend-development-mode)

Modules are added at the bottom of the application's list of modules.

### Config Providers

Configuration providers work with expressive-config-manager, which provides generic functionality for aggregating and merging application configuration. Packages that provide configuration will provide an invokable class that returns configuration for the package. To enable the installer workflow, you will need:

- A configuration provider class. This is a class with no constructor arguments defining an `__invoke()` method returning a configuration array.
- An `extra.zf.config-provider` entry listing the configuration provider class in your `composer.json`.

    namespace Some\Component;

    class ConfigProvider
    {
        public function __invoke()
        {
            return [ /* ... */ ];
        }
    }

    "extra": {
      "zf": {
        "config-provider": "Some\\Component\\ConfigProvider"
      }
    }

You may also specify multiple configuration providers as an array:

    "extra": {
      "zf": {
        "config-provider": [
          "Some\\Component\\ConfigProvider",
          "Some\\Component\\PluginConfigProvider",
        ]
      }
    }

Your application will need to define a `config/config.php` file, and that file will need to have a line that instantiates a `Zend\Expressive\ConfigManager\ConfigManager` instance.

Configuration providers are added at the top of the `ConfigManager` provider array.

## Global Installation

You can also install the plugin globally, in which case it will be active for every project you manage on your machine.

    $ composer global require zendframework/zend-component-installer

## Why?

We're in the process of reducing the required components for zend-mvc and the Zend Framework repository. In the current v2 series, zend-mvc provides copious amounts of integrations with other components; as such, we need to move the various factories, plugin managers, and event listeners into the individual components themselves. Doing so, however, has a side effect: they will no longer be wired automatically.

To provide service and event wiring, we will be adding `Module` classes (and configuration providers) to all Zend Framework components. This exposes a new problem, however: how do we ensure that those components are then added to the application module list as you add them to your application?

This package provides the answer to that problem. As soon as you add this package to your application, whenever you add a component or module that exposes itself as such, the plugin will prompt you, asking where you want to inject it.

## When are multiple items required?

As noted under each of the component, module, and config-provider sections, you can optionally specify an array of items. When would you do this?

The primary reason is for metapackages. Composer does not trigger either `post-package-install` or `post-package-uninstall` events for packages defined as metapackage requirements. As such, you would define the metadata for such packages in the metapackage as well, to ensure that the component installer can update the configuration accordingly.

The other use case is to allow specifying multiple configuration providers from the same package. As an example, you might define default configuration, plus configuration for plugins; specifying these as separate configuration providers allows the consumer to choose if they want both enabled in their application.

## Removing individual packages

When removing individual packages that were originally installed via a metapackage, the component installer will not trigger. As such, you will need to manually remove such packages from your configuration.

Additionally, a later update may actually re-install the package, as it's a requirement of the metapackage. As such, it's typically safer to:

- Remove the metapackage
- Individually install the packages from the metapackage that you wish to keep.