Skip to content

Added a new article about applications with multiple kernels #6840

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Dec 15, 2016
140 changes: 140 additions & 0 deletions request/multiple_kernels.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
.. index::
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should be in the configuration/ directory?

single: kernel, performance

How To Create Symfony Applications with Multiple Kernels
========================================================

In most Symfony applications, incoming requests are processed by the
``web/app.php`` front controller, which instantiates the ``app/AppKernel.php``
class to create the application kernel that loads the bundles and generates the
response.

This single kernel approach is a convenient default provided by the Symfony
Standard edition, but Symfony applications can define any number of kernels.
This is useful to execute the same application using a different configuration
and a different set of bundles for each kernel:

* An application that defines an API could create an ``ApiKernel`` to not have
to load all the bundles enabled in the regular web application. This will
improve the API performance;
* A bundle that doesn't allow multiple instances can define multiple
configurations in different files loaded by each kernel.

Adding a new Kernel to the Application
--------------------------------------

Creating a new kernel in a Symfony application is a three-step process:

1. Create a new front controller to load the new kernel;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is another way to do this (which is done on a BIG Symfony site I know of): keeping app.php and app_dev.php and using some URL matching to load different kernels. For example, if the URL starts with /admin, then load the AdminKernel, else AppKernel. I think it's worth mentioning both. So, what about:

A) Making step (1) actually step (3) (I think creating the kernel and hooking up the configuration makes sense to have first, then finally show how you can instantiate the now-created kernel)

B) Rename this step to Step 3) Executing the kernel from a front controller

C) Mention the if statement approach above (it could be mentioned first or second).

2. Create the new kernel class;
3. Define the configuration loaded by the new kernel.

The following example shows how to create a new kernel for the API of a given
Symfony application.

Step 1) Create a new Front Controller
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Instead of creating the new front controller from scratch, it's recommended to
duplicate the existing ``web/app_dev.php`` and ``web/app.php`` files. For
example, you can create ``web/api_dev.php`` and ``web/api.php`` (or
``web/api/app_dev.php`` and ``web/api/app.php`` depending on your server
configuration).

Then, update the code of the new front controllers to instantiate the new kernel
class instead of the usual ``AppKernel`` class::

// web/api.php
// ...
$kernel = new ApiKernel('prod', true);
Copy link
Member

@yceruto yceruto Aug 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the second parameter "debug" must be false here ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You guessed right. Fixed. Thanks.

// ...

// web/api_dev.php
// ...
$kernel = new ApiKernel('dev', true);
// ...

Step 2) Create the new Kernel Class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Now you need to define the ``ApiKernel`` class used by the new front controller.
The recommendation again is to duplicate the existing ``app/AppKernel.php`` file
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The easiest way to do this is by duplicating the existing...

and make the needed changes.

In this example, the changes of the new ``ApiKernel`` would be to load less
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this example, the ApiKernel will load less bundles than AppKernel. Be sure to also change
the location of the cache, logs and config files so they don't collide with the files
from AppKernel

bundles than ``AppKernel`` and to change the location of the cache, logs and
config files to not mess with the regular application::

// app/ApiKernel.php
<?php
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually don't have the <?php. If you do want it for some specific reason, the filename should probably be moved inside of it, so that the comment is in PHP. But probably, we should just remove <?php


use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;

class ApiKernel extends Kernel
{
public function registerBundles()
{
// load only the bundles strictly needed for the API...
}

public function getCacheDir()
{
return dirname(__DIR__).'/var/cache/api/'.$this->getEnvironment();
}

public function getLogDir()
{
return dirname(__DIR__).'/var/logs/api';
}

public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load($this->getRootDir().'/config/api/config_'.$this->getEnvironment().'.yml');
}
}

Step 3) Define the Kernel Configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Finally, define the configuration used by the application when it executes the
new API kernel. According to the previous code, this config must be defined in
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finally, define the configuration files that the new ApiKernel will load. According to the
above code, this config will live in the...

the ``app/config/api/`` directory.

The new configuration can be created from scratch when you load just a few
bundles, because it it will be very simple. Otherwise, duplicate the existing
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo "it it" ?

config files or better, import them and override the needed options:

.. code-block:: yaml

# app/config/api/config_dev.yml
imports:
- { resource: ../config_dev.yml }

# override option values ...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option is to share some configuration files, especially if both kernels use some of the same bundles that you want configured in the same ways. I'm haven't done this enough to settle on the best organization for this... but we could at least mention it. Perhaps a app/config/shared.yml file where we show just a little bit of config and mention how you could import this from the config.yml file of both kernels.

Adding more Kernels to the Application
--------------------------------------

If your application is very complex and you create several kernels, it's better
to store them on their own directories instead of messing with lots of files in
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

store them in their...

the default ``app/`` directory:

.. code-block:: text

project/
├─ app/
│ ├─ ...
│ ├─ config/
│ └─ AppKernel.php
├─ api/
│ ├─ ...
│ ├─ config/
│ └─ ApiKernel.php
├─ ...
└─ web/
├─ ...
├─ app.php
├─ app_dev.php
├─ api.php
└─ api_dev.php