Skip to content

Commit 9e9436b

Browse files
committed
Merge branch '2.8' into 3.1
* 2.8: (22 commits) [#6894] Adding link to Doctrine [#6857] Re-wording the section a bit [#6840] Adding note based on Stof's feedback Moving file - I think configuration is more appropriate Revert "Updated the contents for the new Symfony 3 dir structure" Updated the contents for the new Symfony 3 dir structure Remove "Symfony3 will use" Using lower case on "Form" Made a bunch of fixes recommended by Ryan Added a note about rendering templates from different kernels Added a new section about running commands under a different kernel Integrated improvement by javiereguiluz Explain what happens if `flush()` fails Update events.rst Added a new use case related to micro-services Removed a use case Reworded the use cases section Fixed typo Fixed an example code Fixed another syntax issue ...
2 parents 10b7771 + 4e5abbd commit 9e9436b

File tree

4 files changed

+226
-5
lines changed

4 files changed

+226
-5
lines changed

configuration/multiple_kernels.rst

+202
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
.. index::
2+
single: kernel, performance
3+
4+
How To Create Symfony Applications with Multiple Kernels
5+
========================================================
6+
7+
In most Symfony applications, incoming requests are processed by the
8+
``web/app.php`` front controller, which instantiates the ``app/AppKernel.php``
9+
class to create the application kernel that loads the bundles and handles the
10+
request to generate the response.
11+
12+
This single kernel approach is a convenient default provided by the Symfony
13+
Standard edition, but Symfony applications can define any number of kernels.
14+
Whereas :doc:`environments </configuration/environments>` execute the same
15+
application with different configurations, kernels can execute different parts
16+
of the same application.
17+
18+
These are some of the common use cases for creating multiple kernels:
19+
20+
* An application that defines an API could define two kernels for performance
21+
reasons. The first kernel would serve the regular application and the second
22+
one would only respond to the API requests, loading less bundles and enabling
23+
less features;
24+
* A highly sensitive application could define two kernels. The first one would
25+
only load the routes that match the parts of the application exposed publicly.
26+
The second kernel would load the rest of the application and its access would
27+
be protected by the web server;
28+
* A micro-services oriented application could define several kernels to
29+
enable/disable services selectively turning a traditional monolith application
30+
into several micro-applications.
31+
32+
Adding a new Kernel to the Application
33+
--------------------------------------
34+
35+
Creating a new kernel in a Symfony application is a three-step process:
36+
37+
1. Create a new front controller to load the new kernel;
38+
2. Create the new kernel class;
39+
3. Define the configuration loaded by the new kernel.
40+
41+
The following example shows how to create a new kernel for the API of a given
42+
Symfony application.
43+
44+
Step 1) Create a new Front Controller
45+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
46+
47+
Instead of creating the new front controller from scratch, it's easier to
48+
duplicate the existing ones. For example, create ``web/api_dev.php`` from
49+
``web/app_dev.php`` and ``web/api.php`` from ``web/app.php``.
50+
51+
Then, update the code of the new front controllers to instantiate the new kernel
52+
class instead of the usual ``AppKernel`` class::
53+
54+
// web/api.php
55+
// ...
56+
$kernel = new ApiKernel('prod', false);
57+
// ...
58+
59+
// web/api_dev.php
60+
// ...
61+
$kernel = new ApiKernel('dev', true);
62+
// ...
63+
64+
.. tip::
65+
66+
Another approach is to keep the existing front controller (e.g. ``app.php`` and
67+
``app_dev.php``), but add an ``if`` statement to load the different kernel based
68+
on the URL (e.g. if the URL starts with ``/api``, use the ``ApiKernel``).
69+
70+
Step 2) Create the new Kernel Class
71+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
72+
73+
Now you need to define the ``ApiKernel`` class used by the new front controller.
74+
The easiest way to do this is by duplicating the existing ``app/AppKernel.php``
75+
file and make the needed changes.
76+
77+
In this example, the ``ApiKernel`` will load less bundles than AppKernel. Be
78+
sure to also change the location of the cache, logs and configuration files so
79+
they don't collide with the files from ``AppKernel``::
80+
81+
// app/ApiKernel.php
82+
use Symfony\Component\HttpKernel\Kernel;
83+
use Symfony\Component\Config\Loader\LoaderInterface;
84+
85+
class ApiKernel extends Kernel
86+
{
87+
public function registerBundles()
88+
{
89+
// load only the bundles strictly needed for the API...
90+
}
91+
92+
public function getCacheDir()
93+
{
94+
return dirname(__DIR__).'/var/cache/api/'.$this->getEnvironment();
95+
}
96+
97+
public function getLogDir()
98+
{
99+
return dirname(__DIR__).'/var/logs/api';
100+
}
101+
102+
public function registerContainerConfiguration(LoaderInterface $loader)
103+
{
104+
$loader->load($this->getRootDir().'/config/api/config_'.$this->getEnvironment().'.yml');
105+
}
106+
}
107+
108+
In order for the autoloader to find your new ``ApiKernel``, make sure you add it
109+
to your ``composer.json`` autoload section:
110+
111+
{
112+
"...": "..."
113+
114+
"autoload": {
115+
"psr-4": { "": "src/" },
116+
"classmap": [ "app/AppKernel.php", "app/AppCache.php", "app/ApiKernel.php" ]
117+
}
118+
}
119+
120+
Then, run ``composer install`` to dump your new autoload config.
121+
122+
Step 3) Define the Kernel Configuration
123+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
124+
125+
Finally, define the configuration files that the new ``ApiKernel`` will load.
126+
According to the above code, this config will live in the ``app/config/api/``
127+
directory.
128+
129+
The new configuration can be created from scratch when you load just a few
130+
bundles, because it will be very simple. Otherwise, duplicate the existing
131+
config files or better, import them and override the needed options:
132+
133+
.. code-block:: yaml
134+
135+
# app/config/api/config_dev.yml
136+
imports:
137+
- { resource: ../config_dev.yml }
138+
139+
# override option values ...
140+
141+
Executing Commands with a Different Kernel
142+
------------------------------------------
143+
144+
The ``bin/console`` script used to run Symfony commands always uses the default
145+
``AppKernel`` class to build the application and load the commands. If you need
146+
to execute console commands using the new kernel, duplicate the ``bin/console``
147+
script and rename it (e.g. ``bin/api``).
148+
149+
Then, replace the ``AppKernel`` instantiation by your own kernel instantiation
150+
(e.g. ``ApiKernel``) and now you can execute commands using the new kernel
151+
(e.g. ``php bin/api cache:clear``) Now you can use execute commands using the
152+
new kernel.
153+
154+
.. note::
155+
156+
The commands available for each console script (e.g. ``bin/console`` and
157+
``bin/api``) can differ because they depend on the bundles enabled for each
158+
kernel, which could be different.
159+
160+
Rendering Templates Defined in a Different Kernel
161+
-------------------------------------------------
162+
163+
If you follow the Symfony Best Practices, the templates of the default kernel
164+
will be stored in ``app/Resources/views/``. Trying to render those templates in
165+
a different kernel will result in a *There are no registered paths for
166+
namespace "__main__"* error.
167+
168+
In order to solve this issue, add the following configuration to your kernel:
169+
170+
.. code-block:: yaml
171+
172+
# api/config/config.yml
173+
twig:
174+
paths:
175+
# allows to use app/Resources/views/ templates in the ApiKernel
176+
"%kernel.root_dir%/../app/Resources/views": ~
177+
178+
Adding more Kernels to the Application
179+
--------------------------------------
180+
181+
If your application is very complex and you create several kernels, it's better
182+
to store them in their own directories instead of messing with lots of files in
183+
the default ``app/`` directory:
184+
185+
.. code-block:: text
186+
187+
project/
188+
├─ app/
189+
│ ├─ ...
190+
│ ├─ config/
191+
│ └─ AppKernel.php
192+
├─ api/
193+
│ ├─ ...
194+
│ ├─ config/
195+
│ └─ ApiKernel.php
196+
├─ ...
197+
└─ web/
198+
├─ ...
199+
├─ app.php
200+
├─ app_dev.php
201+
├─ api.php
202+
└─ api_dev.php

doctrine.rst

+6
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,11 @@ Take a look at the previous example in more detail:
600600
``Product`` objects and then subsequently call ``flush()``, Doctrine will
601601
execute 100 ``INSERT`` queries using a single prepared statement object.
602602

603+
.. note::
604+
605+
If the ``flush()`` call fails, a ``Doctrine\ORM\ORMException`` exception
606+
is thrown. See `Transactions and Concurrency`_.
607+
603608
Whether creating or updating objects, the workflow is always the same. In
604609
the next section, you'll see how Doctrine is smart enough to automatically
605610
issue an ``UPDATE`` query if the entity already exists in the database.
@@ -916,3 +921,4 @@ Learn more
916921
.. _`DoctrineFixturesBundle`: https://symfony.com/doc/current/bundles/DoctrineFixturesBundle/index.html
917922
.. _`FrameworkExtraBundle documentation`: https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html
918923
.. _`newer utf8mb4 character set`: https://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html
924+
.. _`Transactions and Concurrency`: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/transactions-and-concurrency.html

form/form_customization.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ the base block by using the ``parent()`` Twig function:
443443

444444
.. code-block:: html+twig
445445

446-
{# app/Resources/views/Form/fields.html.twig #}
446+
{# app/Resources/views/form/fields.html.twig #}
447447
{% extends 'form_div_layout.html.twig' %}
448448

449449
{% block integer_widget %}

reference/events.rst

+17-4
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,8 @@ and set a new ``Exception`` object, or do nothing::
241241

242242
.. note::
243243

244-
As Symfony ensures that the Response status code is set to the most
245-
appropriate one depending on the exception, setting the status on the
246-
response won't work. If you want to overwrite the status code (which you
247-
should not without a good reason), set the ``X-Status-Code`` header::
244+
If you want to overwrite the status code (which you should do not without a good
245+
reason), set the ``X-Status-Code`` header::
248246

249247
$response = new Response(
250248
'Error',
@@ -254,6 +252,21 @@ and set a new ``Exception`` object, or do nothing::
254252
)
255253
);
256254

255+
If you do **not** set the ``X-Status-Code`` header, then Symfony uses the following
256+
logic to determine the status code:
257+
258+
* If :method:`Symfony\\Component\\HttpFoundation\\Response::isClientError`,
259+
:method:`Symfony\\Component\\HttpFoundation\\Response::isServerError` or
260+
:method:`Symfony\\Component\\HttpFoundation\\Response::isRedirect` is true,
261+
then the status code on your ``Response`` object is used;
262+
263+
* If the original exception implements
264+
:class:`Symfony\\Component\\HttpKernel\\Exception\\HttpExceptionInterface`,
265+
then ``getStatusCode()`` is called on the exception and used (the headers
266+
from ``getHeaders()`` are also added);
267+
268+
* If both of the above aren't true, then a 500 status code is used.
269+
257270
.. seealso::
258271

259272
Read more on the :ref:`kernel.exception event <component-http-kernel-kernel-exception>`.

0 commit comments

Comments
 (0)