8000 feature #7807 Updates to DI config for 3.3 (weaverryan, GuilhemN) · symfony/symfony-docs@cbedd79 · GitHub
[go: up one dir, main page]

Skip to content

Commit cbedd79

Browse files
committed
feature #7807 Updates to DI config for 3.3 (weaverryan, GuilhemN)
This PR was merged into the master branch. Discussion ---------- Updates to DI config for 3.3 Hi guys! WIP changes the new DI changes in 3.3! Woohoo! Some notes for myself: This relates to, oh, just these 10+ issues :). Assume they will all be closed by this one PR - before merge, if any of them aren't covered, I'll remove them. TODOS later (some might already be done) - update to use `debug:container --types` (symfony/symfony#22624) - update all other documents for possible changes for autowiring and autoconfigure - new page for existing Symfony users to explain the changes - update autowire section to talk about using aliases - document instanceof and also the ability to add configuration to the PSR4 loader - some links in the controller go to the API docs of `Controller`. But this is wrong, the methods now live in `ControllerTrait`... but the API docs for traits is basically broken: http://api.symfony.com/master/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.html - how should we pass a parameter to a controller? - do Twig extensions still need to be public? If so, the example in `service_container` about autoconfigure is still not quite right Definitely included in this PR * #7544 * #7482 * #7339 * #7672 Not included in this PR (but related to DI changes) * #7329 * #7782 * #7777 * #7706 * #7608 * #7538 * #7441 * #7255 * ~~#7041~~ * ~~#7445~~ * ~~#7444~~ * ~~#7436~~ Commits ------- 22adfbd removing duplicate target 12c4944 Tweaks after amazing review from @GuilhemN and @xabbuh cac3c6c Merge remote-tracking branch 'origin/master' into di-3.3-changes 2229fd3 Merge remote-tracking branch 'origin/master' into di-3.3-changes 5452c61 Adding section about public: false ee27765 Adding versionadded bc7088d Merge remote-tracking branch 'origin/di-3.3-changes' into di-3.3-changes 443aec2 Merge pull request #7857 from GuilhemN/patch-1 89e12de bad link 6de83e2 fixing build problem 759e9b2 last tweaks from feedback 45500b3 Adding details and usages of fetching the service as a controller arg 70178d1 adding note about autoconfigure 6e6ed94 more tweaks 0e48bd8 [WIP] Updates to DI config for 3.3 9ab27f0 Add xml files 2636bea bad link c45daf4 fixing build problem 9e84572 last tweaks from feedback 049df7d Adding details and usages of fetching the service as a controller arg 105801c adding note about autoconfigure 2d11347 more tweaks 8433fc1 [WIP] Updates to DI config for 3.3
2 parents a9f975b + 22adfbd commit cbedd79

File tree

6 files changed

+705
-217
lines changed

6 files changed

+705
-217
lines changed

controller.rst

Lines changed: 137 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -116,29 +116,15 @@ For more information on routing, see :doc:`/routing`.
116116
.. index::
117117
single: Controller; Base controller class
118118

119-
.. _anchor-name:
120-
:ref:`The Base Controller Classes & Services <the-base-controller-class-services>`
119+
.. _the-base-controller-class-services:
121120

122121
The Base Controller Classes & Services
123122
--------------------------------------
124123

125124
For convenience, Symfony comes with two optional base
126125
:class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller` and
127126
:class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController`
128-
classes.
129-
If you extend one or the other, this won't change anything about how your
130-
controller works, but you'll get access to a number of **helper methods**.
131-
132-
The base ``Controller`` also allows you to access th 8000 e **service container** (see :ref:`controller-accessing-services`): an
133-
array-like object that gives you access to every useful object in the
134-
system. These useful objects are called **services**, and Symfony ships
135-
with a service object that can render Twig templates, another that can
136-
log messages and many more.
137-
138-
On the other hand, the ``AbstractController`` prevents you from accessing the
139-
**service container**. When you need an external dependency, this forces you to
140-
write a code more robust as you have to explicitly define your dependencies by
141-
using :doc:`the controller as a service </controller/service>`.
127+
classes. You can extend either to get access to a number of `helper methods`_.
142128

143129
Add the ``use`` statement atop the ``Controller`` class and then modify
144130
``LuckyController`` to extend it::
@@ -153,11 +139,19 @@ Add the ``use`` statement atop the ``Controller`` class and then modify
153139
// ...
154140
}
155141

156-
Helper methods are just shortcuts to using core Symfony functionality
157-
that's available to you with or without the use of the base
158-
controller classes. A great way to see the core functionality in
159-
action is to look in the
160-
:class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller` class.
142+
That's it! You now have access to methods like :ref:`$this->render() <controller-rendering-templates>`
143+
and many others that you'll learn about next.
144+
145+
.. tip::
146+
147+
You can extend either ``Controller`` or ``AbstractController``. The difference
148+
is that when you extend ``AbstractController``, you can't access services directly
149+
via ``$this->get()`` or ``$this->container->get()``. This forces you to write
150+
more robust code to access services. But if you *do* need direct access to the
151+
container, using ``Controller`` is fine.
152+
153+
.. versionadded:: 3.3
154+
The ``AbstractController`` class was added in Symfony 3.3.
161155

162156
.. index::
163157
single: Controller; Redirecting
@@ -244,15 +238,121 @@ The Symfony templating system and Twig are explained more in the
244238

245239
.. _controller-accessing-services:
246240

247-
Accessing Other Services
248-
~~~~~~~~~~~~~~~~~~~~~~~~
241+
Fetching Services as Controller Arguments
242+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
243+
244+
.. versionadded:: 3.3
245+
The ability to type-hint a controller argument in order to receive a service
246+
was added in Symfony 3.3.
247+
248+
Symfony comes *packed* with a lot of useful objects, called :doc:`services </service_container>`.
249+
These are used for rendering templates, sending emails, querying the database and
250+
any other "work" you can think of.
251+
252+
If you need a service in a controller, just type-hint an argument with its class
253+
(or interface) name. Symfony will automatically pass you the service you need::
254+
255+
use Psr\Log\LoggerInterface
256+
// ...
257+
258+
/**
259+
* @Route("/lucky/number/{max}")
260+
*/
261+
public function numberAction($max, LoggerInterface $logger)
262+
{
263+
$logger->info('We are logging!');
264+
// ...
265+
}
266+
267+
Awesome!
268+
269+
What other services can you type-hint? To see them, use the ``debug:container`` console
270+
command:
271+
272+
.. code-block:: terminal
273+
274+
$ php bin/console debug:container --types
249275
250-
Symfony comes packed with a lot of useful objects, called *services*. These
251-
are used for rendering templates, sending emails, querying the database and
252-
any other "work" you can think of. When you install a new bundle, it probably
253-
brings in even *more* services.
276+
If you need control over the *exact* value of an argument, you can override your
277+
controller's service config:
254278

255-
When extending the base ``Controller`` class, you can access any Symfony service
279+
.. configuration-block::
280+
281+
.. code-block:: yaml
282+
283+
# app/config/services.yml
284+
services:
285+
# ...
286+
287+
# explicitly configure the service
288+
AppBundle\Controller\LuckyController:
289+
public: true
290+
tags:
291+
# add multiple tags to controller multiple args
292+
- name: controller.service_arguments
293+
action: numberAction
294+
argument: logger
295+
# pass this specific service id
296+
id: monolog.logger.doctrine
297+
298+
.. code-block:: xml
299+
300+
<!-- app/config/services.xml -->
301+
<?xml version="1.0" encoding="UTF-8" ?>
302+
<container xmlns="http://symfony.com/schema/dic/services"
303+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
304+
xsi:schemaLocation="http://symfony.com/schema/dic/services
305+
http://symfony.com/schema/dic/services/services-1.0.xsd">
306+
307+
<services>
308+
<!-- ... -->
309+
310+
<!-- Explicitly configure the service -->
311+
<service id="AppBundle\Controller\LuckyController" public="true">
312+
<tag
313+
name="controller.service_arguments"
314+
action="numberAction"
315+
argument="logger"
316+
id="monolog.logger.doctrine"
317+
/>
318+
</service>
319+
</services>
320+
</container>
321+
322+
.. code-block:: php
323+
324+
// app/config/services.php
325+
use AppBundle\Controller\LuckyController;
326+
327+
$container->register(LuckyController::class)
328+
->setPublic(true)
329+
->addTag('controller.service_arguments', [
330+
'action' => 'numberAction',
331+
'argument' => 'logger',
332+
'id' => 'monolog.logger.doctrine',
333+
])
334+
;
335+
336+
You can of course also use normal :ref:`constructor injection <services-constructor-injection>`
337+
in your controllers.
338+
339+
For more information about services, see the :doc:`/service_container` article.
340+
341+
.. note::
342+
If this isn't working, make sure your controller is registered as a service,
343+
is :ref:`autoconfigured <services-autoconfigure>` and extends either
344+
:class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller` or
345+
:class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController`. Or,
346+
you can tag your service manually with ``controller.service_arguments``. All
347+
of this is done for you in a fresh Symfony install.
348+
349+
.. _accessing-other-services:
350+
.. _controller-access-services-directly:
351+
352+
Accessing the Container Directly
353+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
354+
355+
If you extend the base ``Controller`` class, you can access any Symfony service
256356
via the :method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::get`
257357
method. Here are several common services you might need::
258358

@@ -262,23 +362,17 @@ method. Here are several common services you might need::
262362

263363
$mailer = $this->get('mailer');
264364

265-
What other services exist? To list all services, use the ``debug:container``
266-
console command:
267-
268-
.. code-block:: terminal
365+
// you can also fetch parameters
366+
$someParameter = $this->getParameter('some_parameter');
269367

270-
$ php bin/console debug:container
368+
If you receive an eror like:
271369

272-
For more information, see the :doc:`/service_container` article.
273-
274-
.. tip::
370+
.. code-block:: text
275371
276-
To get a :ref:`container configuration parameter <config-parameter-intro>`,
277-
use the
278-
:method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::getParameter`
279-
method::
372+
You have requested a non-existent service "my_service_id"
280373
281-
$from = $this->getParameter('app.mailer.from');
374+
Check to make sure the service exists (use :ref:`debug:container <container-debug-container>`)
375+
and that it's :ref:`public <container-public>`.
282376

283377
.. index::
284378
single: Controller; Managing errors
@@ -355,7 +449,6 @@ Symfony provides a nice session object that you can use to store information
355449
about the user between requests. By default, Symfony stores the attributes in a
356450
cookie by using native PHP sessions.
357451

358-
359452
.. versionadded:: 3.3
360453
The ability to request a ``Session`` instance in controllers was introduced
361454
in Symfony 3.3.
@@ -418,20 +511,6 @@ For example, imagine you're processing a :doc:`form </forms>` submission::
418511
return $this->render(...);
419512
}
420513

421-
.. tip::
422-
423-
As a developer, you might prefer not to extend the ``Controller``. To
424-
use the flash message functionality, you can request the flash bag from
425-
the :class:`Symfony\\Component\\HttpFoundation\\Session\\Session`::
426-
427-
use Symfony\Component\HttpFoundation\Session\Session;
428-
429-
public function indexAction(Session $session)
430-
{
431-
// getFlashBag is not available in the SessionInterface and requires the Session
432-
$flashBag = $session->getFlashBag();
433-
}
434-
435514
After processing the request, the controller sets a flash message in the session
436515
and then redirects. The message key (``notice`` in this example) can be anything:
437516
you'll use this key to retrieve the message.
@@ -636,12 +715,7 @@ and it's a PHP function where you can do anything in order to return the
636715
final ``Response`` object that will be returned to the user.
637716

638717
To make life easier, you'll probably extend the base ``Controller`` class because
639-
this gives two things:
640-
641-
A) Shortcut methods (like ``render()`` and ``redirectToRoute()``);
642-
643-
B) Access to *all* of the useful objects (services) in the system via the
644-
:ref:`get() <controller-accessing-services>` method.
718+
this gives access to shortcut methods (like ``render()`` and ``redirectToRoute()``).
645719

646720
In other articles, you'll learn how to use specific services from inside your controller
647721
that will h 10000 elp you persist and fetch objects from a database, process form submissions,
@@ -666,4 +740,5 @@ Learn more about Controllers
666740

667741
controller/*
668742

743+
.. _`helper methods`: https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php
669744
.. _`unvalidated redirects security vulnerability`: https://www.owasp.org/index.php/Open_redirect

doctrine.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,7 @@ a controller, this is pretty easy. Add the following method to the
548548
// ...
549549
use AppBundle\Entity\Product;
550550
use Symfony\Component\HttpFoundation\Response;
551+
use Doctrine\ORM\EntityManagerInterface;
551552

552553
// ...
553554
public function createAction()
@@ -568,6 +569,12 @@ a controller, this is pretty easy. Add the following method to the
568569
return new Response('Saved new product with id '.$product->getId());
569570
}
570571

572+
// you can also receive the $em as an argument
573+
public function editAction(EntityManagerInterface $em)
574+
{
575+
// ...
576+
}
577+
571578
.. note::
572579

573580
If you're following along with this example, you'll need to create a

email.rst

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ The Swift Mailer library works by creating, configuring and then sending
100100
of the message and is accessible via the ``mailer`` service. Overall, sending
101101
an email is pretty straightforward::
102102

103-
public function indexAction($name)
103+
public function indexAction($name, \Swift_Mailer $mailer)
104104
{
105105
$message = \Swift_Message::newInstance()
106106
->setSubject('Hello Email')
@@ -125,7 +125,11 @@ an email is pretty straightforward::
125125
)
126126
*/
127127
;
128-
$this->get('mailer')->send($message);
128+
129+
$mailer->send($message);
130+
131+
// or, you can also fetch the mailer service this way
132+
// $this->get('mailer')->send($message);
129133

130134
return $this->render(...);
131135
}

logging.rst

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@ Logging a Message
1010
To log a message, fetch the ``logger`` service from the container in
1111
your controller::
1212

13-
public function indexAction()
13+
use Psr\Log\LoggerInterface;
14+
15+
public function indexAction(LoggerInterface $logger)
1416
{
15-
$logger = $this->get('logger');
17+
// alternative way of getting the logger
18+
// $logger = $this->get('logger');
19+
1620
$logger->info('I just got the logger');
1721
$logger->error('An error occurred');
1822

0 commit comments

Comments
 (0)
0