Now, where the ServiceManager has been equipped with the required services, and the ModuleManagerhas loaded the application’s modules, the Application itself can be started and the request processing, initiated. This occurs in 3 steps, partly in the init() method of the application itself
and partly in the index.php: Starting the application (bootstrap()), followed by the execution
(run()) and last but not least returning the generated results (send()):
<?php $application = $serviceManager->get('Application'); $application->bootstrap() $application->run(); $application->send();
Generation of the application & bootstrapping
The application object is generated via the factory that is registered in the ServiceManager. In the
scope of the generation, the Application invokes a number of standard services, among them both
the Request, as the basis for further processing, and the Response, which is to be filled with life in
the scope of the processing. In addition, the Application gets a reference to the ModuleManager and its own instance of the EventManager (which is indeed deposited in the ServiceManager such that
it is not shared; thus a new instance of this service is returned). The latter ensures―analogously to
the ModuleManager―that the Application can trigger events and inform listeners. The Application
sets off a number of events in the scope of the processing.
bootstrap: Is executed when the application is started.
route: Occurs when a controller and an action are determined for the URL.
dispatch: Takes place when a determined controller is identified and invoked.
render: Occurs when the result for the return is prepared on the basis of templates.
finish: Is executed when the application has been completed.
In the course of bootstrapping the Application likewise registers (incidentally in this case the
Application itself and not the ApplicationFactory) a number of listeners, which it also obtains via
the ServiceManager: RouteListener for the route event, DispatchListener for the dispatch event
and the ViewManager for a colourful bunch of additional listeners, which perform the processing of
templates and layouts. More about this in the next section.
Furthermore, the Application then creates the MVC-specific event object (MvcEvent), which is
registered with the EventManager as event object. MvcEvent then enables the listeners to access
Request, Response, Application and the Router.
Finally, the bootstrap event is initiated and the registered listeners are run. They can also
particularly be the application’s individual modules, which have registered for just this event.
Execution
The run() method, which is executed subsequent to bootstrapping, then actuates a number of
“levers” that had already been placed in the correct position. To begin with, the Application
triggers the route event. The RouteListener, which was registered for this event beforehand, is
run and the Router from the MvcEvent is asked to perform its services: i.e. to match the URL to
a defined route. In this case, a route is the description of a URL on the basis of a defined pattern.
We will take a detailed look at the mechanics of routing later. At the moment, we only have to
remember that the Router now either finds a route that fits the invoked URL and thus determines
the appropriate controller as well as the appropriate action or, on the contrary, the Router returns
with bad news and did not turn up any search results at all. But let’s initially remain on the successful path in this case. The appropriate route is deposited in the form of a RouteMatch object in MvcEvent by the RouteListener. MvcEvent is thus increasingly proving to be a central object in which a number of other important objects and data are available. Then the dispatch event is initiated, the ControllerLoader is invoked and uses the MvcEvent to find the identified controller, which is to be instantiated. To achieve this, the DispatchListener requests the ControllerLoader from the
ServiceManager (which, technically speaking, in its own right is also again a “ServiceManager”)
and then the actual controller from it (i.e. from the ControllerLoader). In the course of this,
the controller is also equipped with an EventManager of its own. Now, it can thus actuate events
and manage listeners. Then the controller’s dispatch() method is invoked, and performs the
further processing itself. If any intermittent problems occur in this enterprise, the dispatch.error
event is triggered; otherwise, the result of the dispatch() invocation is deposited in MvcEvent and
additionally returned and thereupon the dispatch process within the controller is concluded.
In Zend Framework, controllers are so conceived that they only have to have one dispatch() method at their disposal. This is externally invoked, in the process the Requestobject is transferred, and the controller is expected to return an object of the Zend\Stdlib\ResponseInterface type when
the work has been completed. In order for the principle of controller and action to function,
as one is accustomed to and expects, this logic must be implemented in the controller itself;
otherwise only the dispatch method would be invoked, but not the appropriate “action” method.
To insure that that one does not have to do this oneself, one’s own controller inherits this from
the Zend\Mvc\Controller\AbstractActionController. Subsequently, any arbitrary actions can be
deposited in the controller when one adheres to the convention that the method name must end
with “action”:
<?php namespace Helloworld\Controller; use Zend\Mvc\Controller\AbstractActionController; use Zend\View\Model\ViewModel; class IndexController extends AbstractActionController { private $greetingService; public function indexAction() { return new ViewModel( array( 'greeting' => $this->greetingService->getGreeting(), 'date' => $this->currentDate() ) ); } }
Back in the Application , the two results render and finish are now initiated and the run() method
concluded. Incidentally, the following fact is very interesting and helpful.: Normally, an action
returns an object of the ViewModel type at the end of processing. It thus implicitly signals the
subsequent processing steps that the result must still be processed before it can be returned.
<?php public function indexAction() { return new ViewModel( array( 'greeting' => $this->greetingService->getGreeting(), 'date' => $this->currentDate() ) ); }
However, a very practical implementation detail is the fact that when a Response object is returned
instead of a ViewModel, the downstream render activities are omitted.
<?php public function indexAction() { $resp = new \Zend\Http\PhpEnvironment\Response; $resp->setStatusCode(503); return $resp; }
This mechanism is helpful if one desires, for example, to briefly return a 503 code, because the
application is just undergoing scheduled maintenance or when one desires to return data of a specific Mime type, for example the contents of an image, of a PDF document or something similar.
ViewManager
Before the processing has ended, the ViewManager comes into play again. In the previous section,
we have already seen that the onBootstrap() method is executed in the scope of the bootstrapping
of the Application (because it is registered for the corresponding event) and that an entire series
of additional preparations are made there. Up to now, we have blended this out for simplicity’s
sake, but now we also have to look at the details in this case. After the ViewManager with its
many collaborators has completed its work, we have actually worked our way through the entire
processing chain once.
To begin with, the ViewManager obtains the Config from the ServiceManager, which at this time
already represents the merged “total configuration” of the application and of the modules. The
ViewManager looks for the view_manager key and uses the configurations deposited there. Then the old game of registering diverse listeners and the provision of additional services begins again.
View-oriented listeners
The following listeners are generated and all of them are attached to the dispatch event of the
ActionController class (or more exactly: of the EventManager of the ActionController):
CreateViewModelListener: Ensures that, after execution of the controller, an object of the
ViewModel type is available for the rendering, even if only NULL or an array was made available
by the controller.
RouteNotFoundStrategy: Generates a ViewModel for the case that no controller was determined and no “View Model” could be generated (404 error).
InjectTemplateListener: Adds the appropriate template to the ViewModel for subsequent
rendering.
InjectViewModelListener: Adds the ViewModel to MvcEvent. This listener is also registered
for the dispatch.error event of the Application in order to also be able to make a ViewModel
available in case of error.
The dispatch event is incidentally somewhat nasty: it occurs twice in the system It is once
triggered by the Application, and again by the ActionController. Even if the designation of the
event is identical (it can indeed be freely selected), due to the fact that it is triggered by different
EventManagers, we are dealing with two completely different events.
Incidentally, at this time, the EventManager of the respective , specific manifestation of the
ActionController does not yet exist because the latter has not yet been generated at all. In this case,
this problem is avoided by using the SharedEventManager. With the aid of the SharedEventManager, listeners for the events of an EventManager, which does not even exist at the time of registration, can be registered. For the time being, we’ll simple leave things as they are. We’ll take a more detailed look at how this mechanism is realized in the next chapter.
View-oriented services
In addition, a number of view-oriented services are made available in the ServiceManager:
View and View Model: To begin with there is the View itself with its View Model, the
representation of the “payload” generated from a request for the response.
DefaultRenderingStrategy: Can access the View and is registered for the render Event of the
Application. If this event occurs, the View is transferred to the ViewModel, which is obtained
from the MvcEvent and then prompts the View to render just that.
ViewPhpRendererStrategy: However, the actual rendering is not performed by the Viewitself,
but is instead delegated to the ViewPhpRendererStrategy, which initially specifies the
appropriate renderer and transfers the finished result to the Response‘ subsequent
to processing.
RouteNotFoundStrategy: Defines the appropriate behaviour in case of a 404 situation.
ExceptionStrategy: Defines the appropriate behaviour in case of a “dispatch errors”.
ViewRenderer: Takes over the actual rendering work, i.e. the merging of the ViewModel data
and the appropriate template.
ViewResolver: In order to localise the respective template, the ViewRenderer accesses the
ViewResolver.
ViewTemplatePathStack: Makes it possible for the “resolver” to localise a template on the
basis of deposited paths.
ViewTemplateMapResolver: Makes it possible for the “resolver” to localise a template on the
basis of a “key value assignment”.
ViewHelperManager: Makes it possible to access “ViewHelpers” in templates; this simplifies
the generation of dynamic markup.
In case of an error in the scope of routing or in the course of dispatching, respectively, the
Application triggers a dispatch.error event. This signalises that an error has occurred in the
processing.