Skip to content

More updates for "Type-based" injection #7906

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

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions _build/redirection_map
Original file line number Diff line number Diff line change
Expand Up @@ -334,3 +334,4 @@
/form /forms
/testing/simulating_authentication /testing/http_authentication
/components/dependency_injection/autowiring /service_container/autowiring
/event_dispatcher/class_extension /event_dispatcher
13 changes: 9 additions & 4 deletions controller.rst
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ controller's service config:
AppBundle\Controller\LuckyController:
public: true
tags:
# add multiple tags to controller multiple args
# add multiple tags to control multiple args
- name: controller.service_arguments
action: numberAction
argument: logger
Expand Down Expand Up @@ -338,13 +338,18 @@ in your controllers.

For more information about services, see the :doc:`/service_container` article.

.. _controller-service-arguments-tag:

.. 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.
:class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController`. If
you use the :ref:`services.yml configuration from the Symfony Standard Edition <service-container-services-load-example>`,
then your controllers are already registered as services and autoconfigured.

If you're not using the default configuration, you can tag your service manually
with ``controller.service_arguments``.

.. _accessing-other-services:
.. _controller-access-services-directly:
Expand Down
50 changes: 4 additions & 46 deletions controller/soap_web_service.rst
Original file line number Diff line number Diff line change
Expand Up @@ -50,53 +50,11 @@ In this case, the SOAP service will allow the client to call a method called
}
}

Next, make sure that your new class is registered as a service. If you use
:doc:`autowiring </service_container/autowiring>` (enabled by default in the Symfony
Standard Edition), this is easy:
Next, make sure that your new class is registered as a service. If you're using
the :ref:`default services configuration <service-container-services-load-example>`,
you don't need to do anything!

.. configuration-block::

.. code-block:: yaml

# app/config/services.yml
services:
_defaults:
# ... be sure autowiring is enabled
autowire: true
# ...

# add Service/ to the list of directories to load services from
AppBundle\:
resource: '../../src/AppBundle/{Service,Updates,Command,Form,EventSubscriber,Twig,Security}'

.. 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>
<!-- ... be sure autowiring is enabled -->
<defaults autowire="true" ... />
<!-- ... -->

<!-- add Service/ to the list of directories to load services from -->
<prototype namespace="AppBundle\" resource="../../src/AppBundle/{Service,Updates,Command,Form,EventSubscriber,Twig,Security}" />
</services>
</container>

.. code-block:: php

// app/config/services.php
use AppBundle\Service\HelloService;

$container->autowire(HelloService::class)
->setPublic(false);

Below is an example of a controller that is capable of handling a SOAP
Finally, below is an example of a controller that is capable of handling a SOAP
request. Because ``indexAction()`` is accessible via ``/soap``, the WSDL document
can be retrieved via ``/soap?wsdl``::

Expand Down
2 changes: 2 additions & 0 deletions event_dispatcher.rst
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ listen to the same ``kernel.exception`` event::
That's it! Your ``services.yml`` file should already be setup to load services from
the ``EventSubscriber`` directory. Symfony takes care of the rest.

.. _ref-event-subscriber-configuration:

.. tip::

If your methods are *not* called when an exception is thrown, double-check that
Expand Down
141 changes: 43 additions & 98 deletions event_dispatcher/before_after_filters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ parameters key:
Tag Controllers to Be Checked
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

A ``kernel.controller`` listener gets notified on *every* request, right before
the controller is executed. So, first, you need some way to identify if the
controller that matches the request needs token validation.
A ``kernel.controller`` (aka ``KernelEvents::CONTROLLER``) listener gets notified
on *every* request, right before the controller is executed. So, first, you need
some way to identify if the controller that matches the request needs token validation.

A clean and easy way is to create an empty interface and make the controllers
implement it::
Expand Down Expand Up @@ -97,21 +97,23 @@ A controller that implements this interface simply looks like this::
}
}

Creating an Event Listener
~~~~~~~~~~~~~~~~~~~~~~~~~~
Creating an Event Subscriber
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Next, you'll need to create an event listener, which will hold the logic
that you want to be executed before your controllers. If you're not familiar with
event listeners, you can learn more about them at :doc:`/event_dispatcher`::

// src/AppBundle/EventListener/TokenListener.php
namespace AppBundle\EventListener;
// src/AppBundle/EventSubscriber/TokenSubscriber.php
namespace AppBundle\EventSubscriber;

use AppBundle\Controller\TokenAuthenticatedController;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;

class TokenListener
class TokenSubscriber implements EventSubscriberInterface
{
private $tokens;

Expand Down Expand Up @@ -140,52 +142,28 @@ event listeners, you can learn more about them at :doc:`/event_dispatcher`::
}
}
}
}

Registering the Listener
~~~~~~~~~~~~~~~~~~~~~~~~

Finally, register your listener as a service and tag it as an event listener.
By listening on ``kernel.controller``, you're telling Symfony that you want
your listener to be called just before any controller is executed.

.. configuration-block::

.. code-block:: yaml

# app/config/services.yml
services:
app.tokens.action_listener:
class: AppBundle\EventListener\TokenListener
arguments: ['%tokens%']
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onKernelController }

.. code-block:: xml

<!-- app/config/services.xml -->
<service id="app.tokens.action_listener" class="AppBundle\EventListener\TokenListener">
<argument>%tokens%</argument>
<tag name="kernel.event_listener" event="kernel.controller" method="onKernelController" />
</service>

.. code-block:: php
public static function getSubscribedEvents()
{
return array(
KernelEvents::CONTROLLER => 'onKernelController',
);
}
}

// app/config/services.php
use AppBundle\EventListener\TokenListener;
That's it! Your ``services.yml`` file should already be setup to load services from
the ``EventSubscriber`` directory. Symfony takes care of the rest. Your
``TokenSubscriber`` ``onKernelController()`` method will be executed on each request.
If the controller that is about to be executed implements ``TokenAuthenticatedController``,
token authentication is applied. This lets you have a "before" filter on any controller
you want.

$container->register('app.tokens.action_listener', TokenListener::class)
->addArgument('%tokens%')
->addTag('kernel.event_listener', array(
'event' => 'kernel.controller',
'method' => 'onKernelController',
));
.. tip::

With this configuration, your ``TokenListener`` ``onKernelController()`` method
will be executed on each request. If the controller that is about to be executed
implements ``TokenAuthenticatedController``, token authentication is
applied. This lets you have a "before" filter on any controller that you
want.
If your subscriber id *not* called on each request, double-check that
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

id -> is

you're :ref:`loading services <service-container-services-load-example>` from
the ``EventSubscriber`` directory and have :ref:`autoconfigure <services-autoconfigure>`
enabled. You can also manually add the ``kernel.event_subscriber`` tag.

After Filters with the ``kernel.response`` Event
------------------------------------------------
Expand All @@ -195,12 +173,12 @@ can also add a hook that's executed *after* your controller. For this example,
imagine that you want to add a sha1 hash (with a salt using that token) to
all responses that have passed this token authentication.

Another core Symfony event - called ``kernel.response`` - is notified on
every request, but after the controller returns a Response object. Creating
an "after" listener is as easy as creating a listener class and registering
Another core Symfony event - called ``kernel.response`` (aka ``KernelEvents::RESPONSE``) -
is notified on every request, but after the controller returns a Response object.
Creating an "after" listener is as easy as creating a listener class and registering
it as a service on this event.

For example, take the ``TokenListener`` from the previous example and first
For example, take the ``TokenSubscriber`` from the previous example and first
record the authentication token inside the request attributes. This will
serve as a basic flag that this request underwent token authentication::

Expand All @@ -219,9 +197,9 @@ serve as a basic flag that this request underwent token authentication::
}
}

Now, add another method to this class - ``onKernelResponse()`` - that looks
for this flag on the request object and sets a custom header on the response
if it's found::
Now, configure the subscriber to listen to another event and add ``onKernelResponse()``.
This will look for the ``auth_token`` flag on the request object and set a custom
header on the response if it's found::

// add the new use statement at the top of your file
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
Expand All @@ -240,49 +218,16 @@ if it's found::
$response->headers->set('X-CONTENT-HASH', $hash);
}

Finally, a second "tag" is needed in the service definition to notify Symfony
that the ``onKernelResponse`` event should be notified for the ``kernel.response``
event:

.. configuration-block::

.. code-block:: yaml

# app/config/services.yml
services:
app.tokens.action_listener:
class: AppBundle\EventListener\TokenListener
arguments: ['%tokens%']
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onKernelController }
- { name: kernel.event_listener, event: kernel.response, method: onKernelResponse }

.. code-block:: xml

<!-- app/config/services.xml -->
<service id="app.tokens.action_listener" class="AppBundle\EventListener\TokenListener">
<argument>%tokens%</argument>
<tag name="kernel.event_listener" event="kernel.controller" method="onKernelController" />
<tag name="kernel.event_listener" event="kernel.response" method="onKernelResponse" />
</service>
public static function getSubscribedEvents()
{
return array(
KernelEvents::CONTROLLER => 'onKernelController',
KernelEvents::RESPONSE => 'onKernelResponse',
);
}

.. code-block:: php

// app/config/services.php
use AppBundle\EventListener\TokenListener;

$container->register('app.tokens.action_listener', TokenListener::class)
->addArgument('%tokens%')
->addTag('kernel.event_listener', array(
'event' => 'kernel.controller',
'method' => 'onKernelController',
))
->addTag('kernel.event_listener', array(
'event' => 'kernel.response',
'method' => 'onKernelResponse',
));

That's it! The ``TokenListener`` is now notified before every controller is
That's it! The ``TokenSubscriber`` is now notified before every controller is
executed (``onKernelController()``) and after every controller returns a response
(``onKernelResponse()``). By making specific controllers implement the ``TokenAuthenticatedController``
interface, your listener knows which controllers it should take action on.
Expand Down
Loading