Skip to content

[DependencyInjection] Fixed public service use case #13057

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 1 commit into from
Feb 19, 2020
Merged
Show file tree
Hide file tree
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
48 changes: 34 additions & 14 deletions service_container.rst
Original file line number Diff line number Diff line change
Expand Up @@ -815,20 +815,35 @@ Public Versus Private Services
From Symfony 4.0, every service defined is private by default.

What does this mean? When a service **is** public, you can access it directly
from the container object, which is accessible from any controller that extends
``Controller``::
from the container object, which can also be injected thanks to autowiring.
This is mostly useful when you want to fetch services lazily::

use App\Service\MessageGenerator;
namespace App\Generator;

// ...
public function new()
use Psr\Container\ContainerInterface;

class MessageGenerator
{
// there IS a public "logger" service in the container
$logger = $this->container->get('logger');
private $container;

// this will NOT work: MessageGenerator is a private service
$generator = $this->container->get(MessageGenerator::class);
}
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}

public function generate(string $message, string $template = null, array $context = []): string
{
if ($template && $this->container->has('twig')) {
// there IS a public "twig" service in the container
$twig = $this->container->get('twig');

return $twig->render($template, $context + ['message' => $message]);
}

// if no template is passed, the "twig" service will not be loaded

// ...
}

As a best practice, you should only create *private* services, which will happen
automatically. And also, you should *not* use the ``$container->get()`` method to
Expand All @@ -845,7 +860,7 @@ But, if you *do* need to make a service public, override the ``public`` setting:
# ... same code as before

# explicitly configure the service
App\Service\MessageGenerator:
Acme\PublicService:
public: true

.. code-block:: xml
Expand All @@ -861,7 +876,7 @@ But, if you *do* need to make a service public, override the ``public`` setting:
<!-- ... same code as before -->

<!-- Explicitly configure the service -->
<service id="App\Service\MessageGenerator" public="true"></service>
<service id="Acme\PublicService" public="true"></service>
</services>
</container>

Expand All @@ -870,17 +885,22 @@ But, if you *do* need to make a service public, override the ``public`` setting:
// config/services.php
namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use App\Service\MessageGenerator;
use Acme\PublicService;

return function(ContainerConfigurator $configurator) {
// ... same as code before

// explicitly configure the service
$services->set(MessageGenerator::class)
$services->set(PublicService::class)
->public()
;
};

.. note::

Instead of injecting the container you should consider using a
:ref:`service locator <service-locators>` instead.

.. _service-psr4-loader:

Importing Many Services at once with resource
Expand Down
2 changes: 2 additions & 0 deletions service_container/service_subscribers_locators.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
.. index::
single: DependencyInjection; Service Subscribers

.. _service-locators:

Service Subscribers & Locators
==============================

Expand Down