diff --git a/request/multiple_kernels.rst b/request/multiple_kernels.rst new file mode 100644 index 00000000000..fbd23a0b0fa --- /dev/null +++ b/request/multiple_kernels.rst @@ -0,0 +1,182 @@ +.. index:: + 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 handles the +request to generate 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. +Whereas :doc:`environments ` execute the same +application with different configurations, kernels can execute different parts +of the same application. + +These are some of the common use cases for creating multiple kernels: + +* An application that defines an API could define two kernels for performance + reasons. The first kernel would serve the regular application and the second + one would only respond to the API requests, loading less bundles and enabling + less features; +* A highly sensitive application could define two kernels. The first one would + only load the routes that match the parts of the application exposed publicly. + The second kernel would load the rest of the application and its access would + be protected by the web server; +* A micro-services oriented application could define several kernels to + enable/disable services selectively turning a traditional monolith application + into several micro-applications. + +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; +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 easier to +duplicate the existing ones. For example, create ``web/api_dev.php`` from +``web/app_dev.php`` and ``web/api.php`` from ``web/app.php``. + +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', false); + // ... + + // 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 easiest way to do this is by duplicating the existing ``app/AppKernel.php`` +file and make the needed changes. + +In this example, the ``ApiKernel`` will load less bundles than AppKernel. Be +sure to also change the location of the cache, logs and configuration files so +they don't collide with the files from ``AppKernel``:: + + // app/ApiKernel.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 files that the new ``ApiKernel`` will load. +According to the above code, this config will live in the ``app/config/api/`` +directory. + +The new configuration can be created from scratch when you load just a few +bundles, because it will be very simple. Otherwise, duplicate the existing +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 ... + +Executing Commands with a Different Kernel +------------------------------------------ + +The ``bin/console`` script used to run Symfony commands always uses the default +``AppKernel`` class to build the application and load the commands. If you need +to execute console commands using the new kernel, duplicate the ``bin/console`` +script and rename it (e.g. ``bin/api``). + +Then, replace the ``AppKernel`` instantiation by your own kernel instantiation +(e.g. ``ApiKernel``) and now you can execute commands using the new kernel +(e.g. ``php bin/api cache:clear``) Now you can use execute commands using the +new kernel. + +.. note:: + + The commands available for each console script (e.g. ``bin/console`` and + ``bin/api``) can differ because they depend on the bundles enabled for each + kernel, which could be different. + +Rendering Templates Defined in a Different Kernel +------------------------------------------------- + +If you follow the Symfony Best Practices, the templates of the default kernel +will be stored in ``app/Resources/views/``. Trying to render those templates in +a different kernel will result in a *There are no registered paths for +namespace "__main__"* error. + +In order to solve this issue, add the following configuration to your kernel: + +.. code-block:: yaml + + # api/config/config.yml + twig: + paths: + # allows to use app/Resources/views/ templates in the ApiKernel + "%kernel.root_dir%/../app/Resources/views": ~ + +Adding more Kernels to the Application +-------------------------------------- + +If your application is very complex and you create several kernels, it's better +to store them in their own directories instead of messing with lots of files in +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