New in Symfony 2.8: Symfony as a Microframework

A microframework is a term used to refer to "minimalistic web application frameworks". Developers usually associate this term with "fast and small frameworks", such as Silex. But you can also think of microframeworks as simple and less-opinionated fameworks where you opt-in to the the architecture-related decisions.

Thanks to its flexible internal architecture, it has been possible to use Symfony as a microframework since day one. However, few developers have used Symfony in that way because it wasn't completely convenient.

Symfony 2.8 introduces a new microkernel trait to greatly simplify the creation of single-file (or just smaller) Symfony applications. A "Hello World" application using Symfony as a microframework looks like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// app/MicroKernel.php
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Routing\RouteCollectionBuilder;

class MicroKernel extends Kernel
{
    use MicroKernelTrait;

    public function registerBundles()
    {
        return array(new Symfony\Bundle\FrameworkBundle\FrameworkBundle());
    }

    protected function configureRoutes(RouteCollectionBuilder $routes)
    {
        $routes->add('/', 'kernel:indexAction', 'index');
    }

    protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader)
    {
        $c->loadFromExtension('framework', ['secret' => '12345']);
    }

    public function indexAction()
    {
        return new Response('Hello World');
    }
}

A single MicroKernel class enables the bundles, configures them, defines the routing and even holds the controller code. If you exclude the mandatory use imports and the function declarations, the above example has exactly 4 lines of PHP code. Think about that for a moment: a fully-functional Symfony application in just 4 lines of code!

The new microkernel doesn't improve the raw Symfony performance, because it just changes the way routes and bundles are registered. However, since you are only enabling the features you use, lots of the features and bundles of the Symfony Standard Edition are disabled. This explains the difference perceived in the application performance:

Symfony Microframework vs Symfony Standard Edition

The best thing about the Symfony microframework is that you are building your application on the shoulders of Symfony, meaning that you won't face any of the usual restrictions of the microframeworks. All the incredible Symfony features and bundles are ready to use in case you need them as your application grows.

In the following example, the Hello World application is expanded to add Twig templating support, the Web Debug toolbar and the Symfony Profiler. The result is still a single-file application:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// app/MicroKernel.php

class MicroKernel extends Kernel
{
    use MicroKernelTrait;

    public function registerBundles()
    {
        $bundles = array(
            new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
            new Symfony\Bundle\TwigBundle\TwigBundle(),
        );

        if (in_array($this->getEnvironment(), array('dev', 'test'), true)) {
            $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
        }

        return $bundles;
    }

    protected function configureRoutes(RouteCollectionBuilder $routes)
    {
        $routes->mount('/_wdt', $routes->import('@WebProfilerBundle/Resources/config/routing/wdt.xml'));
        $routes->mount('/_profiler', $routes->import('@WebProfilerBundle/Resources/config/routing/profiler.xml'));

        $routes->add('/', 'kernel:indexAction', 'index');
    }

    protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader)
    {
        // load bundles' configuration
        $c->loadFromExtension('framework', [
            'secret' => '12345',
            'profiler' => null,
            'templating' => ['engines' => ['twig']],
        ]);

        $c->loadFromExtension('web_profiler', ['toolbar' => true]);

        // add configuration parameters
        $c->setParameter('mail_sender', 'user@example.com');

        // register services
        $c->register('app.markdown', 'AppBundle\\Service\\Parser\\Markdown');
    }

    public function indexAction()
    {
        return $this->container->get('templating')->renderResponse('index.html.twig');
    }
}

Creating single-file applications is not the main purpose of this microkernel. The real use-case is to create smaller Symfony applications, perhaps having just one services.yml file, one config.yml file per environment and the routing defined as annotations in regular controller classes. This is the full code needed to implement this use case:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// app/MicroKernel.php

// ...

class MicroKernel extends Kernel
{
    use MicroKernelTrait;

    public function registerBundles()
    {
        return array(
            new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),
            new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
            new Symfony\Bundle\TwigBundle\TwigBundle(),
            new AppBundle\AppBundle(),
        );
    }

    protected function configureRoutes(RouteCollectionBuilder $routes)
    {
        $routes->mount('/', $routes->import('@AppBundle/Controller', 'annotation'));
    }

    protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader)
    {
        $loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml');
        $loader->load(__DIR__.'/config/services.yml');
    }
}

And don't forget to update the front controller to use this new microkernel instead of the usual AppKernel:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// web/app.php
use Symfony\Component\HttpFoundation\Request;

$loader = require __DIR__.'/../app/autoload.php';
require_once __DIR__.'/../app/MicroKernel.php';

$app = new MicroKernel('prod', false);
$app->loadClassCache();

$app->handle(Request::createFromGlobals())->send();

So if you're choosing between a microframework or the full-stack framework, you have a new possibility. Now you can have both at the same time in the same application and without compromising any features.

Comments

Thanks for the article !

What questions should guide our choices to determine whether to use Silex (for instance) or Symfony as a microframework in a project ?
Nice addition, it's a good start :)
How about a micro-edition with this Micro Kernel already set up and only the minimal requirements to boot a Symfony application ?
I've made a simple demo repository with micro trait https://github.com/CawaKharkov/symfony-micro
Silex and Symfony MicroKernel are not related at all.

Silex is an implementation of a framework on top of the Symfony components (done in a very different way than Symfony, the full-stack framework; Pimple, ...).

Symfony MicroKernel is a "just" different way to **configure** the Symfony full-stack framework, but shares everything else (caching, bundles, ...).
fameworks :)
Great work! I'm sure this will be a boon for creating integrated microservices (an oxymoron? :D) on top of the full Framework.

Some API endpoints or other tasks that require little logic on the server spring to mind.
Symfony as a Microframework seems very interesting, especially the last note about using both the fullstack framework and microframework at the same time.

I have a Symfony App called Campus Discounts where I separate logic using requests such that GET requests are delivered promptly while POST requests are sent to a queue to be processed later. Depending on the POST action, an email might be sent, an API contacted, both or more. There are many bundles installed for these tasks. Is it my understanding that I can use the Symfony microframework to create a new app.php for GET requests removing unnecessary bundles that have nothing to do with displaying content thus having a leaner faster system but still have the bundles for another app_queue.php for processing code?

This is how I am seeing it so far and if so it excites me, not that my app is suffering from performance issues thanks to Blackfire :)
This is a great new interesting addition to Symfony.
@Don Omondi: That's absolutely accurate. But you can already create multiple kernels today. The MicroKernelTrait makes it a bit more *obvious* how to do it, but it's already possible. You *will* get more performance by doing this, but don't forget that having multiple kernels may add a little bit of complexity to your app.

Anyways, being able to create multiple kernels easily is one of the side benefits of the MicroKernelTrait that I hadn't even thought about until recently :).
JoliCode's Slack Secret Santa is a nice real world app using Symfony as a microframework in conjonction with the new autowiring feature of the Dependency Injection Component: https://github.com/jolicode/slack-secret-santa/blob/master/src/SantaKernel.php
Nice features. Very useful when a "light" implementation is needed with the flexibility to "At my signal, unleash hell" switching to a full Kernel configuration.
Although I'm just a little symfony2, and php developer (I started php just three months before I started to use symfony2 last year), I marvel on this new ! while I was recently dreaming how one day any symfony version will look like and I was imagining "our framework" like it just have php extensions so that the performance is like never before in any web framework and the world will know symfony (x) as web 3.0 technology !!!!
You may want to wrap the route loading for the profiler in an if-statement as you will get exception now when you are in the prod.
Great work! Nice features.. This can be very useful in most projects.
Great feature! This kills Silex which I also like, but this does not matter. No Silex for small projects anymore, Symfony rules! :-)
Inspired by Ryan's talk at SymfonyCon, I've set up Symfony as a microframework so you won't have to :)

https://github.com/ikoene/symfony-micro
IMHO Silex is the right choice for a backend with very little business logic. Take for example a light backend that connects some 3rd party or internal API with an Angular/React frontend. All it does is some minor "massaging" of the data, maybe adding a simple auth layer and multiplexing some API calls. The real work is done in the API being integrated. That API can BTW also be a file dumped into the file system.

Once you get more business logic, I would recommend to go to Symfony full stack.
One of the downsides of Silex is that you can't use Symfony bundles. So if you need functionality that is provided by bundles in Symfony, you have to find a solution if you use Silex (often more work).

Comments are closed.

To ensure that comments stay relevant, they are closed for old posts.