Skip to content

Tell about controllers in doc about service subscribers #9989

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

Merged
merged 2 commits into from
Jul 4, 2018
Merged
Changes from all 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
54 changes: 25 additions & 29 deletions service_container/service_subscribers_locators.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ instantiation of the services to be lazy. However, that's not possible using
the explicit dependency injection since services are not all meant to
be ``lazy`` (see :doc:`/service_container/lazy_services`).

A real-world example are applications that implement the `Command pattern`_
This can typically be the case in your controllers, where you may inject several
services in the constructor, but the action executed only uses some of them.
Another example are applications that implement the `Command pattern`_
using a CommandBus to map command handlers by Command class names and use them
to handle their respective command when it is asked for::

Expand Down Expand Up @@ -50,35 +52,12 @@ to handle their respective command when it is asked for::

Considering that only one command is handled at a time, instantiating all the
other command handlers is unnecessary. A possible solution to lazy-load the
handlers could be to inject the whole dependency injection container::

// ...
use Symfony\Component\DependencyInjection\ContainerInterface;

class CommandBus
{
private $container;

public function __construct(ContainerInterface $container)
{
$this->container = $container;
}

public function handle(Command $command)
{
$commandClass = get_class($command);

if ($this->container->has($commandClass)) {
$handler = $this->container->get($commandClass);

return $handler->handle($command);
}
}
}
handlers could be to inject the main dependency injection container.

However, injecting the entire container is discouraged because it gives too
broad access to existing services and it hides the actual dependencies of the
services.
services. Doing so also requires services to be made public, which isn't the
case by default in Symfony applications.

**Service Subscribers** are intended to solve this problem by giving access to a
set of predefined services while instantiating them only when actually needed
Expand Down Expand Up @@ -139,8 +118,7 @@ The injected service is an instance of :class:`Symfony\\Component\\DependencyInj
which implements the PSR-11 ``ContainerInterface``, but it is also a callable::

// ...
$locateHandler = $this->locator;
$handler = $locateHandler($commandClass);
$handler = ($this->locator)($commandClass);

return $handler->handle($command);

Expand Down Expand Up @@ -173,6 +151,24 @@ Service types can also be keyed by a service name for internal use::
];
}

When extending a class that also implements ``ServiceSubscriberInterface``,
it's your responsibility to call the parent when overriding the method. This
typically happens when extending ``AbstractController``::

use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

class MyController extends AbstractController
{
public static function getSubscribedServices()
{
return array_merge(parent::getSubscribedServices(), [
// ...
'logger' => LoggerInterface::class,
]);
}
}

Optional Services
~~~~~~~~~~~~~~~~~

Expand Down