(I’m putting this in a separate post to keep things organized a bit)
You wanted to see a FrontController + PageController + InterceptingFilters in action? Here goes:
class FrontController
{
function run()
{
$filterChain = new SessionTrackingFilter(
new AuthenticationFilter(
new OutputBufferFilter
(
$this
)
)
);
$filterChain->processRequest();
}
function processRequest()
{
switch ($_GET['page'])
{
case 'add':
$pageController = new UserAddController;
break;
case 'edit':
$pageController = new UserEditController;
break;
case 'list':
$pageController = new UserListController;
break;
}
$pageController->execute();
$view = $pageController->getView();
$view->render();
}
}
Some explanation first before I show you the rest of the code. As you can see, in the FrontController, instead of directly selecting a PageController, now I set up a chain of InterceptingFilters and at the end of the chain I put the FrontController again. The request now gets processed by the SessionTrackingFilter, which passes it onto the AuthenticationFilter, to the OutputBufferFilter and finally back again to the FrontController.
Now for the intercepting filters:
class SessionTrackingFilter extends InterceptingFilter
{
function __construct($nextFilter)
{
$this->nextFilter = $nextFilter;
}
function processRequest()
{
// do whatever needs to be done to start a session
...
// let all the other filters do their work
$this->nextFilter->processRequest();
// and after those filters have done their work, close the session
...
}
}
class authenticationFilter extends InterceptingFilter
{
function processRequest()
{
if ($validCookieFound)
{
// the user has been authenticated, so move on to the next filter
$this->nextFilter->processRequest();
}
else
{
// whoah, hold up, we need to ask the user for authentication first
echo 'Please enter your username and password in the form here etc. ';
// now we do not move on to the next filter, we stop processing the request here
// and return control to the previous filter in the chain
return;
}
}
}
}
class OutputBufferFilter extends InterceptingFilter
{
function processRequest()
{
ob_start();
$this->nextFilter->processRequest();
ob_end_flush();
}
}
As you can see, the InterceptingFilters are clean and small classes. If for some section of your website you need a different authorization method, or perhaps you don’t want to use sessions, you simply rearrange the chain of filters: reuse them.
That is the most important advantage I can think of, and it is an advantage that comes from good object oriented design: reusability. You can reuse the filters and rearrange them in any order, something you can’t do when you implement their behaviour in a base PageController class (you would theoretically need one for every possible combination of filters in any order).
For more information about InterceptingFilters, I can also recommend the link seratonin gave: http://www.corej2eepatterns.com/Patterns2ndEd/InterceptingFilter.htm You’ll see that the example I gave above is not so much different from the Java code.
Also
One solution would be modifying the FC to something like the following + code
That’s what McGruff said