Building your own Framework with the MicroKernelTrait
Warning: You are browsing the documentation for Symfony 2.x, which is no longer maintained.
Read the updated version of this page for Symfony 7.1 (the current stable version).
A traditional Symfony app contains a sensible
directory structure, various configuration files and an AppKernel
with several
bundles already-registered. This is a fully-featured app that's ready to go.
But did you know, you can create a fully-functional Symfony application in as little as one file? This is possible thanks to the new MicroKernelTrait. This allows you to start with a tiny application, and then add features and structure as you need to.
Note
The MicroKernelTrait requires PHP 5.4. However, there's nothing special about this trait. If you're using PHP 5.3, simply copy its methods into your kernel class to get the same functionality.
A Single-File Symfony Application
Start with a completely empty directory. Get symfony/symfony
as a dependency
via Composer:
1
$ composer require symfony/symfony
Next, create an index.php
file that creates a kernel class and executes it:
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
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Routing\RouteCollectionBuilder;
// require Composer's autoloader
require __DIR__.'/vendor/autoload.php';
class AppKernel extends Kernel
{
use MicroKernelTrait;
public function registerBundles()
{
return array(
new Symfony\Bundle\FrameworkBundle\FrameworkBundle()
);
}
protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader)
{
// PHP equivalent of config.yml
$c->loadFromExtension('framework', array(
'secret' => 'S0ME_SECRET'
));
}
protected function configureRoutes(RouteCollectionBuilder $routes)
{
// kernel is a service that points to this class
// optional 3rd argument is the route name
$routes->add('/random/{limit}', 'kernel:randomAction');
}
public function randomAction($limit)
{
return new JsonResponse(array(
'number' => rand(0, $limit)
));
}
}
$kernel = new AppKernel('dev', true);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
That's it! To test it, you can start the built-in web server:
1
$ php -S localhost:8000
Then see the JSON response in your browser:
The Methods of a "Micro" Kernel
When you use the MicroKernelTrait
, your kernel needs to have exactly three methods
that define your bundles, your services and your routes:
- registerBundles()
-
This is the same
registerBundles()
that you see in a normal kernel. - configureContainer(ContainerBuilder $c, LoaderInterface $loader)
-
This method builds and configures the container. In practice, you will use
loadFromExtension
to configure different bundles (this is the equivalent of what you see in a normalconfig.yml
file). You can also register services directly in PHP or load external configuration files (shown below). - configureRoutes(RouteCollectionBuilder $routes)
-
Your job in this method is to add routes to the application. The
RouteCollectionBuilder
is new in Symfony 2.8 and has methods that make adding routes in PHP more fun. You can also load external routing files (shown below).
Advanced Example: Twig, Annotations and the Web Debug Toolbar
The purpose of the MicroKernelTrait
is not to have a single-file application.
Instead, its goal to give you the power to choose your bundles and structure.
First, you'll probably want to put your PHP classes in an src/
directory. Configure
your composer.json
file to load from there:
1 2 3 4 5 6 7 8 9 10
{
"require": {
"...": "..."
},
"autoload": {
"psr-4": {
"": "src/"
}
}
}
Now, suppose you want to use Twig and load routes via annotations. For annotation routing, you need SensioFrameworkExtraBundle. This comes with a normal Symfony project. But in this case, you need to download it:
1
$ composer require sensio/framework-extra-bundle
Instead of putting everything in index.php
, create a new app/AppKernel.php
to hold the kernel. Now it 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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
// app/AppKernel.php
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Routing\RouteCollectionBuilder;
use Doctrine\Common\Annotations\AnnotationRegistry;
// require Composer's autoloader
$loader = require __DIR__.'/../vendor/autoload.php';
// auto-load annotations
AnnotationRegistry::registerLoader(array($loader, 'loadClass'));
class AppKernel extends Kernel
{
use MicroKernelTrait;
public function registerBundles()
{
$bundles = array(
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Symfony\Bundle\TwigBundle\TwigBundle(),
new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle()
);
if ($this->getEnvironment() == 'dev') {
$bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
}
return $bundles;
}
protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader)
{
$loader->load(__DIR__.'/config/config.yml');
// configure WebProfilerBundle only if the bundle is enabled
if (isset($this->bundles['WebProfilerBundle'])) {
$c->loadFromExtension('web_profiler', array(
'toolbar' => true,
'intercept_redirects' => false,
));
}
}
protected function configureRoutes(RouteCollectionBuilder $routes)
{
// import the WebProfilerRoutes, only if the bundle is enabled
if (isset($this->bundles['WebProfilerBundle'])) {
$routes->import('@WebProfilerBundle/Resources/config/routing/wdt.xml', '/_wdt');
$routes->import('@WebProfilerBundle/Resources/config/routing/profiler.xml', '/_profiler');
}
// load the annotation routes
$routes->import(__DIR__.'/../src/App/Controller/', '/', 'annotation');
}
}
Unlike the previous kernel, this loads an external app/config/config.yml
file,
because the configuration started to get bigger:
1 2 3 4 5 6
# app/config/config.yml
framework:
secret: S0ME_SECRET
templating:
engines: ['twig']
profiler: { only_exceptions: false }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:framework="http://symfony.com/schema/dic/symfony"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
<framework:config secret="S0ME_SECRET">
<framework:templating>
<framework:engine>twig</framework:engine>
</framework:templating>
<framework:profiler only-exceptions="false" />
</framework:config>
</container>
1 2 3 4 5 6 7 8 9 10
// app/config/config.php
$container->loadFromExtension('framework', array(
'secret' => 'S0ME_SECRET',
'templating' => array(
'engines' => array('twig'),
),
'profiler' => array(
'only_exceptions' => false,
),
));
This also loads annotation routes from an src/App/Controller/
directory, which
has one file in it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
// src/App/Controller/MicroController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
class MicroController extends Controller
{
/**
* @Route("/random/{limit}")
*/
public function randomAction($limit)
{
$number = rand(0, $limit);
return $this->render('micro/random.html.twig', array(
'number' => $number
));
}
}
Template files should live in the Resources/views
directory of whatever directory
your kernel lives in. Since AppKernel
lives in app/
, this template lives
at app/Resources/views/micro/random.html.twig
:
1 2 3 4 5 6 7 8 9 10
<!-- app/Resources/views/micro/random.html.twig -->
<!DOCTYPE html>
<html>
<head>
<title>Random action</title>
</head>
<body>
<p>{{ number }}</p>
</body>
</html>
Finally, you need a front controller to boot and run the application. Create a
web/index.php
:
1 2 3 4 5 6 7 8 9 10 11
// web/index.php
use Symfony\Component\HttpFoundation\Request;
require __DIR__.'/../app/AppKernel.php';
$kernel = new AppKernel('dev', true);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
That's it! This /random/10
URL will work, Twig will render, and you'll even
get the web debug toolbar to show up at the bottom. The final structure looks like
this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
your-project/
├─ app/
| ├─ AppKernel.php
│ ├─ cache/
│ ├─ config/
│ ├─ logs/
│ └─ Resources
| └─ views
| └─ micro
| └─ random.html.twig
├─ src/
│ └─ App
| └─ Controller
| └─ MicroController.php
├─ vendor/
│ └─ ...
├─ web/
| └─ index.php
├─ composer.json
└─ composer.lock
As before you can use PHP built-in server:
1 2
cd web/
$ php -S localhost:8000
Then see webpage in browser:
Hey, that looks a lot like a traditional Symfony application! You're right: the
MicroKernelTrait
is still Symfony: but you can control your structure and
features quite easily.