Skip to content

Commit 5330c43

Browse files
committed
feature #5899 Adding the MicroKernel article (weaverryan)
This PR was merged into the 2.8 branch. Discussion ---------- Adding the MicroKernel article | Q | A | ------------- | --- | Doc fix? | no | New docs? | yes | Applies to | 2.8+ | Fixed tickets | #5864 Here's the `MicroKernelTrait` article. Finished code behind this can be found here: https://github.com/weaverryan/docs-micro_kernel/tree/finished This shows the smallest example (single file) and an example that is appropriately large, with the WDT, annotation routes, Twig and a sensible directory structure (which shows off importing external resources, etc). With a few code comments, I think (hope) the code speaks for itself. Thanks! Commits ------- e59d351 tweaks thanks to WouterJ and javiereguiluz 80c637d adding the MicroKernel article
2 parents 5a361ee + e59d351 commit 5330c43

File tree

4 files changed

+331
-0
lines changed

4 files changed

+331
-0
lines changed

Diff for: book/installation.rst

+2
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ execute it as follows:
5454
c:\> move symfony c:\projects
5555
c:\projects\> php symfony
5656
57+
.. _installation-creating-the-app:
58+
5759
Creating the Symfony Application
5860
--------------------------------
5961

Diff for: cookbook/configuration/index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Configuration
55
:maxdepth: 2
66

77
environments
8+
micro-kernel-trait
89
override_dir_structure
910
using_parameters_in_dic
1011
front_controllers_and_kernel

Diff for: cookbook/configuration/micro-kernel-trait.rst

+327
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
Building your own Framework with the MicroKernelTrait
2+
=====================================================
3+
4+
A :ref:`traditional Symfony app <installation-creating-the-app>` contains a sensible
5+
directory structure, various configuration files and an ``AppKernel`` with several
6+
bundles already-registered. This is a fully-featured app that's ready to go.
7+
8+
But did you know, you can create a fully-functional Symfony application in as little
9+
as one file? This is possible thanks to the new
10+
:class:`Symfony\\Bundle\\FrameworkBundle\\Kernel\\MicroKernelTrait`. This allows
11+
you to start with a tiny application, and then add features and structure as you
12+
need to.
13+
14+
.. note::
15+
16+
The MicroKernelTrait requires PHP 5.4. However, there's nothing special about
17+
this trait. If you're using PHP 5.3, simply copy its methods into *your* kernel
18+
class to get the same functionality.
19+
20+
A Single-File Symfony Application
21+
---------------------------------
22+
23+
Start with a completely empty directory. Get ``symfony/symfony`` as a dependency
24+
via Composer:
25+
26+
.. code-block:: bash
27+
28+
$ composer require symfony/symfony
29+
30+
Next, create an ``index.php`` file that creates a kernel class and executes it::
31+
32+
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
33+
use Symfony\Component\Config\Loader\LoaderInterface;
34+
use Symfony\Component\DependencyInjection\ContainerBuilder;
35+
use Symfony\Component\HttpFoundation\JsonResponse;
36+
use Symfony\Component\HttpFoundation\Request;
37+
use Symfony\Component\HttpKernel\Kernel;
38+
use Symfony\Component\Routing\RouteCollectionBuilder;
39+
40+
// require Composer's autoloader
41+
require __DIR__.'/vendor/autoload.php';
42+
43+
class AppKernel extends Kernel
44+
{
45+
use MicroKernelTrait;
46+
47+
public function registerBundles()
48+
{
49+
return array(
50+
new Symfony\Bundle\FrameworkBundle\FrameworkBundle()
51+
);
52+
}
53+
54+
protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader)
55+
{
56+
// PHP equivalent of config.yml
57+
$c->loadFromExtension('framework', array(
58+
'secret' => 'S0ME_SECRET'
59+
));
60+
}
61+
62+
protected function configureRoutes(RouteCollectionBuilder $routes)
63+
{
64+
// kernel is a service that points to this class
65+
// optional 3rd argument is the route name
66+
$routes->add('/random/{limit}', 'kernel:randomAction');
67+
}
68+
69+
public function randomAction($limit)
70+
{
71+
return new JsonResponse(array(
72+
'number' => rand(0, $limit)
73+
));
74+
}
75+
}
76+
77+
$kernel = new AppKernel('dev', true);
78+
$request = Request::createFromGlobals();
79+
$response = $kernel->handle($request);
80+
$response->send();
81+
$kernel->terminate($request, $response);
82+
83+
That's it! To test it, you can start the built-in web server:
84+
85+
.. code-block:: bash
86+
87+
$ php -S localhost:8000
88+
89+
Then see the JSON response in your browser:
90+
91+
> http://localhost:8000/random/10
92+
93+
The Methods of a "Micro" Kernel
94+
-------------------------------
95+
96+
When you use the ``MicroKernelTrait``, your kernel needs to have exactly three methods
97+
that define your bundles, your services and your routes:
98+
99+
**registerBundles()**
100+
This is the same ``registerBundles()`` that you see in a normal kernel.
101+
102+
**configureContainer(ContainerBuilder $c, LoaderInterface $loader)**
103+
This methods builds and configures the container. In practice, you will use
104+
``loadFromExtension`` to configure different bundles (this is the equivalent
105+
of what you see in a normal ``config.yml`` file). You can also register services
106+
directly in PHP or load external configuration files (shown below).
107+
108+
**configureRoutes(RouteCollectionBuilder $routes)**
109+
Your job in this method is to add routes to the application. The ``RouteCollectionBuilder``
110+
is new in Symfony 2.8 and has methods that make adding routes in PHP more fun.
111+
You can also load external routing files (shown below).
112+
113+
114+
Advanced Example: Twig, Annotations and the Web Debug Toolbar
115+
-------------------------------------------------------------
116+
117+
The purpose of the ``MicroKernelTrait`` is *not* to have a single-file application.
118+
Instead, its goal to give you the power to choose your bundles and structure.
119+
120+
First, you'll probably want to put your PHP classes in an ``src/`` directory. Configure
121+
your ``composer.json`` file to load from there:
122+
123+
.. code-block:: json
124+
125+
{
126+
"require": {
127+
"...": "..."
128+
},
129+
"autoload": {
130+
"psr-4": {
131+
"": "src/"
132+
}
133+
}
134+
}
135+
136+
Now, suppose you want to use Twig and load routes via annotations. For annotation
137+
routing, you need SensioFrameworkExtraBundle. This comes with a normal Symfony project.
138+
But in this case, you need to download it:
139+
140+
.. code-block:: bash
141+
142+
$ composer require sensio/framework-extra-bundle
143+
144+
Instead of putting *everything* in ``index.php``, create a new ``app/AppKernel.php``
145+
to hold the kernel. Now it looks like this::
146+
147+
// app/AppKernel.php
148+
149+
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
150+
use Symfony\Component\Config\Loader\LoaderInterface;
151+
use Symfony\Component\DependencyInjection\ContainerBuilder;
152+
use Symfony\Component\HttpKernel\Kernel;
153+
use Symfony\Component\Routing\RouteCollectionBuilder;
154+
use Doctrine\Common\Annotations\AnnotationRegistry;
155+
156+
// require Composer's autoloader
157+
$loader = require __DIR__.'/../vendor/autoload.php';
158+
// auto-load annotations
159+
AnnotationRegistry::registerLoader(array($loader, 'loadClass'));
160+
161+
class AppKernel extends Kernel
162+
{
163+
use MicroKernelTrait;
164+
165+
public function registerBundles()
166+
{
167+
$bundles = array(
168+
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
169+
new Symfony\Bundle\TwigBundle\TwigBundle(),
170+
new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle()
171+
);
172+
173+
if ($this->getEnvironment() == 'dev') {
174+
$bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
175+
}
176+
177+
return $bundles;
178+
}
179+
180+
protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader)
181+
{
182+
$loader->load(__DIR__.'/config/config.yml');
183+
184+
// configure WebProfilerBundle only if the bundle is enabled
185+
if (isset($this->bundles['WebProfilerBundle'])) {
186+
$c->loadFromExtension('web_profiler', array(
187+
'toolbar' => true,
188+
'intercept_redirects' => false,
189+
));
190+
}
191+
}
192+
193+
protected function configureRoutes(RouteCollectionBuilder $routes)
194+
{
195+
// import the WebProfilerRoutes, only if the bundle is enabled
196+
if (isset($this->bundles['WebProfilerBundle'])) {
197+
$routes->mount('/_wdt', $routes->import('@WebProfilerBundle/Resources/config/routing/wdt.xml'));
198+
$routes->mount('/_profiler', $routes->import('@WebProfilerBundle/Resources/config/routing/profiler.xml'));
199+
}
200+
201+
// load the annotation routes
202+
$routes->mount(
203+
'/',
204+
$routes->import(__DIR__.'/../src/App/Controller/', 'annotation')
205+
);
206+
}
207+
}
208+
209+
Unlike the previous kernel, this loads an external ``app/config/config.yml`` file,
210+
because the configuration started to get bigger:
211+
212+
.. configuration-block::
213+
214+
.. code-block:: yaml
215+
216+
# app/config/config.yml
217+
framework:
218+
secret: S0ME_SECRET
219+
templating:
220+
engines: ['twig']
221+
profiler: { only_exceptions: false }
222+
223+
.. code-block:: xml
224+
225+
<!-- app/config/config.xml -->
226+
<?xml version="1.0" encoding="UTF-8" ?>
227+
<container xmlns="http://symfony.com/schema/dic/services"
228+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
229+
xmlns:framework="http://symfony.com/schema/dic/symfony"
230+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
231+
http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
232+
233+
<framework:config secret="S0ME_SECRET">
234+
<framework:templating>
235+
<framework:engine>twig</framework:engine>
236+
</framework:templating>
237+
<framework:profiler only-exceptions="false" />
238+
</framework:config>
239+
</container>
240+
241+
.. code-block:: php
242+
243+
// app/config/config.php
244+
$container->loadFromExtension('framework', array(
245+
'secret' => 'S0ME_SECRET',
246+
'templating' => array(
247+
'engines' => array('twig'),
248+
),
249+
'profiler' => array(
250+
'only_exceptions' => false,
251+
),
252+
));
253+
254+
This also loads annotation routes from an ``src/App/Controller/`` directory, which
255+
has one file in it::
256+
257+
// src/App/Controller/MicroController.php
258+
namespace App\Controller;
259+
260+
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
261+
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
262+
263+
class MicroController extends Controller
264+
{
265+
/**
266+
* @Route("/random/{limit}")
267+
*/
268+
public function randomAction($limit)
269+
{
270+
$number = rand(0, $limit);
271+
272+
return $this->render('micro/random.html.twig', array(
273+
'number' => $number
274+
));
275+
}
276+
}
277+
278+
Template files should live in the ``Resources/views`` directory of whatever directory
279+
your *kernel* lives in. Since ``AppKernel`` lives in ``app/``, this template lives
280+
at ``app/Resources/views/micro/random.html.twig``.
281+
282+
Finally, you need a front controller to boot and run the application. Create a
283+
``web/index.php``:
284+
285+
// web/index.php
286+
287+
use Symfony\Component\HttpFoundation\Request;
288+
289+
require __DIR__.'/../app/AppKernel.php';
290+
291+
$kernel = new AppKernel('dev', true);
292+
$request = Request::createFromGlobals();
293+
$response = $kernel->handle($request);
294+
$response->send();
295+
$kernel->terminate($request, $response);
296+
297+
That's it! This ``/random/10`` URL will work, Twig will render, and you'll even
298+
get the web debug toolbar to show up at the bottom. The final structure looks like
299+
this:
300+
301+
.. code-block:: text
302+
303+
your-project/
304+
├─ app/
305+
| ├─ AppKernel.php
306+
│ ├─ cache/
307+
│ ├─ config/
308+
│ ├─ logs/
309+
│ └─ Resources
310+
| └─ views
311+
| ├─ base.html.twig
312+
| └─ micro
313+
| └─ random.html.twig
314+
├─ src/
315+
│ └─ App
316+
| └─ Controller
317+
| └─ MicroController.php
318+
├─ vendor/
319+
│ └─ ...
320+
├─ web/
321+
| └─ index.php
322+
├─ composer.json
323+
└─ composer.lock
324+
325+
Hey, that looks a lot like a *traditional* Symfony application! You're right: the
326+
``MicroKernelTrait`` *is* still Symfony: but you can control your structure and
327+
features quite easily.

Diff for: cookbook/map.rst.inc

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
* :doc:`/cookbook/configuration/index`
3131

3232
* :doc:`/cookbook/configuration/environments`
33+
* :doc:`/cookbook/configuration/micro-kernel-trait`
3334
* :doc:`/cookbook/configuration/override_dir_structure`
3435
* :doc:`/cookbook/configuration/using_parameters_in_dic`
3536
* :doc:`/cookbook/configuration/front_controllers_and_kernel`

0 commit comments

Comments
 (0)