Routing and Dispatching in a Straightforward Way
In reality, there are so many nifty options that can be used for building a functional front controller, but I’ll start by letting my pragmatic side show (yes, I have one). The first front controller implementation that I’ll go through will be charged with routing/dispatching URIs that conform to the following format:basepath/controllername/actionname/param1/param2/.../paramNIf you’ve ever laid your hands on a framework that uses the notion of parameterized action controllers, the above URI should familiar to you. It is a fairly ubiquitous pattern. Of course, the most challenging task here is designing a flexible mechanism capable of parsing the URIs in question without much fuss. This can be achieved in all sort of creative ways, either by plain procedural code or appealing to object-oriented code. I’ll be encapsulating the nuts and bolts of the routing/dispatching logic beneath the shell of a single class:
<?php
namespace LibraryController;
interface FrontControllerInterface
{
public function setController($controller);
public function setAction($action);
public function setParams(array $params);
public function run();
}
<?php
namespace LibraryController;
class FrontController implements FrontControllerInterface
{
const DEFAULT_CONTROLLER = "IndexController";
const DEFAULT_ACTION = "index";
protected $controller = self::DEFAULT_CONTROLLER;
protected $action = self::DEFAULT_ACTION;
protected $params = array();
protected $basePath = "mybasepath/";
public function __construct(array $options = array()) {
if (empty($options)) {
$this->parseUri();
}
else {
if (isset($options["controller"])) {
$this->setController($options["controller"]);
}
if (isset($options["action"])) {
$this->setAction($options["action"]);
}
if (isset($options["params"])) {
$this->setParams($options["params"]);
}
}
}
protected function parseUri() {
$path = trim(parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH), "/");
$path = preg_replace('/[^a-zA-Z0-9]//', "", $path);
if (strpos($path, $this->basePath) === 0) {
$path = substr($path, strlen($this->basePath));
}
@list($controller, $action, $params) = explode("/", $path, 3);
if (isset($controller)) {
$this->setController($controller);
}
if (isset($action)) {
$this->setAction($action);
}
if (isset($params)) {
$this->setParams(explode("/", $params));
}
}
public function setController($controller) {
$controller = ucfirst(strtolower($controller)) . "Controller";
if (!class_exists($controller)) {
throw new InvalidArgumentException(
"The action controller '$controller' has not been defined.");
}
$this->controller = $controller;
return $this;
}
public function setAction($action) {
$reflector = new ReflectionClass($this->controller);
if (!$reflector->hasMethod($action)) {
throw new InvalidArgumentException(
"The controller action '$action' has been not defined.");
}
$this->action = $action;
return $this;
}
public function setParams(array $params) {
$this->params = $params;
return $this;
}
public function run() {
call_user_func_array(array(new $this->controller, $this->action), $this->params);
}
}
The FrontController
class’ duties boil down to parsing the request URI, or eventually assembling a brand new one from scratch through a few basic mutators. Once this task has been carried out, the run()
method neatly dispatches the request to the appropriate action controller, along with the supplied arguments, if any.
Given its minimal API, consuming the class is a simple two-step process. First, drop into the web root a typical .htaccess
file, like this one:
RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ /index.phpSecond, set up the following code snippet as
index.php
:
<?php
use LibraryLoaderAutoloader,
LibraryControllerFrontController;
require_once __DIR__ . "/Library/Loader/Autoloader.php";
$autoloader = new Autoloader;
$autoloader->register();
$frontController = new FrontController();
$frontController->run();
In this case, the controller simply parses the request URI and feeds it to the given action controller, which is its default behavior by the way. It’s feasible, though, to explicitly provide a URI by calling the corresponding setters, as follows:
<?php
$frontController = new FrontController(array(
"controller" => "test",
"action" => "show",
"params" => array(1)
));
$frontController->run();
The front controller here is pretty malleable, easily configurable either for internally parsing requests or for routing/dispatching custom ones supplied directly from client code. Moreover, the previous example shows in a nutshell how to call the show()
method of an hypothetical TestController
class and pass around a single numeric argument to it. Of course, it’s possible to use different URIs at will and play around with the controller’s abilities. Therefore, if you’re bored and want to have some fun for free, just go ahead and do so.
Though I have to admit that my carefully-crafted FrontController
class has pretty limited functionality, it makes a statement on its own. It demonstrates that building up a customizable front controller is in fact a straightforward process that can be tamed successfully without having to use obscure and tangled programming principles.
On the flip side, the bad news is that the class has way to many responsibilities to watch over. If you’re skeptical, just check out its run()
method. Certainly its implementation is clean and compact, and can be even accommodated to intercept pre/post dispatch hooks. But it does multiple things at the same time and behaves pretty much as a catch-all point for routes and dispatches. It’s preferable to have a front controller dissected in more granular classes, whose responsibilities are narrowed to perform discrete tasks.
Needless to say that getting such a distilled front controller up and running as expected requires traveling down the road to a fairly prolific number of classes and interfaces. I’m reluctant to make this installment excessively lengthy, so I’ll be covering in depth the details of the whole implementation process in the next article. This way you can have some time to twist and bend my sample front controller and make it suit the taste of your delicate palate.
Closing Thoughts
Front controllers are ridiculously simple to implement from scratch, regardless if the approach makes use of procedural code or object-oriented code. And because of its easy-going nature, it’s fairly easy to scale up a naïve, primitive front controller and pitch over its shoulders the whole shebang required for handling RESTful resources behind the scenes. Quite possibly, the most tangled aspect of writing a front controller is solving the implicit dilemma when it comes to deciding if the requests must be either statically or dynamically routed and dispatched to the appropriate handlers. There’s no formal principle that prescribes all the routing/dispatching logic should be encapsulated within the controller’s boundaries or broken down into standalone modules that can be reused independently. Precisely, the latter is the form of implementation that I’ll be discussing over the course of the next article. So, stay tuned! Image via FotoliaFrequently Asked Questions about Front Controller Pattern
What is the Front Controller Pattern in web development?
The Front Controller Pattern is a software design pattern often used in web development. It provides a centralized entry point for handling requests. This pattern involves a single controller that’s responsible for processing application requests. It’s a part of the design models where you want to provide a centralized request handling mechanism so that all requests will be handled by a single handler.
How does the Front Controller Pattern work?
The Front Controller Pattern works by providing a centralized entry point for all requests. When a request is made, the front controller is responsible for handling the request and delegating the tasks to appropriate handlers. This can include routing the request to different parts of the application, authorizing the user, or handling errors.
What are the benefits of using the Front Controller Pattern?
The Front Controller Pattern offers several benefits. It provides a centralized control point for handling requests, which can lead to more organized and manageable code. It also allows for more flexibility in routing requests, as the controller can dynamically determine where to send the request based on various factors. Additionally, it can provide a consistent way of handling errors and security across the application.
How is the Front Controller Pattern implemented in PHP?
In PHP, the Front Controller Pattern can be implemented by creating a single PHP file that acts as the entry point for all requests. This file, often called index.php, will include the necessary logic to route requests to the appropriate parts of the application. This can be done using a switch statement, an if-else chain, or a routing library.
How does the Front Controller Pattern differ from the Page Controller Pattern?
The main difference between the Front Controller and Page Controller patterns lies in how requests are handled. In the Page Controller pattern, each page in the application has its own controller. This means that each page handles its own requests independently. On the other hand, in the Front Controller pattern, there is a single controller that handles all requests, providing a centralized control point.
Is the Front Controller Pattern suitable for all web applications?
While the Front Controller Pattern has its advantages, it may not be suitable for all web applications. For small, simple applications, using a Front Controller might be overkill and could lead to unnecessary complexity. However, for larger applications with complex routing needs, a Front Controller can provide a more organized and manageable solution.
How does the Front Controller Pattern handle security?
The Front Controller Pattern can enhance security by providing a centralized point for handling security-related tasks. This can include authenticating users, authorizing access to certain parts of the application, and handling errors. By centralizing these tasks, the Front Controller can help ensure that security is consistently enforced across the application.
Can the Front Controller Pattern be used with MVC architecture?
Yes, the Front Controller Pattern can be used in conjunction with the Model-View-Controller (MVC) architecture. In fact, it’s often used as part of MVC frameworks. In this context, the Front Controller acts as the initial entry point for requests, which are then passed on to the appropriate controller in the MVC architecture.
What are some examples of frameworks that use the Front Controller Pattern?
Many popular web development frameworks use the Front Controller Pattern. This includes frameworks like Symfony, Laravel, and Zend in PHP, Spring MVC in Java, and ASP.NET MVC in .NET. These frameworks provide built-in support for implementing a Front Controller, often through a base controller class that can be extended for different parts of the application.
Are there any drawbacks to using the Front Controller Pattern?
While the Front Controller Pattern has many benefits, it also has some potential drawbacks. One potential issue is that it can lead to a single point of failure. If there’s a problem with the Front Controller, it can affect the entire application. Additionally, the Front Controller can become complex and difficult to manage if not properly structured.
Alejandro Gervasio is a senior System Analyst from Argentina who has been involved in software development since the mid-80's. He has more than 12 years of experience in PHP development, 10 years in Java Programming, Object-Oriented Design, and most of the client-side technologies available out there.