Skip to content

Updated service_container/* articles to Symfony 4 #8751

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
Nov 29, 2017
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
80 changes: 36 additions & 44 deletions service_container.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,10 @@ send emails while another object might help you save things to the database.
Almost *everything* that your app "does" is actually done by one of these objects.
And each time you install a new bundle, you get access to even more!

In Symfony, these useful objects are called **services** and each service lives inside
a very special object called the **service container**. If you have the service container,
then you can fetch a service by using that service's id::

$logger = $container->get('logger');
$entityManager = $container->get('doctrine.orm.entity_manager');

The container allows you to centralize the way objects are constructed. It makes
your life easier, promotes a strong architecture and is super fast!
In Symfony, these useful objects are called **services** and each service lives
inside a very special object called the **service container**. The container
allows you to centralize the way objects are constructed. It makes your life
easier, promotes a strong architecture and is super fast!

Fetching and using Services
---------------------------
Expand All @@ -36,7 +31,7 @@ service's class or interface name. Want to :doc:`log </logging>` something? No p
/**
* @Route("/products")
*/
public function listAction(LoggerInterface $logger)
public function list(LoggerInterface $logger)
{
$logger->info('Look! I just used a service');

Expand Down Expand Up @@ -83,7 +78,7 @@ You can also use the unique "Service ID" to access a service directly::
/**
* @Route("/products")
*/
public function listAction()
public function list()
{
$logger = $this->container->get('logger');
$logger->info('Look! I just used a service');
Expand Down Expand Up @@ -146,7 +141,7 @@ inside your controller::

use App\Service\MessageGenerator;

public function newAction(MessageGenerator $messageGenerator)
public function new(MessageGenerator $messageGenerator)
{
// thanks to the type-hint, the container will instantiate a
// new MessageGenerator and pass it to you!
Expand All @@ -167,9 +162,7 @@ each time you ask for it.

.. sidebar:: Automatic Service Loading in services.yaml

The documentation assumes you're using
`Symfony Standard Edition (version 3.3) services.yaml`_ configuration. The most
important part is this:
The documentation assumes you're using the following service configuration:

.. configuration-block::

Expand All @@ -185,10 +178,10 @@ each time you ask for it.

# makes classes in src/ available to be used as services
App\:
resource: '../../src/*'
resource: '../src/*'
# you can exclude directories or files
# but if a service is unused, it's removed anyway
exclude: '../../src/{Entity,Repository}'
exclude: '../src/{Entity,Repository}'

.. code-block:: xml

Expand All @@ -204,7 +197,7 @@ each time you ask for it.
<defaults autowire="true" autoconfigure="true" public="false" />

<!-- Load services from whatever directories you want (you can update this!) -->
<prototype namespace="App\" resource="../../src/*" exclude="../../src/{Entity,Repository}" />
<prototype namespace="App\" resource="../src/*" exclude="../src/{Entity,Repository}" />
</services>
</container>

Expand All @@ -223,7 +216,7 @@ each time you ask for it.
;

// $this is a reference to the current loader
$this->registerClasses($definition, 'App\\', '../../src/*', '../../src/{Entity,Repository}');
$this->registerClasses($definition, 'App\\', '../src/*', '../src/{Entity,Repository}');

.. tip::

Expand All @@ -237,15 +230,16 @@ each time you ask for it.
If you'd prefer to manually wire your service, that's totally possible: see
:ref:`services-explicitly-configure-wire-services`.

You can also fetch a service directly from the container via its "id", which will
be its class name in this case::
If the :ref:`service is public <container-public>`, you can also fetch it
directly from the container via its "id". However, this practice is discouraged
and you should instead inject services via constructors::

use App\Service\MessageGenerator;

// accessing services like this only works if you extend Controller
class ProductController extends Controller
{
public function newAction()
public function new()
{
// only works if your service is public
$messageGenerator = $this->get(MessageGenerator::class);
Expand All @@ -256,8 +250,6 @@ be its class name in this case::
}
}

However, this only works if you make your service :ref:`public <container-public>`.

.. _services-constructor-injection:

Injecting Services/Config into a Service
Expand Down Expand Up @@ -368,7 +360,7 @@ you can use the service immediately::

use App\Updates\SiteUpdateManager;

public function newAction(SiteUpdateManager $siteUpdateManager)
public function new(SiteUpdateManager $siteUpdateManager)
{
// ...

Expand Down Expand Up @@ -438,8 +430,8 @@ pass here. No problem! In your configuration, you can explicitly set this argume

# same as before
App\:
resource: '../../src/*'
exclude: '../../src/{Entity,Repository}'
resource: '../src/*'
exclude: '../src/{Entity,Repository}'

# explicitly configure the service
App\Updates\SiteUpdateManager:
Expand All @@ -459,7 +451,7 @@ pass here. No problem! In your configuration, you can explicitly set this argume
<!-- ... -->

<!-- Same as before -->
<prototype namespace="App\" resource="../../src/*" exclude="../../src/{Entity,Repository}" />
<prototype namespace="App\" resource="../src/*" exclude="../src/{Entity,Repository}" />

<!-- Explicitly configure the service -->
<service id="App\Updates\SiteUpdateManager">
Expand All @@ -483,7 +475,7 @@ pass here. No problem! In your configuration, you can explicitly set this argume
->setPublic(false)
;

$this->registerClasses($definition, 'App\\', '../../src/*', '../../src/{Entity,Repository}');
$this->registerClasses($definition, 'App\\', '../src/*', '../src/{Entity,Repository}');

// Explicitly configure the service
$container->getDefinition(SiteUpdateManager::class)
Expand Down Expand Up @@ -553,9 +545,9 @@ and reference it with the ``%parameter_name%`` syntax:
// ...
->setArgument('$adminEmail', '%admin_email%');

Actually, once you define a parameter, it can be referenced via the ``%parameter_name%``
syntax in *any* other service configuration file - like ``config.yml``. Many parameters
are defined in a :ref:`parameters.yml file <config-parameters-yml>`.
Actually, once you define a parameter, it can be referenced via the
``%parameter_name%`` syntax in *any* other configuration file. Many parameters
are defined in the ``config/services.yaml`` file.

You can then fetch the parameter in the service::

Expand All @@ -573,11 +565,11 @@ You can then fetch the parameter in the service::

You can also fetch parameters directly from the container::

public function newAction()
public function new()
{
// ...

// this ONLY works if you extend Controller
// this ONLY works if you extend the base Controller
$adminEmail = $this->container->getParameter('admin_email');

// or a shorter way!
Expand Down Expand Up @@ -741,7 +733,7 @@ as a service, and :doc:`tag </service_container/tags>` it with ``twig.extension`
->addTag('twig.extension');

But, with ``autoconfigure: true``, you don't need the tag. In fact, if you're using
the :ref:`Symfony Standard Edition services.yaml config <service-container-services-load-example>`,
the :ref:`default services.yaml config <service-container-services-load-example>`,
you don't need to do *anything*: the service will be automatically loaded. Then,
``autoconfigure`` will add the ``twig.extension`` tag *for* you, because your class
implements ``Twig_ExtensionInterface``. And thanks to ``autowire``, you can even add
Expand Down Expand Up @@ -789,15 +781,15 @@ from the container::

use App\Service\MessageGenerator;

public function newAction(MessageGenerator $messageGenerator)
public function new(MessageGenerator $messageGenerator)
{
// type-hinting it as an argument DOES work

// but accessing it directly from the container does NOT Work
$this->container->get(MessageGenerator::class);
}

Usually, this is ok: there are better ways to access a service. But, if you *do*
Usually, this is OK: there are better ways to access a service. But, if you *do*
need to make your service public, just override this setting:

.. configuration-block::
Expand Down Expand Up @@ -848,13 +840,13 @@ key. For example, the default Symfony configuration contains this:
# the namespace prefix for classes (must end in \)
App\:
# create services for all the classes found in this directory...
resource: '../../src/*'
resource: '../src/*'
# ...except for the classes located in these directories
exclude: '../../src/{Entity,Repository}'
exclude: '../src/{Entity,Repository}'

# these were imported above, but we want to add some extra config
App\Controller\:
resource: '../../src/Controller'
resource: '../src/Controller'
# apply some configuration to these services
public: true
tags: ['controller.service_arguments']
Expand All @@ -871,9 +863,9 @@ key. For example, the default Symfony configuration contains this:
<services>
<!-- ... -->

<prototype namespace="App\" resource="../../src/*" exclude="../../src/{Entity,Repository}" />
<prototype namespace="App\" resource="../src/*" exclude="../src/{Entity,Repository}" />

<prototype namespace="App\Controller\" resource="../../src/Controller" public="true">
<prototype namespace="App\Controller\" resource="../src/Controller" public="true">
<tag name="controller.service_arguments" />
</prototype>
</services>
Expand All @@ -893,7 +885,7 @@ key. For example, the default Symfony configuration contains this:
->setPublic(false)
;

$this->registerClasses($definition, 'App\\', '../../src/*', '../../src/{Entity,Repository}');
$this->registerClasses($definition, 'App\\', '../src/*', '../src/{Entity,Repository}');

// Changes default config
$definition
Expand All @@ -902,7 +894,7 @@ key. For example, the default Symfony configuration contains this:
;

// $this is a reference to the current loader
$this->registerClasses($definition, 'App\\Controller\\', '../../src/Controller/*');
$this->registerClasses($definition, 'App\\Controller\\', '../src/Controller/*');

.. tip::

Expand Down
40 changes: 20 additions & 20 deletions service_container/3.3-di-changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,15 @@ Symfony Standard Edition:
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../../src/*'
resource: '../src/*'
# you can exclude directories or files
# but if a service is unused, it's removed anyway
exclude: '../../src/{Entity,Repository}'
exclude: '../src/{Entity,Repository}'

# controllers are imported separately to make sure they're public
# and have a tag that allows actions to type-hint services
App\Controller\:
resource: '../../src/Controller'
resource: '../src/Controller'
tags: ['controller.service_arguments']

# add more services, or override services that need manual wiring
Expand All @@ -77,9 +77,9 @@ Symfony Standard Edition:
<services>
<defaults autowire="true" autoconfigure="true" public="false" />

<prototype namespace="App\" resource="../../src/*" exclude="../../src/{Entity,Repository}" />
<prototype namespace="App\" resource="../src/*" exclude="../src/{Entity,Repository}" />

<prototype namespace="App\Controller\" resource="../../src/Controller">
<prototype namespace="App\Controller\" resource="../src/Controller">
<tag name="controller.service_arguments" />
</prototype>

Expand All @@ -101,15 +101,15 @@ Symfony Standard Edition:
->setPublic(false)
;

$this->registerClasses($definition, 'App\\', '../../src/*', '../../src/{Entity,Repository}');
$this->registerClasses($definition, 'App\\', '../src/*', '../src/{Entity,Repository}');

// Changes default config
$definition
->addTag('controller.service_arguments')
;

// $this is a reference to the current loader
$this->registerClasses($definition, 'App\\Controller\\', '../../src/Controller/*');
$this->registerClasses($definition, 'App\\Controller\\', '../src/Controller/*');

// add more services, or override services that need manual wiring

Expand Down Expand Up @@ -139,10 +139,10 @@ thanks to the following config:
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../../src/*'
resource: '../src/*'
# you can exclude directories or files
# but if a service is unused, it's removed anyway
exclude: '../../src/{Entity,Repository}'
exclude: '../src/{Entity,Repository}'

.. code-block:: xml

Expand All @@ -156,7 +156,7 @@ thanks to the following config:
<services>
<!-- ... -->

<prototype namespace="App\" resource="../../src/*" exclude="../../src/{Entity,Repository}" />
<prototype namespace="App\" resource="../src/*" exclude="../src/{Entity,Repository}" />
</services>
</container>

Expand All @@ -174,7 +174,7 @@ thanks to the following config:
->setPublic(false)
;

$this->registerClasses($definition, 'App\\', '../../src/*', '../../src/{Entity,Repository}');
$this->registerClasses($definition, 'App\\', '../src/*', '../src/{Entity,Repository}');

This means that every class in ``src/`` is *available* to be used as a
service. And thanks to the ``_defaults`` section at the top of the file, all of
Expand Down Expand Up @@ -345,7 +345,7 @@ The third big change is that, in a new Symfony 3.3 project, your controllers are
# controllers are imported separately to make sure they're public
# and have a tag that allows actions to type-hint services
App\Controller\:
resource: '../../src/Controller'
resource: '../src/Controller'
tags: ['controller.service_arguments']

.. code-block:: xml
Expand All @@ -360,7 +360,7 @@ The third big change is that, in a new Symfony 3.3 project, your controllers are
<services>
<!-- ... -->

<prototype namespace="App\Controller\" resource="../../src/Controller">
<prototype namespace="App\Controller\" resource="../src/Controller">
<tag name="controller.service_arguments" />
</prototype>
</services>
Expand All @@ -372,7 +372,7 @@ The third big change is that, in a new Symfony 3.3 project, your controllers are

// ...

$this->registerClasses($definition, 'App\\Controller\\', '../../src/Controller/*');
$this->registerClasses($definition, 'App\\Controller\\', '../src/Controller/*');

But, you might not even notice this. First, your controllers *can* still extend
the same base ``Controller`` class or a new :ref:`AbstractController <controller-abstract-versus-controller>`.
Expand Down Expand Up @@ -720,11 +720,11 @@ You're now ready to automatically register all services in ``src/``
# ...

+ App\:
+ resource: '../../src/*'
+ exclude: '../../src/{Entity,Repository}'
+ resource: '../src/*'
+ exclude: '../src/{Entity,Repository}'
+
+ App\Controller\:
+ resource: '../../src/Controller'
+ resource: '../src/Controller'
+ tags: ['controller.service_arguments']

# ...
Expand Down Expand Up @@ -809,11 +809,11 @@ can be autowired. The final configuration looks like this:
public: false

App\:
resource: '../../src/*'
exclude: '../../src/{Entity,Repository}'
resource: '../src/*'
exclude: '../src/{Entity,Repository}'

App\Controller\:
resource: '../../src/Controller'
resource: '../src/Controller'
tags: ['controller.service_arguments']

App\Service\GitHubNotifier:
Expand Down
Loading