-
-
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 all 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,19 @@ 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 *do* need direct access to the | ||
container, using ``Controller`` is fine. | ||
|
||
.. versionadded:: 3.3 | ||
The ``AbstractController`` class was added in Symfony 3.3. | ||
|
||
.. index:: | ||
single: Controller; Redirecting | ||
|
@@ -244,15 +238,121 @@ The Symfony templating system and Twig are explained more in the | |
|
||
.. _controller-accessing-services: | ||
|
||
Accessing Other Services | ||
~~~~~~~~~~~~~~~~~~~~~~~~ | ||
Fetching Services as Controller Arguments | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
.. versionadded:: 3.3 | ||
The ability to type-hint a controller argument in order to receive a service | ||
was added in Symfony 3.3. | ||
|
||
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. | ||
|
||
If you need a service in a controller, just type-hint an argument with its class | ||
(or interface) name. Symfony will automatically pass you the service you need:: | ||
|
||
use Psr\Log\LoggerInterface | ||
// ... | ||
|
||
/** | ||
* @Route("/lucky/number/{max}") | ||
*/ | ||
public function numberAction($max, LoggerInterface $logger) | ||
{ | ||
$logger->info('We are logging!'); | ||
// ... | ||
} | ||
|
||
Awesome! | ||
|
||
What other services can you type-hint? To see them, use the ``debug:container`` console | ||
command: | ||
|
||
.. code-block:: terminal | ||
|
||
$ php bin/console debug:container --types | ||
|
||
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. | ||
If you need control over the *exact* value of an argument, you can override your | ||
controller's service config: | ||
|
||
When extending the base ``Controller`` class, you can access any Symfony service | ||
.. 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 | ||
|
||
.. 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', | ||
]) | ||
; | ||
|
||
You can of course also use normal :ref:`constructor injection <services-constructor-injection>` | ||
in your controllers. | ||
|
||
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, | ||
is :ref:`autoconfigured <services-autoconfigure>` and extends either | ||
:class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller` or | ||
:class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController`. Or, | ||
you can tag your service manually with ``controller.service_arguments``. All | ||
of this is done for you in a fresh Symfony install. | ||
|
||
.. _accessing-other-services: | ||
.. _controller-access-services-directly: | ||
|
||
Accessing the Container Directly | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
If you extend 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:: | ||
|
||
|
@@ -262,23 +362,17 @@ method. Here are several common services you might need:: | |
|
||
$mailer = $this->get('mailer'); | ||
|
||
What other services exist? To list all services, use the ``debug:container`` | ||
console command: | ||
|
||
.. code-block:: terminal | ||
// you can also fetch parameters | ||
$someParameter = $this->getParameter('some_parameter'); | ||
|
||
$ php bin/console debug:container | ||
If you receive an eror like: | ||
|
||
For more information, see the :doc:`/service_container` article. | ||
|
||
.. tip:: | ||
.. code-block:: text | ||
|
||
To get a :ref:`container configuration parameter <config-parameter-intro>`, | ||
use the | ||
:method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::getParameter` | ||
method:: | ||
You have requested a non-existent service "my_service_id" | ||
|
||
$from = $this->getParameter('app.mailer.from'); | ||
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 +449,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 +511,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 +715,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 +740,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 | ||
|
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.
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 comment
The 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.