Symfony2: A two piece puzzle.

If you’re getting started with Symfony2, you’ll get something running pretty quickly. The AcmeBundle contains some of the basic features you’ll need when writing a Symfony2 app. The basics lie in the MVC paradigm, so there is some model (Doctrine ORM), some view (Twig templates) and some controllers.

However, none of that is the real core of Symfony2. The most interesting part lies in two main components of the framework. First, the HttpFoundation component and second, the Service container.

The HTTP Kernel

Ordinarily, with any controller framework out there, you’ll have a front controller, a router, a dispatcher and some action controllers that work together to generate output for any URL that is requested within your app. In essence, this is no different in Symfony2. There is something extra though. The HttpKernel, which is actually the core of your application is responsible for speaking HTTP. The developers of Symfony2 have put extra effort into nitpicking every aspect of the protocol, such as caching, so that any application written with the HTTP Component would have all the tools at hand to harness the power of HTTP.

The request loop

So, what actually happens when a typical Symfony2 app handles a request, is that a Request object is forged from all PHP’s relevant variables, it is dispatched into the Kernel as an event. The kernel holds a reference to the service container too. Each of the services registered as an event listener for this particular event is notified, so they can build a response. Then the response triggers a new event so all listeners can influence the response again, and ultimately the Response object is sent to the client.

Both the Request and Response objects reflect HTTP messages. As you probably know, any HTTP message is made up from a status line, a set of headers and an optional body. The headers contain protocol information and the body contains content. Usually, when you visit a page, a GET message is issued to the server, containing some headers on how your browser is configured and what host we want to get the URL from. The webserver responds with an answer, containing a status line which indicates the nature of the rest of the response, headers about the size of the response and some other useful information such as how long the resource may be cached by proxies and browsers, and, finally, a body, usually containing the resource data of the requested object if the request succeeded.

Parlez-vous HTTP?

In ye olden days, it was typical for a PHP script to always execute the exact same way, no matter how the user configured their browser or what information on caching was available. Moreover, it was common to have PHP scripts always send, what we affectionately called the “no cache headers”, which instructed the browser to absolutely never cache the page and please always come back to refresh the data, so all data was up to date for all PHP pages and all visitors, always. This had also to do with a particular browser that tended to cache more than was actually instructed by the web server, and customers who wanted to see changes rather sooner than later. Well, the conclusion was, that we, as a profession, never learned to parler HTTP.

Nowadays, with applications getting bigger and application speed, performance and stability are makers or breakers of the application’s success, you’re soon too late to dive in. There was a few years where we could get away with caching only in the backend by optimizing MySQL’s query cache, utilizing simple file caching mechanisms or firing up APC, Memcached and all the likes. All very useful, but only half the story.

Get up `ahhhh! Like a cache-machine

Basically, there are two ways of caching stuff. You can tell the client to keep a resource a maximum amount of time, or you can tell them when the resource was last modified 1. These two models are called Expiration and Validation, respectively.

In the first case, a client may keep the data as long as is specified. In the second case, the client must check back with the server to see if their cached version of the resource is still valid. If not, the response proceeds as usual; if so, the response is set to a 304 Not Modified status and is returned without a body. Expiration and validation can be combined so the client is told how old a resource is and with what frequency they should check back to validate the resource. That’s the short version. Read the longer version here.

The service container

The service container is a registry. What’s a registry, you say? It is a container object that contains immutable objects based on unique keys (much like a “hash” or a “map” structure), which is application wide. Martin Fowler describes it as “A well-known object that other objects can use to find common objects and services”2. The service container itself, therefore, is not that big a deal. THe idea behind it, though, is that all the services that are available in the service container can be loaded on demand. This phenomenon is called lazy loading or bootstrapping. That means that if you have a gazillion services defined, and not one of the lot is used, none of them will be instantiated. This means that if you have a PHP script cropping an image on-the-fly, that does not need the database connection will not open the database connection, even if the script uses the same front controller logic. Now, that sounds like it could be useful.

Depend this!

The clever thing about Symfony2’s service container is that it ships with a load of logic to resolve and inject dependencies. What that means is that if you have, say, a model class which depends on a database connection, you only have to explain to the container how the dependencies can be instantiated and how they reference each other, and the service container will know how to resolve the dependencies. This sounds like a lot of overhead, but as this dependency resolution is done at compile time, and PHP code is generated that actually has all such depencies resolved already, there really is next to none.

And then?

Get on the Symfony2-wave. It is rolling like crazy and Github is exploding with bundles (symfony2’s modules) and contributors. If you know the Kernel and the Dependency Injection components, you should head over to the Form component. Then you know about everything you need to know to build a real Symfony Bundle. The rest will come as you go.

One last tip, don’t use the Bundle Generator if you don’t know what it generates and whether you need it or not. Just create your bundle by hand, you can always start generating bundles if you actually know what it does. My next post on this topic will be a simple guide to help set things up by hand in stead of all the command line wizardry. Why? Because then you actually know what the wizard conjures.

There is also something called “E-tags”. In effect, this is the same as a Last-Modified. The semantical difference is that an E-Tag should represent a state of a resource (e.g. a hash, which would of course change as the resource changes) and the Last-Modified always represents a date. The (in)validation works exactly the same. ↩