Packing a Symfony full-stack Framework Application in one File -- Bootstrapping

Fabien Potencier

June 18, 2013

This article is part of a series of articles that explains how to pack a Symfony full-stack application in one file. The first article explains why this might actually be useful: 1) Introduction, 2) Bootstrapping, ...

The most common way to create a Symfony project is to start with the Symfony Standard Edition: it defines a sensible directory structure for your project and it make things a lot easier when someone want to take over an existing project as he knows where the templates, the controllers, or the configuration are stored. So, let's start our journey with the Symfony Standard Edition:

$ composer.phar create-project -n symfony/framework-standard-edition se/ 2.3.0

From there, let's remove a bunch of code to get the bare minimum of code needed to keep it working:

rm -rf LICENSE README.md UPGRADE* bin/ app/SymfonyRequirements.php \
       app/autoload.php app/bootstrap.php.cache app/AppCache.php app/check.php \
       app/console app/phpunit.xml.dist app/Resources src/ web/config.php \
       web/favicon.ico web/robots.txt web/apple-touch-icon.png web/app.php web/bundles/ \
       app/cache/* app/log/* .travis.yml app/.htaccess web/.htaccess
 

I've removed all those files and directories because there are not needed for the purpose of our challenge.

Next, let's simplify the configuration and move everything into just one file:

# app/config/config_dev.yml
framework:
    secret:          $ecret
    router:
        resource: "%kernel.root_dir%/config/routing_dev.yml"
    form:            ~
    csrf_protection: ~
    validation:      { enable_annotations: true }
    templating:
        engines: ['twig']
    session:         ~
    fragments:       ~
 

The routing_dev.yml file has been emptied for now, and all other configuration files have been removed.

We can also remove most of the bundles from the application kernel class:

use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;
 
class AppKernel extends Kernel
{
    public function registerBundles()
    {
        return array(
            new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
            new Symfony\Bundle\TwigBundle\TwigBundle(),
        );
    }
 
    public function registerContainerConfiguration(LoaderInterface $loader)
    {
        $loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml');
    }
}
 

We can also simplify the web/app_dev.php code:

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Debug\Debug;
 
require_once __DIR__.'/../vendor/autoload.php';
Debug::enable();
 
require_once __DIR__.'/../app/AppKernel.php';
 
$kernel = new AppKernel('dev', true);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
 

The composer.json file can also be simplified:

{
    "name": "fabpot/onefile-challenge",
    "license": "MIT",
    "type": "project",
    "autoload": {
        "psr-0": { "": "src/" }
    },
    "require": {
        "php": ">=5.3.3",
        "symfony/symfony": "2.3.*"
    }
}
 

As the code is available in a Git repository, I've kept the .gitignore file with the following content:

  /app/cache/*
  /app/logs/*
  /vendor/
  /composer.lock
 

Run composer again to remove all unneeded dependencies:

$ composer.phar update

After cleaning everything, here is the directory structure:

app/
??? AppKernel.php
??? cache
??? config
?   ??? config_dev.yml
?   ??? routing_dev.yml
??? logs
composer.json
vendor/
web/
??? app_dev.php
 

As you can see, we are now down to 5 files. And of course, you still have the full power of the full-stack framework (from the web profiler to the Twig templating system). Code for today is available on Github.

In the next post, I will write about the Kernel class and how it works.

Discussion

gravatar Luis Cordova  — June 18, 2013 15:29   #1
nice but one thing Fabien

it would be best if you had committed first and rebased on the original state, then add the remove commit so we can see exactly what things got removed or how they were adapted. Something picky but would help everybody follow along.

great series
gravatar Michal Dudek  — June 20, 2013 15:07   #2
Hmm, how can you say you're down to 5 files with all the contents of vendor/ dir?
gravatar Fran├žois Pluchino  — June 20, 2013 18:03   #3
@Michal As explained Fabien in his introduction post ("Micro vs Full-Stack" section), "micro does not mean less code. The user of a framework does not care about the number of lines of code in the framework. It does not matter when using the framework".

So, in starting a new project, the important, this is the quantity of code created by the developer to actually start the project development, and not the total quantity of code used, IMO.
gravatar Larry Hill  — June 26, 2013 21:06   #4
I had the same misunderstanding as Michal. When I read "Symfony full-stack Framework Application in one File," I took that to mean vendor code and all. I'm afraid to say that I'm much less excited about this series now than I was before.
gravatar Fabien Potencier  — June 26, 2013 21:17   #5
@Michal @Larry Packing everything in one file including the vendors would not fulfil my goals as stated in the first part of the series.

Anyway, creating a phar is probably what you are looking for.
gravatar Michael Bodnarchuk  — June 30, 2013 21:06   #6
@Fabien

There was an issue runing Symfony 2.2 app with phar files included. Not sure it was fixed in 2.3, pls, so just wanted to mention.

https://github.com/symfony/symfony/issues/7798
gravatar Symfomany  — July 19, 2013 09:21   #7
To understand quality of code in last keynote and german quality like PHPUnit of Sebastian Bergmann, you just watch this add ... TDD: We love it ! http://www.youtube.com/watch?v=4P9pC4iGSs0 :)
gravatar Tito Miguel Costa  — July 23, 2013 15:48   #8
@Fabien, when are you planning to release a new chapter? It's been a while. I am looking forward. Keep up the good work.