In this article we’re going to get our hands dirty poking around inside the Symfony 2 front controller. Scalpels ready? What’s that? A question?
What's a front controller?
If you’ve worked with a few web applications in your time you’ve probably already encountered the front controller pattern. What it does is provide a single entry point into your web application. That means all requests go to the front controller, and all responses emanate from the front controller.
What normally happens with a web server is that a remote host requests a resource from it using a URL, the web server does some computation and then sends back some data. For the sake of illustration, let’s imagine you’ve written some some software that enables creative web hipsters to publish articles for all the world to see, listed in reverse chronological order. You were going to call this ground-breaking application the “web log” before you realised how much creative web hipsters like esoteric jargon, so you put the words together and dropped the first two letters.
The Normal request flow So let’s say a visitor is checking out the incredible life-changing content you are now able to publish (thanks to your shiny new web app) and they want to read your latest article about the influence of Mongolian Throat Singing on Norwegian death metal. It’s likely they’ll type something like the following:
Of course if you speak HTTP (as all good web developers do, right?) you understand that this request is asking for a file on the server called “articles.php” and is providing a parameter in the query string, which is “id=34”. So what will normally happen now is that the server will retrieve and run a script saved in a file called “articles.php”, and the response will be sent back to the user. Simple.
The “front controller” request flow The key difference between the “normal” way of handling requests and the front controller pattern is that all requests are sent to a single script, regardless of what they’re asking for. So if we were to implement a front controller – let’s call it “index.php” – what would happen is that a request for:
… would result in “index.php” being run. It is then up to the code in “index.php” to work out what to do and return the request, based on the URL and parameters.
… and why do we care?
So… why? Isn’t this confusing? Well, it turns out there are a bunch of good reasons for doing this.
Separate the routing of requests within the web application from the filesystem. This means our URL structure doesn’t need to match the file and folder structure of our web application. We can even change the URLs dynamically without having to manipulate the file system. Hide the implementation details of the application. Using the old method, it’s very obvious to the user how the application is structured, as they’re directly interacting with scripts via URLs that mimic the actual file system on the server. The front controller provides a layer of abstraction over the top of this.
Symfony’s front controllers
Symfony uses different front controllers to define environments. By modifying the existing front controllers or creating new ones, you can customise different configurations of Symfony for different working environments, such as “test”, “development” and “production”.
The production environment
The front controller for the production environment is called “app.php” and contains the following:
These few lines of code are the heart of the Symfony engine. Let’s break it down by line.
The first line loads the bootstrap cache. To increase speed, Symfony aggregates a bunch of PHP classes that your application needs for every request into a single file. This means instead of having to open and parse tens or hundreds of PHP files for every request, it can just open a single big one.
The next include is for the AppKernel. The Kernel implements the front controller logic, and is responsible for handling Bundle and environment management as well as the flow of control through the app.
Ignore the commented out lines for now – we’ll cover those shortly.
Next we have a namespace declaration so we can use the ‘Request’ class, which (as the name implies) provides an object representation of the current request.
$kernel = new AppKernel('prod', false);
This line creates and sets-up an environment for us the handle the request. The first parameter provides a name for our environment, and will be used when looking up the configuration file (‘prod’ means Symfony will look for the file ‘config_prod.yml’). The second parameter determines whether or not ‘debugging’ is enabled. Obviously this will be set to ‘false’ for in the production environment.
Is used to regenerate the PHP class cache. We typically won’t need to interact with this line of the front controller, just as long as it’s in there we’re happy.
Creates a (singleton) instance of Request and dispatches it to the Kernel. The kernel will be responsible for sending it to the correct location in the app based on the routing rules.
//require_once **DIR**.'/../app/AppCache.php'; ... //$kernel = new AppCache($kernel);
These lines are commented out by default. If we uncomment them, the front controller file creates an instance of the AppCache class which is a wrapper for the kernel which enables reverse proxy caching. By doing this each request to the application will be cached. This provides an obvious performance boost, but can result in unexpected behaviour if not managed correctly. To find out more about caching in Symfony, check out the documentation.
Symfony also comes with a “development” front controller, which creates an environment from which we can test and debug our application. It is also located in the web folder, but is named “app_dev.php”. Its contents are:
You’ll notice that the first few lines are significantly different to those in the production front controller. These check to make sure that the user is navigating to the page from localhost, as some sensitive information may be displayed in the “dev” environment that we don’t want publicly accessible if we were to accidentally deploy this front controller in the live environment.
The only other differences you’ll notice here are that the commented-out lines to enable caching are omitted (as we typically don’t want to cache when debugging) and the debug mode is enabled when creating the instance of AppKernel.
That’s it. The front controllers are small files, but without them nothing would work. After reading this you should be a front controller expert! Why not jump in and try to create your own environment from scratch by writing a custom front controller file?
For more information check out the Symfony documentation on environments.