-
-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Updates to DI config for 3.3 #7807
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
Changes from 20 commits
8433fc1
2d11347
105801c
049df7d
9e84572
c45daf4
2636bea
9ab27f0
0e48bd8
6e6ed94
70178d1
45500b3
759e9b2
6de83e2
89e12de
443aec2
bc7088d
ee27765
5452c61
2229fd3
cac3c6c
12c4944
22adfbd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -116,29 +116,15 @@ For more information on routing, see :doc:`/routing`. | |
.. index:: | ||
single: Controller; Base controller class | ||
|
||
.. _anchor-name: | ||
:ref:`The Base Controller Classes & Services <the-base-controller-class-services>` | ||
.. _the-base-controller-class-services: | ||
|
||
The Base Controller Classes & Services | ||
-------------------------------------- | ||
|
||
For convenience, Symfony comes with two optional base | ||
:class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller` and | ||
:class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController` | ||
classes. | ||
If you extend one or the other, this won't change anything about how your | ||
controller works, but you'll get access to a number of **helper methods**. | ||
|
||
The base ``Controller`` also allows you to access the **service container** (see :ref:`controller-accessing-services`): an | ||
array-like object that gives you access to every useful object in the | ||
system. These useful objects are called **services**, and Symfony ships | ||
with a service object that can render Twig templates, another that can | ||
log messages and many more. | ||
|
||
On the other hand, the ``AbstractController`` prevents you from accessing the | ||
**service container**. When you need an external dependency, this forces you to | ||
write a code more robust as you have to explicitly define your dependencies by | ||
using :doc:`the controller as a service </controller/service>`. | ||
classes. You can extend either to get access to a number of `helper methods`_. | ||
|
||
Add the ``use`` statement atop the ``Controller`` class and then modify | ||
``LuckyController`` to extend it:: | ||
|
@@ -153,11 +139,18 @@ Add the ``use`` statement atop the ``Controller`` class and then modify | |
// ... | ||
} | ||
|
||
Helper methods are just shortcuts to using core Symfony functionality | ||
that's available to you with or without the use of the base | ||
controller classes. A great way to see the core functionality in | ||
action is to look in the | ||
:class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller` class. | ||
That's it! You now have access to methods like :ref:`$this->render() <controller-rendering-templates>` | ||
and many others that you'll learn about next. | ||
|
||
.. tip:: | ||
|
||
You can extend either ``Controller`` or ``AbstractController``. The difference | ||
is that when you extend ``AbstractController``, you can't access services directly | ||
via ``$this->get()`` or ``$this->container->get()``. This forces you to write | ||
more robust code to access services, but if you're not use, use ``Controller``. | ||
|
||
.. versionadded:: 3.3 | ||
The ``AbstractController`` class was added in Symfony 3.3. | ||
|
||
.. index:: | ||
single: Controller; Redirecting | ||
|
@@ -244,41 +237,136 @@ The Symfony templating system and Twig are explained more in the | |
|
||
.. _controller-accessing-services: | ||
|
||
Accessing other Services | ||
~~~~~~~~~~~~~~~~~~~~~~~~ | ||
Fetching Services as Arguments | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should addd an anchor for the old headline |
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
Symfony comes packed with a lot of useful objects, called *services*. These | ||
are used for rendering templates, sending emails, querying the database and | ||
any other "work" you can think of. When you install a new bundle, it probably | ||
brings in even *more* services. | ||
.. versionadded:: 3.3 | ||
The ability to type-hint an argument in order to receive a service was added | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
in Symfony 3.3. | ||
|
||
When extending the base ``Controller`` class, you can access any Symfony service | ||
via the :method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::get` | ||
method. Here are several common services you might need:: | ||
Symfony comes *packed* with a lot of useful objects, called :doc:`services </service_container>`. | ||
These are used for rendering templates, sending emails, querying the database and | ||
any other "work" you can think of. | ||
|
||
$templating = $this->get('templating'); | ||
If you need a service, just type-hint an argument with its class (or interface) name. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't we explicit that this is only for controllers? |
||
Symfony will automatically pass you the service you need:: | ||
|
||
$router = $this->get('router'); | ||
use Psr\Log\LoggerInterface | ||
// ... | ||
|
||
$mailer = $this->get('mailer'); | ||
/** | ||
* @Route("/lucky/number/{max}") | ||
*/ | ||
public function numberAction($max, LoggerInterface $logger) | ||
{ | ||
$logger->info('We are logging!'); | ||
// ... | ||
} | ||
|
||
What other services exist? To list all services, use the ``debug:container`` | ||
console command: | ||
Awesome! | ||
|
||
What other services exist? Each page of the documentation will reveal more and more | ||
services you can use. To list *all* services, use the ``debug:container`` console | ||
command: | ||
|
||
.. code-block:: terminal | ||
|
||
$ php bin/console debug:container | ||
|
||
For more information, see the :doc:`/service_container` article. | ||
If need to control the *exact* value of an argument, you can override your controller's | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you need control over the [...] |
||
service config: | ||
|
||
.. tip:: | ||
.. configuration-block:: | ||
|
||
.. code-block:: yaml | ||
|
||
# app/config/services.yml | ||
services: | ||
# ... | ||
|
||
# explicitly configure the service | ||
AppBundle\Controller\LuckyController: | ||
public: true | ||
tags: | ||
# add multiple tags to controller multiple args | ||
- name: controller.service_arguments | ||
action: numberAction | ||
argument: logger | ||
# pass this specific service id | ||
id: monolog.logger.doctrine | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just as a reminder for me, I think it could be nice to be able to use bindings here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I also like bindings... we'll see how everything works out for in reality in Symfony 3.3 :). For the most part, bindings and arguments accomplish the same task (in a slightly different way). But it's interesting that bindings could also work to help with controller args - I hadn't really thought about that... seems like one use-case that makes bindings actually a bit better. |
||
|
||
.. code-block:: xml | ||
|
||
<!-- app/config/services.xml --> | ||
<?xml version="1.0" encoding="UTF-8" ?> | ||
<container xmlns="http://symfony.com/schema/dic/services" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://symfony.com/schema/dic/services | ||
http://symfony.com/schema/dic/services/services-1.0.xsd"> | ||
|
||
<services> | ||
<!-- ... --> | ||
|
||
<!-- Explicitly configure the service --> | ||
<service id="AppBundle\Controller\LuckyController" public="true"> | ||
<tag | ||
name="controller.service_arguments" | ||
action="numberAction" | ||
argument="logger" | ||
id="monolog.logger.doctrine" | ||
/> | ||
</service> | ||
</services> | ||
</container> | ||
|
||
.. code-block:: php | ||
|
||
// app/config/services.php | ||
use AppBundle\Controller\LuckyController; | ||
|
||
$container->register(LuckyController::class) | ||
->setPublic(true) | ||
->addTag('controller.service_arguments', [ | ||
'action' => 'numberAction', | ||
'argument' => 'logger', | ||
'id' => 'monolog.logger.doctrine', | ||
]) | ||
; | ||
|
||
For more information about services, see the :doc:`/service_container` article. | ||
|
||
.. note:: | ||
If this isn't working, make sure your controller is registered as a service, | ||
:ref:`autoconfigured <services-autoconfigure>` and extends either | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wouldn't |
||
:class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller` or | ||
:class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController`. Or, | ||
you can tag your service manually with ``controller.service_arguments``. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would replace this by |
||
|
||
To get a :ref:`container configuration parameter <config-parameter-intro>`, | ||
use the | ||
:method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::getParameter` | ||
method:: | ||
.. _accessing-other-services: | ||
.. _controller-access-services-directly: | ||
|
||
$from = $this->getParameter('app.mailer.from'); | ||
Accessing the Container Directly | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
If extending the base ``Controller`` class, you can access any Symfony service | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
via the :method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::get` | ||
method. Here are several common services you might need:: | ||
|
||
$templating = $this->get('templating'); | ||
|
||
$router = $this->get('router'); | ||
|
||
$mailer = $this->get('mailer'); | ||
|
||
// you can also fetch parameters | ||
$someParameter = $this->getParameter('some_parameter'); | ||
|
||
If you receive an eror like: | ||
|
||
You have requested a non-existent service "my_service_id" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will render the error message as a block quote. Do we really want that? I suggest to use a |
||
|
||
Check to make sure the service exists (use :ref:`debug:container <container-debug-container>`) | ||
and that it's :ref:`public <container-public>`. | ||
|
||
.. index:: | ||
single: Controller; Managing errors | ||
|
@@ -355,7 +443,6 @@ Symfony provides a nice session object that you can use to store information | |
about the user between requests. By default, Symfony stores the attributes in a | ||
cookie by using native PHP sessions. | ||
|
||
|
||
.. versionadded:: 3.3 | ||
The ability to request a ``Session`` instance in controllers was introduced | ||
in Symfony 3.3. | ||
|
@@ -418,20 +505,6 @@ For example, imagine you're processing a :doc:`form </forms>` submission:: | |
return $this->render(...); | ||
} | ||
|
||
.. tip:: | ||
|
||
As a developer, you might prefer not to extend the ``Controller``. To | ||
use the flash message functionality, you can request the flash bag from | ||
the :class:`Symfony\\Component\\HttpFoundation\\Session\\Session`:: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this also be removed in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we need to re-read and re-think that article in its entirety... since controllers as services are a first-class citizen (does it make sense to still have a separate article?) |
||
|
||
use Symfony\Component\HttpFoundation\Session\Session; | ||
|
||
public function indexAction(Session $session) | ||
{ | ||
// getFlashBag is not available in the SessionInterface and requires the Session | ||
$flashBag = $session->getFlashBag(); | ||
} | ||
|
||
After processing the request, the controller sets a flash message in the session | ||
and then redirects. The message key (``notice`` in this example) can be anything: | ||
you'll use this key to retrieve the message. | ||
|
@@ -636,12 +709,7 @@ and it's a PHP function where you can do anything in order to return the | |
final ``Response`` object that will be returned to the user. | ||
|
||
To make life easier, you'll probably extend the base ``Controller`` class because | ||
this gives two things: | ||
|
||
A) Shortcut methods (like ``render()`` and ``redirectToRoute()``); | ||
|
||
B) Access to *all* of the useful objects (services) in the system via the | ||
:ref:`get() <controller-accessing-services>` method. | ||
this gives access to shortcut methods (like ``render()`` and ``redirectToRoute()``). | ||
|
||
In other articles, you'll learn how to use specific services from inside your controller | ||
that will help you persist and fetch objects from a database, process form submissions, | ||
|
@@ -666,4 +734,5 @@ Learn more about Controllers | |
|
||
controller/* | ||
|
||
.. _`helper methods`: https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about document the trait in the reference section instead? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure why, but the API docs for the trait are terrible, basically empty :/. It's actually a problem because I would like to link to some methods in the trait via |
||
.. _`unvalidated redirects security vulnerability`: https://www.owasp.org/index.php/Open_redirect |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -548,6 +548,7 @@ a controller, this is pretty easy. Add the following method to the | |
// ... | ||
use AppBundle\Entity\Product; | ||
use Symfony\Component\HttpFoundation\Response; | ||
use Doctrine\ORM\EntityManagerInterface; | ||
|
||
// ... | ||
public function createAction() | ||
|
@@ -568,6 +569,12 @@ a controller, this is pretty easy. Add the following method to the | |
return new Response('Saved new product with id '.$product->getId()); | ||
} | ||
|
||
// you can also receive the $em as an argument | ||
public function editAction(EntityManagerInterface $em) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we also add this to the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll update the whole Doctrine section in another PR with more of this fancy type-based stuff :) |
||
{ | ||
// ... | ||
} | ||
|
||
.. note:: | ||
|
||
If you're following along with this example, you'll need to create a | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -100,7 +100,7 @@ The Swift Mailer library works by creating, configuring and then sending | |
of the message and is accessible via the ``mailer`` service. Overall, sending | ||
an email is pretty straightforward:: | ||
|
||
public function indexAction($name) | ||
public function indexAction($name, \Swift_Mailer $mailer) | ||
{ | ||
$message = \Swift_Message::newInstance() | ||
->setSubject('Hello Email') | ||
|
@@ -125,7 +125,11 @@ an email is pretty straightforward:: | |
) | ||
*/ | ||
; | ||
$this->get('mailer')->send($message); | ||
|
||
$mailer->send($message); | ||
|
||
// or, you can also fetch the mailer service in this way | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. imo we should remove the |
||
// $this->get('mailer')->send($message); | ||
|
||
return $this->render(...); | ||
} | ||
|
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would reverse this sentence:
but if you're use to fetch dependencies using the container, use Controller
, wdyt?