Skip to content

Commit 17c2fc6

Browse files
committed
Merge branch '5.1' into 5.x
* 5.1: Update doctrine.rst Update multiple_kernels.rst Fixed DOCtor [Cache] Custom pool namespaces [#12802] Updated XML and PHP examples Security: How to Build a Login Form: sync with recent Maker Bundle changes Added PHP typehints to getting started guides Update deployment docs with new .env loading Update typehints Missing format parameter in a serialize call
2 parents 6896144 + 3ac74f0 commit 17c2fc6

22 files changed

+241
-109
lines changed

cache.rst

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,53 @@ with either :class:`Symfony\\Contracts\\Cache\\CacheInterface` or
330330
// ...
331331
}
332332

333+
.. tip::
334+
335+
If you need the namespace to be interoperable with a third-party app,
336+
you can take control over auto-generation by setting the ``namespace``
337+
attribute of the ``cache.pool`` service tag. For example, you can
338+
override the service definition of the adapter:
339+
340+
.. configuration-block::
341+
342+
.. code-block:: yaml
343+
344+
# config/services.yaml
345+
services:
346+
app.cache.adapter.redis:
347+
parent: 'cache.adapter.redis'
348+
tags:
349+
- { name: 'cache.pool', namespace: 'my_custom_namespace' }
350+
351+
.. code-block:: xml
352+
353+
<!-- config/services.xml -->
354+
<?xml version="1.0" encoding="UTF-8" ?>
355+
<container xmlns="http://symfony.com/schema/dic/services"
356+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
357+
xsi:schemaLocation="http://symfony.com/schema/dic/services
358+
https://symfony.com/schema/dic/services/services-1.0.xsd">
359+
360+
<services>
361+
<service id="app.cache.adapter.redis" parent="cache.adapter.redis">
362+
<tag name="cache.pool" namespace="my_custom_namespace"/>
363+
</service>
364+
</services>
365+
</container>
366+
367+
.. code-block:: php
368+
369+
// config/services.php
370+
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
371+
372+
return function(ContainerConfigurator $configurator) {
373+
$services = $configurator->services();
374+
375+
$services->set('app.cace.adapter.redis')
376+
->parent('cache.adapter.redis')
377+
->tag('cache.pool', ['namespace' => 'my_custom_namespace'])
378+
};
379+
333380
Custom Provider Options
334381
-----------------------
335382

components/asset.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,12 +200,12 @@ every day::
200200
$this->version = date('Ymd');
201201
}
202202

203-
public function getVersion($path)
203+
public function getVersion(string $path)
204204
{
205205
return $this->version;
206206
}
207207

208-
public function applyVersion($path)
208+
public function applyVersion(string $path)
209209
{
210210
return sprintf('%s?v=%s', $path, $this->getVersion($path));
211211
}

components/serializer.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,7 @@ defines a ``Person`` entity with a ``firstName`` property:
681681
This custom mapping is used to convert property names when serializing and
682682
deserializing objects::
683683

684-
$serialized = $serializer->serialize(new Person("Kévin"));
684+
$serialized = $serializer->serialize(new Person("Kévin"), 'json');
685685
// {"customer_name": "Kévin"}
686686

687687
Serializing Boolean Attributes
@@ -1537,7 +1537,7 @@ and ``BitBucketCodeRepository`` classes:
15371537
15381538
Once configured, the serializer uses the mapping to pick the correct class::
15391539

1540-
$serialized = $serializer->serialize(new GitHubCodeRepository());
1540+
$serialized = $serializer->serialize(new GitHubCodeRepository(), 'json');
15411541
// {"type": "github"}
15421542

15431543
$repository = $serializer->deserialize($serialized, CodeRepository::class, 'json');

configuration.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -753,12 +753,13 @@ use the ``getParameter()`` helper::
753753
namespace App\Controller;
754754

755755
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
756+
use Symfony\Component\HttpFoundation\Response;
756757

757758
class UserController extends AbstractController
758759
{
759760
// ...
760761

761-
public function index()
762+
public function index(): Response
762763
{
763764
$projectDir = $this->getParameter('kernel.project_dir');
764765
$adminEmail = $this->getParameter('app.admin_email');

configuration/env_var_processors.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,7 @@ create a class that implements
631631

632632
class LowercasingEnvVarProcessor implements EnvVarProcessorInterface
633633
{
634-
public function getEnv($prefix, $name, \Closure $getEnv)
634+
public function getEnv(string $prefix, string $name, \Closure $getEnv)
635635
{
636636
$env = $getEnv($name);
637637

configuration/multiple_kernels.rst

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -88,31 +88,50 @@ files so they don't collide with the files from ``src/Kernel.php``::
8888

8989
class ApiKernel extends Kernel
9090
{
91-
// ...
91+
use MicroKernelTrait;
9292

9393
public function registerBundles()
9494
{
95-
// load only the bundles strictly needed for the API...
95+
// load only the bundles strictly needed for the API
96+
$contents = require $this->getProjectDir().'/config/api_bundles.php';
97+
foreach ($contents as $class => $envs) {
98+
if ($envs[$this->environment] ?? $envs['all'] ?? false) {
99+
yield new $class();
100+
}
101+
}
102+
}
103+
104+
public function getProjectDir(): string
105+
{
106+
return \dirname(__DIR__);
96107
}
97108

98-
public function getCacheDir()
109+
public function getCacheDir(): string
99110
{
100-
return dirname(__DIR__).'/var/cache/api/'.$this->getEnvironment();
111+
return $this->getProjectDir().'/var/cache/api/'.$this->getEnvironment();
101112
}
102113

103-
public function getLogDir()
114+
public function getLogDir(): string
104115
{
105-
return dirname(__DIR__).'/var/log/api';
116+
return $this->getProjectDir().'/var/log/api';
106117
}
107118

108119
public function configureContainer(ContainerBuilder $container, LoaderInterface $loader)
109120
{
110-
// load only the config files strictly needed for the API
111-
$confDir = $this->getProjectDir().'/config';
112-
$loader->load($confDir.'/api/*'.self::CONFIG_EXTS, 'glob');
113-
if (is_dir($confDir.'/api/'.$this->environment)) {
114-
$loader->load($confDir.'/api/'.$this->environment.'/**/*'.self::CONFIG_EXTS, 'glob');
115-
}
121+
$container->addResource(new FileResource($this->getProjectDir().'/config/api_bundles.php'));
122+
$container->setParameter('container.dumper.inline_factories', true);
123+
$confDir = $this->getProjectDir().'/config/api';
124+
125+
$loader->load($confDir.'/{packages}/*'.self::CONFIG_EXTS, 'glob');
126+
$loader->load($confDir.'/{packages}/'.$this->environment.'/*'.self::CONFIG_EXTS, 'glob');
127+
$loader->load($confDir.'/{services}'.self::CONFIG_EXTS, 'glob');
128+
$loader->load($confDir.'/{services}_'.$this->environment.self::CONFIG_EXTS, 'glob');
129+
}
130+
131+
protected function configureRoutes(RouteCollectionBuilder $routes): void
132+
{
133+
$confDir = $this->getProjectDir().'/config/api';
134+
// ... load only the config routes strictly needed for the API
116135
}
117136
}
118137

controller.rst

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class::
3636
/**
3737
* @Route("/lucky/number/{max}", name="app_lucky_number")
3838
*/
39-
public function number($max)
39+
public function number(int $max): Response
4040
{
4141
$number = random_int(0, $max);
4242

@@ -134,7 +134,7 @@ and ``redirect()`` methods::
134134
use Symfony\Component\HttpFoundation\RedirectResponse;
135135

136136
// ...
137-
public function index()
137+
public function index(): RedirectResponse
138138
{
139139
// redirects to the "homepage" route
140140
return $this->redirectToRoute('homepage');
@@ -196,12 +196,13 @@ If you need a service in a controller, type-hint an argument with its class
196196
(or interface) name. Symfony will automatically pass you the service you need::
197197

198198
use Psr\Log\LoggerInterface;
199+
use Symfony\Component\HttpFoundation\Response;
199200
// ...
200201

201202
/**
202203
* @Route("/lucky/number/{max}")
203204
*/
204-
public function number($max, LoggerInterface $logger)
205+
public function number(int $max, LoggerInterface $logger): Response
205206
{
206207
$logger->info('We are logging!');
207208
// ...
@@ -322,10 +323,11 @@ Managing Errors and 404 Pages
322323
When things are not found, you should return a 404 response. To do this, throw a
323324
special type of exception::
324325

326+
use Symfony\Component\HttpFoundation\Response;
325327
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
326328

327329
// ...
328-
public function index()
330+
public function index(): Response
329331
{
330332
// retrieve the object from database
331333
$product = ...;
@@ -370,8 +372,10 @@ object. To access it in your controller, add it as an argument and
370372
**type-hint it with the Request class**::
371373

372374
use Symfony\Component\HttpFoundation\Request;
375+
use Symfony\Component\HttpFoundation\Response;
376+
// ...
373377

374-
public function index(Request $request, $firstName, $lastName)
378+
public function index(Request $request, string $firstName, string $lastName): Response
375379
{
376380
$page = $request->query->get('page', 1);
377381

@@ -401,9 +405,11 @@ Session storage and other configuration can be controlled under the
401405
To get the session, add an argument and type-hint it with
402406
:class:`Symfony\\Component\\HttpFoundation\\Session\\SessionInterface`::
403407

408+
use Symfony\Component\HttpFoundation\Response;
404409
use Symfony\Component\HttpFoundation\Session\SessionInterface;
410+
// ...
405411

406-
public function index(SessionInterface $session)
412+
public function index(SessionInterface $session): Response
407413
{
408414
// stores an attribute for reuse during a later user request
409415
$session->set('foo', 'bar');
@@ -413,6 +419,8 @@ To get the session, add an argument and type-hint it with
413419

414420
// uses a default value if the attribute doesn't exist
415421
$filters = $session->get('filters', []);
422+
423+
// ...
416424
}
417425

418426
Stored attributes remain in the session for the remainder of that user's session.
@@ -435,8 +443,10 @@ from the session automatically as soon as you retrieve them. This feature makes
435443
For example, imagine you're processing a :doc:`form </forms>` submission::
436444

437445
use Symfony\Component\HttpFoundation\Request;
446+
use Symfony\Component\HttpFoundation\Response;
447+
// ...
438448

439-
public function update(Request $request)
449+
public function update(Request $request): Response
440450
{
441451
// ...
442452

@@ -515,8 +525,9 @@ pass the ``Request`` object to any controller argument that is type-hinted with
515525
the ``Request`` class::
516526

517527
use Symfony\Component\HttpFoundation\Request;
528+
use Symfony\Component\HttpFoundation\Response;
518529

519-
public function index(Request $request)
530+
public function index(Request $request): Response
520531
{
521532
$request->isXmlHttpRequest(); // is it an Ajax request?
522533

@@ -572,7 +583,7 @@ To get the value of any :ref:`configuration parameter <configuration-parameters>
572583
from a controller, use the ``getParameter()`` helper method::
573584

574585
// ...
575-
public function index()
586+
public function index(): Response
576587
{
577588
$contentsDir = $this->getParameter('kernel.project_dir').'/contents';
578589
// ...
@@ -584,8 +595,10 @@ Returning JSON Response
584595
To return JSON from a controller, use the ``json()`` helper method. This returns a
585596
``JsonResponse`` object that encodes the data automatically::
586597

598+
use Symfony\Component\HttpFoundation\Response;
587599
// ...
588-
public function index()
600+
601+
public function index(): Response
589602
{
590603
// returns '{"username":"jane.doe"}' and sets the proper Content-Type header
591604
return $this->json(['username' => 'jane.doe']);
@@ -604,7 +617,10 @@ Streaming File Responses
604617
You can use the :method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController::file`
605618
helper to serve a file from inside a controller::
606619

607-
public function download()
620+
use Symfony\Component\HttpFoundation\Response;
621+
// ...
622+
623+
public function download(): Response
608624
{
609625
// send the file contents and force the browser to download it
610626
return $this->file('/path/to/some_file.pdf');
@@ -614,8 +630,9 @@ The ``file()`` helper provides some arguments to configure its behavior::
614630

615631
use Symfony\Component\HttpFoundation\File\File;
616632
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
633+
// ...
617634

618-
public function download()
635+
public function download(): Response
619636
{
620637
// load the file from the filesystem
621638
$file = new File('/path/to/some_file.pdf');

deployment.rst

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,21 +126,29 @@ While developing locally, you'll usually store these in ``.env`` and ``.env.loca
126126

127127
1. Create "real" environment variables. How you set environment variables, depends
128128
on your setup: they can be set at the command line, in your Nginx configuration,
129-
or via other methods provided by your hosting service.
129+
or via other methods provided by your hosting service;
130130

131-
2. Or, create a ``.env.local`` file like your local development (see note below)
131+
2. Or, create a ``.env.local`` file like your local development.
132132

133133
There is no significant advantage to either of the two options: use whatever is
134134
most natural in your hosting environment.
135135

136-
.. note::
136+
.. tip::
137+
138+
You might not want your application to process the ``.env.*`` files on
139+
every request. You can generate an optimized ``.env.local.php`` which
140+
overrides all other configuration files:
141+
142+
.. code-block:: terminal
143+
144+
$ composer dump-env prod
137145
138-
If you use the ``.env.*`` files on production, you may need to move your
139-
``symfony/dotenv`` dependency from ``require-dev`` to ``require`` in ``composer.json``:
146+
The generated file will contain all the configuration stored in ``.env``. If you
147+
want to rely only on environment variables, generate one without any values using:
140148

141149
.. code-block:: terminal
142150
143-
$ composer require symfony/dotenv
151+
$ composer dump-env prod --empty
144152
145153
C) Install/Update your Vendors
146154
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

doctrine.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -875,4 +875,4 @@ Learn more
875875
.. _`API Platform`: https://api-platform.com/docs/core/validation/
876876
.. _`PDO`: https://www.php.net/pdo
877877
.. _`available Doctrine extensions`: https://github.com/Atlantic18/DoctrineExtensions
878-
.. _`StofDoctrineExtensionsBundle`: https://github.com/antishov/StofDoctrineExtensionsBundle
878+
.. _`StofDoctrineExtensionsBundle`: https://github.com/stof/StofDoctrineExtensionsBundle

form/data_mappers.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ in your form type::
9898
/**
9999
* @param Color|null $viewData
100100
*/
101-
public function mapDataToForms($viewData, $forms)
101+
public function mapDataToForms($viewData, iterable $forms)
102102
{
103103
// there is no data yet, so nothing to prepopulate
104104
if (null === $viewData) {
@@ -119,7 +119,7 @@ in your form type::
119119
$forms['blue']->setData($viewData->getBlue());
120120
}
121121

122-
public function mapFormsToData($forms, &$viewData)
122+
public function mapFormsToData(iterable $forms, &$viewData)
123123
{
124124
/** @var FormInterface[] $forms */
125125
$forms = iterator_to_array($forms);

0 commit comments

Comments
 (0)