Matthew wrote up an article on modules in Zend_Application and that got me thinking a little bit. When I have done training for Zend Framework, one of the things that mystifies students to some extent is the whole plugin architecture and where things can go. There has been several articles written about it, but they tend to use code to describe it. I was only able to find a small handfull of articles that used some kind of chart to describe what goes on. Not that that's a problem, but I had found that when I drew out the request lifecycle that it helped the students understand it better.
The chart on the right is a color-coded chart that shows when something is executed and where it is executed from. This chart is intentionally missing a whole bunch of things for the purpose of simplicity. If you want a more full explanation of the request lifecycle here is a great PDF that might help. For an introduction to plugins (with code examples but no diagrams 🙂 ) go here.
Note: to have a plugin potentially execute in all of the hooks you will need to add it in your bootstrap file, or class, prior to the front controller calling its dispatch() method.
The first hook that is run is the routeStartup(). It is run one time prior to the route being decided. If you have any kinds of custom routing that needs to be done, this might be the place to do it.
The second hook is the routeShutdown() hook. If you have module/controller/action based access control, this is not a bad place to put it. It is the very first time that you will know what the module, controller and action will be. That way if someone tries to access a certain URL that they shouldn't have access to they will be stopped immediately. However, if you use a lot of forwards or if you use the action stack a lot to hop around between controllers, modules and actions then this would not be a good place for access control since it is only called once. The error handler uses the routeShutdown() hook to check if it is handling an error for the current dispatch loop iteration so it can forward the dispatcher to the error controller prior to any other logic being called.
The next hook is the dispatchLoopStartup() hook. This is called immediately before the dispatch loop is started, and right after routeShutdown(). Functionally, at this point in time, there is no difference between dispatchLoopStartup() and route
After dispatchLoopStartup() is called, we enter the dispatch loop which is handled within a do-while statement, so it will run at least once. The next hook to run is the plugin preDispatch(). This method will be executed for each and every dispatch loop that runs. If you have a lot of forwards or use the action stack a lot to cross access control lines, this is a good place to put that control, instead of in routeShutdown() or dispatchLoopStartup().
After that, the execution moves to the dispatcher. This is where the controller class is loaded and instantiated. Because this is where the controller is instantiated, it is also where the controller init() method is called. A new controller object will be created for each and every dispatch loop, whether or not it is iterating over the same controller name. Therefore, init() will be called once per dispatch loop.
After the controller has been instantiated we move from the dispatcher's dispatch() method into the controller's dispatch() method. The first thing that happens is that the controller dispatch calls all of the controller helper's preDispatch() method. The preDispatch() method will only be called if the helper has been either a) referenced, or b) explicitly instantiated. Therefore, the preDispatch() method in a controller action helper MAY be called. In a plugin, the preDispatch() method WILL be called.
Once the controller action helper preDispatch() method has been called the controller's individual preDispatch() method is called. This is used to implement any functionality that is universal to the individual controller. Setting up contexts is an example of what you can do here.
Then the individual action is called. This, of course, is where you implement your logic for the individual piece of functionality that this required for this specific module, controller and action combo.
After that, the postDispatch() method is called on the controller. This is where the View Renderer is called. If you need to do something either immediately before or immediately after the View Renderer, this is a good place to do it.
The last point of execution for the individual dispatch is the plugin postDispatch(). An example of what is executed here is the Zend_Layout plugin. This call is handled in the front controller.
Here, the front controller has a decision to make. It will check to see if there are any outstanding actions to be executed. If so, it will start the do-while loop over again. If not, it will exit the loop and call the dispatchLoopShutdown() method on all of the plugins. In Zend Framework 1.10 there is only one component that uses this, and that is the Wildfire component.
So that is a brief overview of the request lifecycle in Zend Framework MVC applications. There's nothing new or special here, except that this posting has a picture with funny colors.