Reference

The Module Manager

The module manager, Laminas\ModuleManager\ModuleManager, is responsible for iterating over an array of module names and triggering a sequence of events for each. Instantiation of module classes, initialization tasks, and configuration are all performed by attached event listeners.

Module Manager Events

The Module Manager events are defined in Laminas\ModuleManager\ModuleEvent.

loadModules (ModuleEvent::EVENT_LOAD_MODULES)

This event is primarily used internally to help encapsulate the work of loading modules in event listeners, and allows the loadModules.post event to be more user-friendly. Internal listeners will attach to this event with a negative priority instead of loadModules.post so that users can safely assume things like config merging have been done once loadModules.post is triggered, without having to worry about priorities.

loadModule.resolve (ModuleEvent::EVENT_LOAD_MODULE_RESOLVE)

Triggered for each module that is to be loaded. The listener(s) to this event are responsible for taking a module name and resolving it to an instance of some class. The default module resolver looks for the class {modulename}\Module, instantiating and returning it if it exists.

The name of the module may be retrieved by listeners using the getModuleName() method of the Event object; a listener should then take that name and resolve it to an object instance representing the given module. Multiple listeners can be attached to this event, and the module manager will trigger them in order of their priority until one returns an object. This allows you to attach additional listeners which have alternative methods of resolving modules from a given module name.

loadModule (ModuleEvent::EVENT_LOAD_MODULE)

Once a module resolver listener has resolved the module name to an object, the module manager then triggers this event, passing the newly created object to all listeners.

mergeConfig (ModuleEvent::EVENT_MERGE_CONFIG)

After all modules have been loaded, the mergeConfig event is triggered. By default, Laminas\ModuleManager\Listener\ConfigLister listens on this event at priority 1000, and merges all configuration. You may attach additional listeners to this event in order to manipulate the merged configuration. See the tutorial on manipulating merged configuration for more information.

loadModules.post (ModuleEvent::EVENT_LOAD_MODULES_POST)

This event is triggered by the module manager to allow any listeners to perform work after every module has finished loading. For example, the default configuration listener, Laminas\ModuleManager\Listener\ConfigListener (covered later), attaches to this event to merge additional user-supplied configuration which is meant to override the default supplied configurations of installed modules.

Module Manager Listeners

By default, Laminas provides several useful module manager listeners. All shipped listeners are in the Laminas\ModuleManager\Listener namespace.

DefaultListenerAggregate

To address the most common use case of the module manager, Laminas provides this default aggregate listener. In most cases, this will be the only listener you will need to attach to use the module manager, as it will take care of properly attaching the requisite listeners (those listed below) for the module system to function properly.

AutoloaderListener

This listener checks each module to see if it has implemented Laminas\ModuleManager\Feature\AutoloaderProviderInterface or defined the getAutoloaderConfig() method. If so, it calls the getAutoloaderConfig() method on the module class and passes the returned array to Laminas\Loader\AutoloaderFactory.

ModuleDependencyCheckerListener

This listener checks each module to verify if all the modules it depends on were loaded. When a module class implements Laminas\ModuleManager\Feature\DependencyIndicatorInterface or has defined the getModuleDependencies() method, the listener will call getModuleDependencies(). Each of the values returned by the method is checked against the loaded modules list: if one of the values is not in that list, a Laminas\ModuleManager\Exception\MissingDependencyModuleException is thrown.

ConfigListener

If a module class has a getConfig() method, or implements Laminas\ModuleManager\Feature\ConfigProviderInterface, this listener will call it and merge the returned array (or Traversable object) into the main application configuration.

InitTrigger

If a module class either implements Laminas\ModuleManager\Feature\InitProviderInterface, or defines an init() method, this listener will call init() and pass the current instance of Laminas\ModuleManager\ModuleManager as the sole parameter.

Like the OnBootstrapListener, the init() method is called for every module implementing this feature, on every page request and should only be used for performing lightweight tasks such as registering event listeners.

LocatorRegistrationListener

If a module class implements Laminas\ModuleManager\Feature\LocatorRegisteredInterface, this listener will inject the module class instance into the ServiceManager using the module class name as the service name. This allows you to later retrieve the module class from the ServiceManager.

ModuleResolverListener

This is the default module resolver. It attaches to the loadModule.resolve event and returns an instance of {moduleName}\Module.

Since 2.8.0, if the module name provided resolves to a fully qualified class name, it returns that verbatim.

OnBootstrapListener

If a module class implements Laminas\ModuleManager\Feature\BootstrapListenerInterface, or defines an onBootstrap() method, this listener will register the onBootstrap() method with the Laminas\Mvc\Application bootstrap event. This method will then be triggered during the bootstrap event (and passed an MvcEvent instance).

Like the InitTrigger, the onBootstrap() method is called for every module implementing this feature, on every page request, and should only be used for performing lightweight tasks such as registering event listeners.

ServiceListener

If a module class implements Laminas\ModuleManager\Feature\ServiceProviderInterface, or defines an getServiceConfig() method, this listener will call that method and aggregate the return values for use in configuring the ServiceManager.

The getServiceConfig() method may return either an array of configuration compatible with Laminas\ServiceManager\Config, an instance of that class, or the string name of a class that extends it. Values are merged and aggregated on completion, and then merged with any configuration from the ConfigListener falling under the service_manager key. For more information, see the ServiceManager documentation.

Unlike the other listeners, this listener is not managed by the DefaultListenerAggregate; instead, it is created and instantiated within the Laminas\Mvc\Service\ModuleManagerFactory, where it is injected with the current ServiceManager instance before being registered with the ModuleManager events.

Additionally, this listener manages a variety of plugin managers, including view helpers, controllers, and controller plugins. In each case, you may either specify configuration to define plugins, or provide configuration via a Module class. Configuration follows the same format as for the ServiceManager. The following table outlines the plugin managers that may be configured this way (including the ServiceManager), the configuration key to use, the ModuleManager feature interface to optionally implement (all interfaces specified live in the Laminas\ModuleManager\Feature namespace) , and the module method to optionally define to provide configuration.

Plugin Manager Config Key Interface Module Method
Laminas\Mvc\Controller\ControllerManager controllers ControllerProviderInterface getControllerConfig
Laminas\Mvc\Controller\PluginManager controller_plugins ControllerPluginProviderInterface getControllerPluginConfig
Laminas\Filter\FilterPluginManager filters FilterProviderInterface getFilterConfig
Laminas\Form\FormElementManager form_elements FormElementProviderInterface getFormElementConfig
Laminas\Stdlib\Hydrator\HydratorPluginManager hydrators HydratorProviderInterface getHydratorConfig
Laminas\InputFilter\InputFilterPluginManager input_filters InputFilterProviderInterface getInputFilterConfig
Laminas\Mvc\Router\RoutePluginManager route_manager RouteProviderInterface getRouteConfig
Laminas\Serializer\AdapterPluginManager serializers SerializerProviderInterface getSerializerConfig
Laminas\ServiceManager\ServiceManager service_manager ServiceProviderInterface getServiceConfig
Laminas\Validator\ValidatorPluginManager validators ValidatorProviderInterface getValidatorConfig
Laminas\View\HelperPluginManager view_helpers ViewHelperProviderInterface getViewHelperConfig
Laminas\Log\ProcessorPluginManager log_processors LogProcessorProviderInterface getLogProcessorConfig
Laminas\Log\WriterPluginManager log_writers LogWriterProviderInterface getLogWriterConfig

Configuration follows the examples in the ServiceManager configuration section. As a brief recap, the following configuration keys and values are allowed:

Config Key Allowed values
services service name/instance pairs (these should likely be defined only in Module classes
invokables service name/class name pairs of classes that may be invoked without constructor arguments (deprecated with laminas-servicemanager v3; use the InvokableFactory instead)
factories service names pointing to factories. Factories may be any PHP callable, or a string class name of a class implementing Laminas\ServiceManager\FactoryInterface, or of a class implementing the __invoke method (if a callable is used, it should be defined only in Module classes)
abstract_factories array of either concrete instances of Laminas\ServiceManager\AbstractFactoryInterface, or string class names of classes implementing that interface (if an instance is used, it should be defined only in Module classes)
initializers array of PHP callables or string class names of classes implementing Laminas\ServiceManager\InitializerInterface (if a callable is used, it should be defined only in Module classes)

When working with plugin managers, you will be passed the plugin manager instance to factories, abstract factories, and initializers. If you need access to the application services, you can use the getServiceLocator() method, as in the following example:

public function getViewHelperConfig()
{
    return ['factories' => [
        'foo' => function ($helpers) {
            $container   = $helpers->getServiceLocator();
            $someService = $container->get('SomeService');
            $helper      = new Helper\Foo($someService);

            return $helper;
        },
    ]];
}

This is a powerful technique, as it allows your various plugins to remain agnostic with regards to where and how dependencies are injected, and thus allows you to use Inversion of Control principals even with plugins.

Factories with laminas-servicemanager v3

Starting in the v3 releases of laminas-servicemanager, factories invoked by plugin managers now receive the parent container, and not the plugin manager itself. You can write your factories under v2, and prepare them for v3, by testing the incoming argument to see if it is a plugin manager:

use Laminas\ServiceManager\AbstractPluginManager;

function ($container) {
    $container = $container instanceof AbstractPluginManager
        ? $container->getServiceLocator()
        : $container;

    // create instance with dependencies pulled from app container...
}