It's been a while since i have written any article, especially one not related to a book or review,anyway over the years Zend Framework 2 has seen numerous iterations and releases and also constant updates to the Zend Framework 2 Skeleton tutorial. A lot of authors of have done a tremendous job in writing articles for new comers to the framework, however looking at various websites and their comments i noticed a common trend, most after learning the Skeleton tutorial are often confused about what next or how to proceed from there or when is it the best time to use a certain module, event-manager. This tutorial is not creating a Zf2 application, this will simply explain the Zf2 process and what really goes on to give a better understanding of the framework, however it should be noted that there might be some concept which i either explained inaccurately or not well enough, should such occur please feel free to inform me.

zf2 flowchart

Luckily thanks to Michael Romer, this graphical representation of the ZF2 process architecture actually made writing this article alot easier, as the user can simply see the detailed process and understand what really happens under the hood.

Requests

Zend Framework 2 Cheat Sheet-Start
Now if you really followed the Zend framework 2 Skeleton tutorial, you will notice the stage where you are instructed to set up a virtual host and the htaccess settings. This ensures that all requests from the browser are being sent to the index.php, which is responsible for dispatching each request.

Setup autoloading require 'init_autoloader.php';

// Run the application!

Zend\Mvc\Application::init(require 'config/application.config.php')->run();

Setting up Configuration for the Application

The StandardAutoLoader is being used to ensure that namespaces has a 1 to 1 map with the files, following the PSR-0 Specification, the Zend Frameworks also allows you to specify other loaders such as Composer e.t.c the important line to notice is the require code, this simply loads an array of configuration into the Application class to run it, the following is an example of my application config.


return array(
'modules' => array(
'Application',
'Album',
'Zeffy'
),
'module_listener_options' => array(
'module_paths' => array(
'./module',
'./vendor'
),
'config_glob_paths' => array('config/autoload/{,*.}{global,local}.php')
)
);

This array simply holds numerous and usually nested array of configs, the array key 'modules' informs the Zend/Mvc/Application the modules to run/invoke, this is an interesting aspect as it shows how you can easily plug 3rd Party codes into the Zf2, an example is the famous zend-developer-tool. The key 'module_listener_options" simply contain parameters that will be used when searching for modules, the "module_paths" tells the ModuleManager where to search for modules and the 'config_glob_paths' will scan for paths with the pattern (e.g application.local.php,modulename.global.php) and merge the configuration when the modules have been loaded, it also involves overriding, with the aid of the zend-developer-tool you can easily inspect the application config.


public static function init($configuration = array())
{
$smConfig = isset($configuration['service_manager']) ? $configuration['service_manager'] : array();
$listeners = isset($configuration['listeners']) ? $configuration['listeners'] : array();
$serviceManager = new ServiceManager(new Service\ServiceManagerConfig($smConfig));
$serviceManager->setService('ApplicationConfig', $configuration);
$serviceManager->get('ModuleManager')->loadModules();
return $serviceManager->get('Application')->bootstrap($listeners);
}

In this method the application config is passed as a parameter,the 'service_manager' and 'listeners' key will not be defined at this point so the $smConfig and $listeners will be assigned an empty array. The service manager is later called using the ServiceManagerConfig as the parameter, the ServiceManagerConfig's role is to sniff out the services from the array that have the following key word 'factories','invokables','shared','abstract_factories' ,'alias', and simply merges the arrays and sets them to the respective service. The ServiceManager through the use Dependency Injection calls the ServiceManagerConfig->configureServiceManager() taking the ServiceManager as the parameter,
Note: it's quite evidential, that the ZF2 employs a number of advanced patterns, therefore its important to update your knowledge on them.
The configureServiceManager will initialize and set up the ServiceManager; which was passed from the parameter in the method 'configureServiceManager ' to set itself up as a service in itself.


$serviceManager->setService('ServiceManager', $serviceManager);

Credit goes to Memegenerator.net

At this point, the $serviceManager will configure both the EventManager and ModuleManager in itself, once this has been done, the ServiceManager then creates a service called "ApplicationConfig" which will contain the application cofiguration (an array), this is still the same array except that the array might have been modified, this stores it as a Service, the importance of this is that you can easily retrieve it using the ServiceManager/ServiceLocator later on in the application lifecycle.
Now you might wonder "What sorcery is this ?, where did ModuleManager,EventManager come from"..... good question.
in the ServiceManagerConfig class, the property factories define 2 entries


protected $factories = array(
'EventManager' => 'Zend\Mvc\Service\EventManagerFactory',
'ModuleManager' => 'Zend\Mvc\Service\ModuleManagerFactory',
);

Remember our ServiceManagerConfig method 'configureServiceManager' here is the code


public function configureServiceManager(ServiceManager $serviceManager)
{
foreach ($this->invokables as $name => $class) {
$serviceManager->setInvokableClass($name, $class);
}
//ModuleManager and EventManager are added as factories in the code here
foreach ($this->factories as $name => $factoryClass) {
$serviceManager->setFactory($name, $factoryClass);
}
foreach ($this->abstractFactories as $factoryClass) {
$serviceManager->addAbstractFactory($factoryClass);
}
foreach ($this->aliases as $name => $service) {
$serviceManager->setAlias($name, $service);
}
foreach ($this->shared as $name => $value) {
$serviceManager->setShared($name, $value);
}
$serviceManager->addInitializer(function ($instance) use ($serviceManager) {
if ($instance instanceof EventManagerAwareInterface) {
if ($instance->getEventManager() instanceof EventManagerInterface) {
$instance->getEventManager()->setSharedManager(
$serviceManager->get('SharedEventManager')
);
} else {
$instance->setEventManager($serviceManager->get('EventManager'));
}
}
});

a Factory is actually a Design pattern that hides the complexity of instantiating a class, it creates a simple interface for you to create classes. an important tip to note about 'Factories' in Zend Framework 2, factories implements the 'FactoryInterface' and defines the method 'createService' which will be called, the only exception to this rule; is if you pass a Callback function to the factory key. Okay one small gotcha 'abstract_factories' are a bit similar except it takes the name of the factory as a value e.g (array('SomethingFactory','NothingFactory'), where as factories stores the name using a key. e.g array('remi'=>'AwesomenessFactory','GEJ'=>'DeadPresidentFactory')

[code lang="php" title="Zend/Mvc/Service/ModuleManagerFactory"]
public function createService(ServiceLocatorInterface $serviceLocator)
{
if (!$serviceLocator->has('ServiceListener')) {
$serviceLocator->setFactory('ServiceListener', 'Zend\Mvc\Service\ServiceListenerFactory');
}
$configuration = $serviceLocator->get('ApplicationConfig');
$listenerOptions = new ListenerOptions($configuration['module_listener_options']);
$defaultListeners = new DefaultListenerAggregate($listenerOptions);
$serviceListener = $serviceLocator->get('ServiceListener');
$serviceListener->addServiceManager(
$serviceLocator,
'service_manager',
'Zend\ModuleManager\Feature\ServiceProviderInterface',
'getServiceConfig'
);
$serviceListener->addServiceManager(
'ControllerLoader',
'controllers',
'Zend\ModuleManager\Feature\ControllerProviderInterface',
'getControllerConfig'
);
$serviceListener->addServiceManager(
'ControllerPluginManager',
'controller_plugins',
'Zend\ModuleManager\Feature\ControllerPluginProviderInterface',
'getControllerPluginConfig'
);
$serviceListener->addServiceManager(
'ViewHelperManager',
'view_helpers',
'Zend\ModuleManager\Feature\ViewHelperProviderInterface',
'getViewHelperConfig'
);
$serviceListener->addServiceManager(
'ValidatorManager',
'validators',
'Zend\ModuleManager\Feature\ValidatorProviderInterface',
'getValidatorConfig'
);
$serviceListener->addServiceManager(
'FilterManager',
'filters',
'Zend\ModuleManager\Feature\FilterProviderInterface',
'getFilterConfig'
);
$serviceListener->addServiceManager(
'FormElementManager',
'form_elements',
'Zend\ModuleManager\Feature\FormElementProviderInterface',
'getFormElementConfig'
);
$serviceListener->addServiceManager(
'RoutePluginManager',
'route_manager',
'Zend\ModuleManager\Feature\RouteProviderInterface',
'getRouteConfig'
);
$serviceListener->addServiceManager(
'SerializerAdapterManager',
'serializers',
'Zend\ModuleManager\Feature\SerializerProviderInterface',
'getSerializerConfig'
);
$serviceListener->addServiceManager(
'HydratorManager',
'hydrators',
'Zend\ModuleManager\Feature\HydratorProviderInterface',
'getHydratorConfig'
);
$serviceListener->addServiceManager(
'InputFilterManager',
'input_filters',
'Zend\ModuleManager\Feature\InputFilterProviderInterface',
'getInputFilterConfig'
);
$events = $serviceLocator->get('EventManager');
$events->attach($defaultListeners);
$events->attach($serviceListener);
$moduleEvent = new ModuleEvent;
$moduleEvent->setParam('ServiceManager', $serviceLocator);
$moduleManager = new ModuleManager($configuration['modules'], $events);
$moduleManager->setEvent($moduleEvent);
return $moduleManager;
}

}
[/code]

Okay moving forward the "createService" gets invoked and this is a summary of what simply happens, but before we do that you might need to take a deep breath because a lot goes on this method, we will dive way deeper into the Matrix code. The ListenerOptions simply gets the following keys ('module_listener_options') from the 'ApplicationConfig' (array of our configuration now in the ServiceManager). The ListenerOptions extends the AbstractOptions so the array becomes accessible like a property. e.g $listenerOptions->modulePaths, the DefaultListenerAggregate setups up the common listeners to the ModuleManager; to get more insights look at this official Zend Framework 2 documenation. More Info.
The EventManager gets pulled from the ServiceManager which also contains a SharedEventManager which the eventManager will look for the events in it, the principle is that Objects have their own EventManagers, the SharedEventManager simply holds other events that are owned by other object . This is might be a bit complex to understand at once, but here is an article that does a better job at explaining it. SharedEventManagers/EventManagers
The EventManager attaches the DefaultListener and ServiceListener, this listeners will respond to several events during the life cycle of the application.

[code lang="php" title="DefaultListener"]
public function attach(EventManagerInterface $events)
{
$options = $this->getOptions();
$configListener = $this->getConfigListener();
$locatorRegistrationListener = new LocatorRegistrationListener($options);
// High priority, we assume module autoloading (for FooNamespace\Module classes) should be available before anything else
$this->listeners[] = $events->attach(new ModuleLoaderListener($options));
$this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULE_RESOLVE, new ModuleResolverListener);
// High priority, because most other loadModule listeners will assume the module's classes are available via autoloading
$this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULE, new AutoloaderListener($options), 9000);
if ($options->getCheckDependencies()) {
$this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULE, new ModuleDependencyCheckerListener, 8000);
}
$this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULE, new InitTrigger($options));
$this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULE, new OnBootstrapListener($options));
$this->listeners[] = $events->attach($locatorRegistrationListener);
$this->listeners[] = $events->attach($configListener);
return $this;
}
[/code]

This attaches itself to various events that would occur, and these events are associated with the Modules, as it calls every method from each Modules defined in the ApplicationConfig( in the config['modules']), the OnBootstrap will be triggered from each Module and the init method. It would be very suicidal to have heavy codes in the onBootStrap or init method because as you can see this process will be called on every Page Request. While the ServiceListener will call the getServiceConfig,ViewHelperConfig and other methods related to the configuration of the service manager.
Finally the loadModules gets called and it triggers some events, any function that listens to these events get executed and each function will receive the event as its parameter allowing the function to gain information about the event and the parameters passed.

[code lang="php" title="Zend/Mvc/Application"]
public function loadModules()
{
if (true === $this->modulesAreLoaded) {
return $this;
}
$this->getEventManager()->trigger(ModuleEvent::EVENT_LOAD_MODULES, $this, $this->getEvent());
/**
* Having a dedicated .post event abstracts the complexity of priorities from the user.
* Users can attach to the .post event and be sure that important
* things like config merging are complete without having to worry if
* they set a low enough priority.
*/
$this->getEventManager()->trigger(ModuleEvent::EVENT_LOAD_MODULES_POST, $this, $this->getEvent());
return $this;
}
[/code]

The next code that follows is the bootstrap method, the bootstrap method prepares the application as it retrieves all the listeners, which is then passed into the MvcEvent, looking at the code it fills up the MvcEvent with the necessary properties which will be used by the function that attaches to this event, an example is the setTarget('Application') setRequest(), setResponse(). The trigger function causes all functions attached to the 'MvcEvent::BOOTSTRAP' which is an alias for 'bootstrap' to be executed. This pattern allows the application to be event driven such example exists in the JavaScript world 'Publish/Subscribe'.
Finally the last method to be called is the run in the Zend/Mvc/Application

[code lang="php" title="Zend/Mvc/Application.php"]</pre>
// Trigger route event
$result = $events->trigger(MvcEvent::EVENT_ROUTE, $event, $shortCircuit);
if ($result->stopped()) {
$response = $result->last();
if ($response instanceof ResponseInterface) {
$event->setTarget($this);
$event->setResponse($response);
$events->trigger(MvcEvent::EVENT_FINISH, $event);
return $response;
}
if ($event->getError()) {
return $this->completeRequest($event);
}
return $event->getResponse();
}
if ($event->getError()) {
return $this->completeRequest($event);
}
// Trigger dispatch event
$result = $events->trigger(MvcEvent::EVENT_DISPATCH, $event, $shortCircuit);
// Complete response
$response = $result->last();
if ($response instanceof ResponseInterface) {
$event->setTarget($this);
$event->setResponse($response);
$events->trigger(MvcEvent::EVENT_FINISH, $event);
return $response;
}
$response = $this->getResponse();
$event->setResponse($response);
$this->completeRequest($event);
return $this;
}
[/code]

This method simply triggers different events during the Application life cycle and for each events triggered, it calls the listeners listening to that event. the last function calls the finish event, to let other listeners perform the necessary task during the final life cycle of the application, and this process is repeated again and again for each request.