During the recent development of the new PHP cloud development casts site, which has been developed with the Zend Framework, so much development time has been saved by using one of the simplest and arguably best features of the framework: Controller Plugins. So today I want to introduce you to them and walk you through a working plugin so you can see just how effective and efficient they can make your development workflow.
During the recent development of the new PHP cloud development casts site, which has been developed with the Zend Framework, so much development time has been saved by using one of the simplest and arguably best features of the framework: Controller Plugins.
So today I want to introduce you to them and walk you through a working plugin so you can see just how effective and efficient they can make your development workflow.
If you’re not familiar with controller plugins, they’re effectively code snippets that are automatically executed when any one of six events occurs during the Zend Framework application request lifetime. These events are:
- routeStartup - before the current route is evaluated
- routeShutdown - after the completion of routing
- dispatchLoopStartup - before the dispatch loop is entered
- preDispatch - before the current action is dispatched
- postDispatch - after the current action is dispatched
- dispatchLoopShutdown - after the dispatch loop is completed
With these we can intercept the key points in the dispatch process and do some pretty amazing stuff. To get a better understanding of the dispatch process, look at the dispatch process overview diagram below from Thorsten Ruf.
Zend Framework Dispatch Process Overview by Thorsten Ruf
What Are They Good For
To give you a taste of what can be done using them, consider the following options:
- Insert 3rd party account code at the end of every request, such as Google Analytics
- In a non-production environment, add information to the end of the request body (or page) so that we know, for sure, what environment we’re in and what we’re testing
- Create a pre-launch or maintenance mode for our application
- Redirect a user to a specific page if they are or are not logged in
The list really does go on and on. To show you just how simple they are I’m going to show you a controller that was used in the php cloud casts site which managed the redirection to the prelaunch page before the site was live.
1
2
|
<td class="code">
<pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> MaltBlue_Controller_Action_Plugin_Prelaunch
extends Zend_Controller_Plugin_Abstract
All controller plugins need to extend Zend_Controller_Plugin_Abstract.
1
|
<td class="code">
<pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> preDispatch<span style="color: #009900;">(</span>Zend_Controller_Request_Abstract <span style="color: #000088;">$request</span><span style="color: #009900;">)</span></pre>
</td>
</tr>
We’re going to hook in to the preDispatch event so that we can redirect to the prelaunch page before the current page is loaded, if-needed.
1
2
3
4
|
<td class="code">
<pre class="php" style="font-family:monospace;"><span style="color: #000088;">$auth</span> <span style="color: #339933;">=</span> Zend_Auth<span style="color: #339933;">::</span><span style="color: #004000;">getInstance</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
if ($auth->hasIdentity()) {
return TRUE;
}
If a user is already logged in, don’t worry about redirecting
1
2
3
4
5
|
<td class="code">
<pre class="php" style="font-family:monospace;"><span style="color: #000088;">$front</span> <span style="color: #339933;">=</span> Zend_Controller_Front<span style="color: #339933;">::</span><span style="color: #004000;">getInstance</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
$bootstrap = $front->getParam(‘bootstrap’);
$config = new Zend_Config($bootstrap->getOption(‘resources’));
$resource = $request->getModuleName() . ’:’ . $request->getControllerName();
$redirector = Zend_Controller_Action_HelperBroker::getStaticHelper(‘redirector’);
Get access to certain information about the current environment and load up some configuration details from our application.ini file. The reason the configuration details are in the application.ini file are to avoid having them in code, which makes runtime configuration a lot easier. Below is a sample set configuration which makes the next few snippets make sense.
1
2
3
4
|
<td class="code">
<pre class="php" style="font-family:monospace;">resources<span style="color: #339933;">.</span>prelaunch<span style="color: #339933;">.</span>launchDate <span style="color: #339933;">=</span> ‘<span style="color: #cc66cc;">2012</span><span style="color: #339933;">-</span><span style="color: #208080;">07</span><span style="color: #339933;">-</span><span style="color: #208080;">03</span> <span style="color:#800080;">09</span><span style="color: #339933;">:</span><span style="color: #208080;">00</span><span style="color: #339933;">:</span><span style="color: #208080;">00</span>’
resources.prelaunch.excluded.routes..name = login
resources.prelaunch.excluded.modules..name = administration
resources.prelaunch.excluded.modules.1.name = user
1
2
3
4
5
6
7
|
<td class="code">
<pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">if</span> <span style="color: #009900;">(</span><span style="color: #990000;">count</span><span style="color: #009900;">(</span><span style="color: #000088;">$config</span><span style="color: #339933;">-></span><span style="color: #004000;">prelaunch</span><span style="color: #339933;">-></span><span style="color: #004000;">excluded</span><span style="color: #339933;">-></span><span style="color: #004000;">modules</span><span style="color: #009900;">)</span> <span style="color: #339933;">></span> <span style="color: #cc66cc;"></span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
foreach ($config->prelaunch->excluded->modules as $module) {
if ($module->name == $request->getModuleName()) {
return TRUE;
}
}
}
Even if we’re wanting most of the requests to be redirected to the prelaunch page, we still need to allow content managers to carry out administration of the site. So we check if certain routes have been excluded from being redirected. If so, we allow them to execute as normal.
1
2
3
4
5
6
7
|
<td class="code">
<pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">if</span> <span style="color: #009900;">(</span><span style="color: #990000;">count</span><span style="color: #009900;">(</span><span style="color: #000088;">$config</span><span style="color: #339933;">-></span><span style="color: #004000;">prelaunch</span><span style="color: #339933;">-></span><span style="color: #004000;">excluded</span><span style="color: #339933;">-></span><span style="color: #004000;">routes</span><span style="color: #009900;">)</span> <span style="color: #339933;">></span> <span style="color: #cc66cc;"></span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
foreach ($config->prelaunch->excluded->routes as $route) {
if ($route->name == $front->getRouter()->getCurrentRouteName()) {
return TRUE;
}
}
}
But as the application’s module based, and there are a number of controllers, which have a number of actions, to list them all is extremely ineffective and is error prone. So we can also exclude entire modules from being redirected, as below.
1
2
3
4
5
6
7
|
<td class="code">
<pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">if</span> <span style="color: #009900;">(</span><span style="color: #000088;">$request</span><span style="color: #339933;">-></span><span style="color: #004000;">getModuleName</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'prelaunch'</span>
&& $request->getControllerName() == ‘index’
&& $request->getActionName() == ‘index’) {
return TRUE;
} else {
$redirector->setCode(303) ->setExit(true) ->gotoSimpleAndExit(‘index’, ‘index’, ‘prelaunch’, array());
}
Here we’ve gone through all the exclusions and everything else is to be redirected. So we check if we’re already at the prelaunch page. If so, we simply return true, which completes execution of the plugin.
If not, we set a HTTP code of 303, nice for SEO purposes, indicate that we’re going to exit and then redirect to the index action of the index controller in our prelaunch module, with no supplemental request parameters.
Caveat Emptor (Buyer/Developer Beware)
There is so much more that you can do with controller plugins and this has just scratched the surface. Also, when redirecting in a controller plugin, you need to be careful that you don’t end up in a redirect loop, which I still do from time to time. This can happen based on the logic in your plugin, or if you have a number of plugins and the logic in each isn’t carefully considered.
Nice and Simple.
You can see from this example that we’ve been able to appropriately intercept the relevant segment of the request loop in an elegant and concise way everytime.
We don’t have to re-invent the wheel when building our applications. I hope that this has whet your appetite and that you’ll start using them if you haven’t already.
If you need any further information, check out the Zend Framework manual section on writing plugins and check out an early post that Matthew Weier O’Phinney wrote on them.
Join the discussion
comments powered by Disqus