In the early days of web design, each page was standalone, and you ended up with files like index.html
, about_us.html
, contact.html
, products01.html
, products02.html
etc. Each of these HTML files had a similar structure of tags, with only the content being different. Moreover, HTTP being a stateless protocol meant that there was no meaningful connection between different pages on the same server.
Then scripting languages such as PHP, ColdFusion, ASP, and JSP came along, and web development changed dramatically. Server Side Includes (SSI) and Edge Side Includes addressed some of the issues but not for long. The technology allowed for HTML to be broken up into fragments and then added to any page when necessary. For example, a header and footer fragment are included on pages so that if you need to add a meta tag, for example, it is added in a single file and the change is reflected everywhere it is used.
Later, database server technology was thrown into the mix, which added a different dimension to the entire process. The content was held in a database and on each page where you required a piece of content, maybe an article, a connection was made, data retrieved from database tables and the connection was closed. Web scripting languages made the nice display of such article trivial by outputting the content, surrounded by HTML tags.
Things were now different but each page was still a distinct entity, and there was no guarantee of consistency. Bearing in mind that each incoming request is seen by the server as a fresh request even though they might be coming from the same web browser. Database connection, session setup, and other environment initialization steps required are repeated over and over and again. Each page request provides and manages access to system services and navigation to different pages. Sometimes changes will have to be made in numerous places.
Then, web application development became aligned with the discipline of software engineering and developers began to look at common problems facing them irrespective of the programming language, framework, or environment. Language-agnostic approaches or solutions to problems could potentially be applied in the field of web development. There is no code involved in the software design pattern thought process. It only provides guidelines for developers as they architect solutions and write their code.
Rather than dealing with separate requests for resources at any location, a more manageable solution is to have a central access point for incoming requests to an application. This initial application entry point will handle the common system services required for processing the request. The logic of decision-making is handled centrally to dispatch the request to the appropriate component. Data retrieval and manipulation are also handled centrally, with the selection of an appropriate view, before it is returned to the user.
This is what the front controller design pattern is about. And, once again, it is not unique to web applications. Here is an example for a J2EE application:
All requests are received by the controller and processed. For a web application like Drupal, a single application entry-point will handle the process of initialization (bootstrapping), authentication and authorization, navigation or routing, retrieval of content from a database or web service and making content available to the end user or system in desired formats. There are different variations in what each component of the entire process is called, but the pattern is the same.
All requests to Drupal are redirected to the index.php
file, which serves as the front controller.
<?php
// Drupal 7 - index.php
define('DRUPAL_ROOT', getcwd());
require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
menu_execute_active_handler();
Here is the Drupal 8 version of the file:
<?php
// Drupal 8 - index.php
use Drupal\Core\DrupalKernel;
use Symfony\Component\HttpFoundation\Request;
$autoloader = require_once 'autoload.php';
$kernel = new DrupalKernel('prod', $autoloader);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
Drupal 8 shares a lot with Symfony and we can see that in its app.php
which is the equivalent of the index.php
above:
<?php
// Symfony - app.php
use Symfony\Component\HttpFoundation\Request;
require __DIR__.'/../vendor/autoload.php';
if (PHP_VERSION_ID < 70000) {
include_once __DIR__.'/../var/bootstrap.php.cache';
}
$kernel = new AppKernel('prod', false);
if (PHP_VERSION_ID < 70000) {
$kernel->loadClassCache();
}
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
The similarities between both implementations of the Front Controller design pattern are clear.
When an HTTP request is received by the server, it passes through a kind of filter which determines what needs to be done prior to handing it over to the web application. Drupal targets the most popular web server, Apache, and comes with an .htaccess
file which does a few things with an incoming request if the application is hosted on Apache. There is also a web.config
file for Microsoft Internet Information Services (IIS) servers.
The last step is to redirect the request to the index.php
file. This relatively small file is the gateway that stands in front of our application and controls the entire process of handling the incoming request.
In order to deliver a single page, many requests are made, sometimes running into hundreds and each time the request hits the server, the server configuration file is called into action. All incoming requests are then directed to the index.php
which handles all of them in an orderly fashion. That is the kind of order this design pattern brings to a situation that could be potentially chaotic were it not in place.
Let us take another look at the Drupal 8 front controller, the index.php
file:
<?php
use Drupal\Core\DrupalKernel;
use Symfony\Component\HttpFoundation\Request;
$autoloader = require_once 'autoload.php';
$kernel = new DrupalKernel('prod', $autoloader);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
These 8 lines of code power every Drupal 8 installation and they summarise the key steps of the request-response process. Here is a couple of observations:
- At the very top, we see two
use
statements which mean we need to import two classes which are needed later. They demonstrate the dependency of a Drupal 8 application on the Symfony framework. - Four variables representing objects, manage the entire process -
$autoloader
(ClassLoader
),$kernel
(DrupalKernel
),$request
(Request
) and$response
(Response
). - Do some housekeeping and get an instance of an autoloader,
$autoloader
. - Create a
DrupalKernel
instance,$kernel
. - Create the
Request
object from the incoming request. - The
DrupalKernel
instance handles theRequest
and returns aResponse
instance. - Finally, the
terminate()
method is called on the Kernel instance,$kernel
.
This has been a short introduction to the Front Controller design pattern that powers much of the modern Web. It's useful both in existing frameworks and if you decide to roll your own implementation, so study it, and wield its power wisely!
Up next
Lorem ipsum dolor sit amet, consectetur adipiscing elit.