But now let us return to request processing: After the ServiceManager has been adequately prepared, it has also been used for the first time, to generate the ModuleManager via the registered factory before loading the module is initiated.
get('ModuleManager')->loadModules();
Generation of the ModuleManager
The ModuleManagerFactory serves the purpose of providing the ModuleManager service. As we
remember, a factory is always used when the generation of an object becomes more complex. In
the scope of this generation, initially a new EventManager is requested from the ServiceManager
and is placed at the disposal of the ModuleManager. The ModuleManager is therefore able to generate events and to inform registered “Listeners” beforehand. The following events are triggered by the ModuleManager (at a later point in time!):
loadModules: Is initiated when the modules are loaded.
loadModule.resolve: Is initiated for each module that is to be loaded when the necessary
data are read in.
loadModule: Is initiated during loading of a module for every module when the data that have
been read in are exported.
loadModules.post: Is initiated after all modules have been loaded.
Module-oriented listeners
However, the ModuleManagerFactory does much more. To begin with, it generates a large number
of listeners that are registered for the above-mentioned events.
ModuleAutoloader: Ensures that the Module class of the individual modules can be automatically loaded.
ModuleResolverListener: Instantiates the Module.php of the respective module.
AutoloaderListener: Invokes the getAutoloaderConfig() method in Modules, in order to
obtain information on how the modules’ classes can be automatically loaded.
OnBootstrapListener: Checks to determine whether Modules have an onBootstrap() method
and registers the invocation of this method for the bootstrap event that will be triggered at a later point in time by the Application.
InitTrigger: Checks to determine whether Modules have the init() method at their disposal.
If they do, it is invoked.
ConfigListener: Checks to determine whether Modules have agetConfig() method at their
disposal, which, if present, is invoked and the returned module configurations array is united
with the other configurations.
LocatorRegistrationListener: Insures that instances of all Module classes that implement
the ServiceLocatorRegisteredInterface are injected into the ServiceManager‘.
ServiceListener: Calls the getServiceConfig(), getControllerConfig(), getControllerPluginConfig(),getViewHelperConfig() methods in the Module class, if present (or reads out die the
corresponding configurations; further details on this in the following), processes the merged
configurations of all modules, applies them to the m ServiceManager and adds further
Standard-Services to the latter.
Standard services, Part 2
After a number of standard services have been made available in the course of the generation of the
ServiceManager—among them, in addition to the EventManager, even the ModuleManager itself—the ServiceListener additionally registers (at the request of its factory) a colourful assortment of
additional Services, which are required in the course of the request processing. At this point a brief
comment is appropriate: at this point in time the operational mode of each service can and should
not be completely understood! Many of the services that are registered by the ModuleManager at this time will cross our path again in the course of this chapter or book. The following list thus should serve much more as a reference and outlook to that which is still to come. The following services are thus—listed here according to manner of registration—registered.
Invocables
RouteListener (Zend\Mvc\RouteListener): Listens later to the Mvc result onRoute and then
ensures that the router is charged with the resolution on the appropriate controller.
DispatchListener (Zend\Mvc\DispatchListener): Listens later to the Mvc result onRoute
and then ensures that the ControllerLoader loads the previously selected controller and runs
it.
Factories
Application (Zend\Mvc\Service\ApplicationFactory): The Application (generated by the deposited factory) represents, so to speak, the entire processing chain and in general the entire application.
Configuration (Zend\Mvc\Service\ConfigFactory): The generated Config service returns the merged configuration for the application. It is also available via the Config alias.
ConsoleAdapter (Zend\Mvc\Service\ConsoleAdapterFactory): Service for accessing the command line.
DependencyInjector (Zend\Mvc\Service\DiFactory): Zend Framework has its own implementation of the so-called “dependency injection”, with whose help complex object graphs based on a comprehensive configuration are automatically “merged”. Instead of the
DependencyInjector keys, one can also use its aliases Di or Zend\Di\LocatorInterface. We will look at Zend\Di in more detail later.
Router, HttpRouter, ConsoleRouter (Zend\Mvc\Service\RouterFactory): Based on the request URL, the factory-generated Router service determines the controller that is to be invoked—if necessary, also in the “command line mode”.
Request (Zend\Mvc\PhpEnvironment\Request): Provides access to all request information, e.g. the request parameters.
Response (Zend\Http\PhpEnvironment\Response): Represents the answer generated in the course of processing to the client.
ViewManager: The ViewManager performs a function for the administration of views and their
processing that is similar to that performed by the ModuleManager for the modules and the
ServiceManager for the services. It ensures that the data will sometime become, for example,
web pages with HTML markup.
ViewJsonRenderer (Zend\Mvc\Service\ViewJsonRendererFactory): Allows the realisation
of RESTful3 controllers and thus of web services, which conforms to the REST architecture
style. This topic is discussed in a chapter of its own in the book.
ViewJsonStrategy (Zend\Mvc\Service\ViewJsonStrategyFactory): Ensures that the ViewJsonRenderer will be invoked when required. In the scope of this Strategy, for example, the system checks
to see whether the ViewModel returned by the controller is of the JsonModel type.
ViewFeedRenderer (Zend\Mvc\Service\ViewFeedRendererFactory): Allows the realisation
of RSS or Atom feeds of the “view data” returned by a controller.
ViewFeedStrategy (Zend\Mvc\Service\ViewJsonStrategyFactory): Ensures that the ViewFeedRenderer will be invoked when required. Part of this Strategy the determination of whether the
ViewModel returned by the controller is of the FeedModel type.
ViewResolver (Zend\Mvc\Service\ViewResolverFactory): Makes it possible to find “view
templates”.
ViewTemplateMapResolver (Zend\Mvc\Service\ViewResolverFactory): Makes it possible for
the ViewResolver to find View-Templates on the basis of a map.
And additionally:
ViewTemplatePathStack (Zend\Mvc\Service\ViewTemplatePathStackFactory): Makes it possible for the ViewResolver to find View-Templates on the basis of a list of paths.
ControllerLoader (Zend\Mvc\Service\ControllerLoaderFactory): TheControllerLoader
can load a controller that was previously localised by a routing.
ControllerPluginManager (Zend\Mvc\Service\ControllerPluginManagerFactory): Makes
the ControllerPluginManager and, thus, a number of plugins, which can be used in controllers, are available; among them, for example, the redirect plugin by means of which forwarding can be realised. This service can also be requested via the ControllerPluginBroker keys, Zend\Mvc\Controller\PluginBroker or Zend\Mvc\Controller\PluginManager.
ViewHelperManager (Zend\Mvc\Service\ViewHelperManagerFactory): Generates the ViewHelperManager, which is responsible for the administration of so-called “view helpers”.
The latter three services are particularly interesting, because they, in turn, comprise the new
“ServiceManager”, termed “Scoped ServiceManager” in ZF jargon. Whew, now things are beginning to get a bit complicated! So let’s take a slow look at things—step by step. To begin with we
should remember that there is the one “central ServiceManager” in the system. All of the important
“application services” are generated by using it. It is both a ServiceManager in a technical sense
and the conceptional “central ServiceManager” for us. However, there are specific services that
the ServiceManager itself does not provide, but instead are made available by specialised “subServiceManagers” or “scoped ServiceManagers”, respectively, which can also provide services via
the known mechanisms, i.e. “invocables”, “factories”, etc. All of them are also ServiceManagers in
a technical sense. In this context, let’s again take a look at the last chapter, in which we wrote our own controller. There we find the following passage in the module.config.php:
array( 'invokables' => array( 'Helloworld\Controller\Index' => 'Helloworld\Controller\IndexController' ))// [..]
When this configuration fragment is interpreted, this results in reference to the appropriate
controller class under the Helloworld\Controller\Index key, which is registered as an “invocable”
in the ControllerLoader, one of the standard “scoped ServiceManagers”. Thus, if this controller
is subsequently identified as appropriate in the scope of routing and must then be instantiated, the
system uses the ControllerLoader to do this. In this context, one can then also characterise a
controller as a service.
This procedure of the specialised Sub-ServiceManager has several advantages for certain types of
services. For example, in this manner the central ServiceManager for the application services is
itself not overloaded with innumerable services, and it is easy to determine all of the controllers, a
task that would otherwise not be nearly as easy. Here are the different ServiceManagers again at a
glance:
Application Services (Zend\ServiceManager\ServiceManager): Configuration via the service_-manager key or the getServiceConfig() method (defined in the ServiceProviderInterface).
Controllers (Zend\Mvc\Controller\ControllerManager): Configuration via controllers key
or getControllerConfig() method (defined in ControllerProviderInterface). It can be obtained in the “central ServiceManager” via the ControllerLoader service designation.
Controller plugins (Zend\Mvc\Controller\PluginManager): Configuration via the controller_-plugins key or getControllerPluginConfig() method (defined in ControllerPluginProviderInterface).
It can be obtained in the “central ServiceManager” via the ControllerPlugin manager service designation.
“View helpers” (Zend\View\HelperPluginManager): configuration via the view_helpers key
or the getViewHelperConfig() method. (defined in the ViewHelperProviderInterface).
It can be obtained in the “central ServiceManager” via the ViewHelperManager service
designation.
Loading the modules
After the ModuleManager has been prepared and the required listeners have been registered, the
actual loading of the modules is initiated by invocation of the loadModules() method of the
ModuleManager. At this time, relatively little really happens here because the actual processing, for example the invocation of the above-mentioned methods of the Module.php, indeed
occurs in the many registered listeners. Initially, the loadmodules.pre event is triggered, and
then the loadModule.resolve event and loadModule, for every activated module. Finally, the
loadModules.post event is again triggered. And that was really everything.
The Module Event Object
The concept of the EventManager is that in addition to being the trigger for an event and the listeners registered for the event (receivers), the event itself—represented as independent object—still exists. It is made available to all listeners. This object serves to transfer additional event-relevant information, for example a reference to the location in the code where the event is triggered. Moreover, additional data, which are helpful for the event processing in the listeners, can be transferred. Thus, the module which is now being loaded is generally of interest for a listener during loadModule.
To do justice to the fact that, depending on the context of the event, other data are of interest, the
EventManager of Zend Framework 2 permits deposition of situation-dependent special event classes. For the event principle in the scope of the ModulManager, there is as special ModuleEvent class, which for example bears both the module in question and additionally the name of the module.
Activation of a module
In order for a module to be taken into account at all, an explicit activation in application.config.php
in the config directory is required:
array( 'Application', 'Helloworld' ));
Methods of the module class
As we have seen, a large number of methods in the Module class of a module are invoked if we have implemented them. In Framework there are two relevant possibilities of finding out whether this
is the case. Either the Module class implements a specific interface (this can indeed be tested via
instance of) or the respective method is simply implemented (this can be checked via
the method_exists()‘ invocation).
Let’s now again take a detailed look at the methods in the Module class, which are automatically
invoked by Framework and can be used by application developers:
getAutoloadingConfig() (defined in AutoloaderProviderInterface): We have already
created this method in our Helloworld module. It provides information on how the classes of
the module can be automatically loaded. If we omit this method, the classes of the module
(for example its controller) normally cannot be loaded and serious problems occur when the
corresponding URL is invoked. Consequently, it should always be ensured that information
on how the classes can be automatically loaded has been made available to Framework.
Incidentally, in a purely technical context, Framework takes the information to incorporate
an appropriate loader implementation for this module via spl_autoload_register().
init() (defined in InitProviderInterface): This method allows the application developer
to initialise his or her own module, thus, for example, to register his or her own listeners
for certain events. If necessary, the ModuleManager is consigned to the method and the latter
can thus access the appropriate events (of the ModuleManager) or access the modules. The
important thing is that this “method” is always invoked, that means for every request—and
indeed for every module. One should also realize that this is a good place to ruin the loading
time of an application. Thus, only very few and ideally only light-weight operations should
be performed in the scope of the init() method. If one is attempting to improve the speed of
a ZF2 application, one should always first take a look at the init() methods of the activated
modules.