8000 more tweaks · symfony/symfony-docs@6e6ed94 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6e6ed94

Browse files
committed
more tweaks
1 parent 0e48bd8 commit 6e6ed94

File tree

1 file changed

+98
-48
lines changed

1 file changed

+98
-48
lines changed

service_container.rst

Lines changed: 98 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Service Container
66
=================
77

88
Your application is *full* of useful objects: one "Mailer" object might help you
9-
deliver email messages while another object might help you save things to the database.
9+
send email messages while another object might help you save things to the database.
1010
Almost *everything* that your app "does" is actually done by one of these objects.
1111
And each time you install a new bundle, you get access to even more!
1212

@@ -17,21 +17,13 @@ then you can fetch a service by using that service's id::
1717
$logger = $container->get('logger');
1818
$entityManager = $container->get('doctrine.entity_manager');
1919

20-
The container is the *heart* of Symfony: it allows you to standardize and centralize
21-
the way objects are constructed. It makes your life easier, is super fast, and emphasizes
22-
an architecture that promotes reusable and decoupled code. It's also a big reason
23-
that Symfony is so fast and extensible!
24-
25-
Finally, configuring and using the service container is easy. By the end
26-
of this article, you'll be comfortable creating your own objects via the
27-
container and customizing objects from any third-party bundle. You'll begin
28-
writing code that is more reusable, testable and decoupled, simply because
29-
the service container makes writing good code so easy.
20+
The container allows you to centralize the way objects are constructed. It makes
21+
your life easier, promotes a strong architecture and is super fast!
3022

3123
Fetching and using Services
3224
---------------------------
3325

34-
The moment you start a Symfony app, the container *already* contains many services.
26+
The moment you start a Symfony app, your container *already* contains many services.
3527
These are like *tools*, waiting for you to take advantage of them. In your controller,
3628
you have access to the container via ``$this->container``. Want to :doc:`log </logging>`
3729
something? No problem::
@@ -86,11 +78,10 @@ in the container.
8678

8779
.. sidebar:: Container: Lazy-loaded for speed
8880

89-
If the container holds so many useful objects (services), does that mean those
90-
objects are instantiated on *every* request? No! The container is lazy: it doesn't
91-
instantiate a service until (and unless) you ask for it. For example, if you
92-
never use the ``validator`` service during a request, the container will never
93-
instantiate it.
81+
Wait! Are all the services (objects) instantiated on *every* request? No! The
82+
container is lazy: it doesn't instantiate a service until (and unless) you ask
83+
for it. For example, if you never use the ``validator`` service during a request,
84+
the container will never instantiate it.
9485

9586
.. index::
9687
single: Service Container; Configuring services
@@ -100,10 +91,9 @@ in the container.
10091
Creating/Configuring Services in the Container
10192
----------------------------------------------
10293

103-
You can also leverage the container to organize your *own* code into services. For
104-
example, suppose you want to show your users a random, happy message every time
105-
they do something. If you put this code in your controller, it can't be re-used.
106-
Instead, you decide to create a new class::
94+
You can also organize your *own* code into services. For example, suppose you need
95+
to show your users a random, happy message. If you put this code in your controller,
96+
it can't be re-used. Instead, you decide to create a new class::
10797

10898
// src/AppBundle/Service/MessageGenerator.php
10999
namespace AppBundle\Service;
@@ -133,14 +123,13 @@ the service container *how* to instantiate it:
133123
134124
# app/config/services.yml
135125
services:
136-
# configures defaults for all services in this file
137126
_defaults:
138127
autowire: true
139128
autoconfigure: true
140129
141-
# registers all classes in the dir(s) as services
130+
# load services from whatever directories you want (you can update this!)
142131
AppBundle\:
143-
resource: '../../src/AppBundle/{Service}'
132+
resource: '../../src/AppBundle/{Service,EventDispatcher,Twig,Form}'
144133
145134
.. code-block:: xml
146135
@@ -153,9 +142,10 @@ the service container *how* to instantiate it:
153142
TODO
154143
155144
That's it! Thanks to the ``AppBundle\`` line and ``resource`` key below it, all
156-
classes in the ``src/AppBundle/Service`` directory will automatically be added to
157-
the container. Each service's "key" is simply its class name. You can use it immediately
158-
inside your controller::
145+
classes in the ``src/AppBundle/Service`` directory (and a few other directories)
146+
will automatically be added to the container.
147+
148+
Each service's "key" is its class name. You can use it immediately inside your controller::
159149

160150
use AppBundle\Service\MessageGenerator;
161151

@@ -175,10 +165,8 @@ inside your controller::
175165
}
176166

177167
When you ask for the ``MessageGenerator::class`` service, the container constructs
178-
a new ``MessageGenerator`` object and returns it. If you never ask for the
179-
``MessageGenerator::class`` service during a request, it's *never* constructed, saving
180-
you memory and increasing the speed of your app. This also means that there's almost
181-
no performance overhead for defining a lot of services.
168+
a new ``MessageGenerator`` object and returns it. But if you never ask for the service,
169+
it's *never* constructed: saving memory and speed.
182170

183171
As a bonus, the ``MessageGenerator::class`` service is only created *once*: the same
184172
instance is returned each time you ask for it.
@@ -221,25 +209,26 @@ and set it on a ``$logger`` property::
221209
}
222210

223211
That's it! The container will *automatically* know to pass the ``logger`` service
224-
when instantiating the ``MessageGenerator``? How does it know to do this? The key
225-
is the ``LoggerInterface`` type-hint in your ``__construct()`` method and the
226-
``autowire: true`` config in ``services.yml``. When you type-hint an argument, the
227-
container will automatically find the matching service. If it can't or there is any
228-
ambuiguity, you'll see a clear exception suggesting how to fix it.
212+
when instantiating the ``MessageGenerator``? How does it know to do this?
213+
:doc:`Autowiring </service_container/autowiring>`. The key is the ``LoggerInterface``
214+
type-hint in your ``__construct()`` method and the ``autowire: true`` config in
215+
``services.yml``. When you type-hint an argument, the container will automatically
216+
find the matching service. If it can't or there is any ambuiguity, you'll see a clear
217+
exception suggesting how to fix it.
229218

230219
Be sure to read more about :doc:`autowiring </service_container/autowiring>`.
231220

232221
.. tip::
233222

234-
How do you know to use ``LoggerInterface`` for the type-hint? The best way to
235-
know this is by reading the docs for whatever service you're using. You can
236-
also use the ``php bin/console debug:container`` console command to get a hint
223+
How should you know to use ``LoggerInterface`` for the type-hint? The best way
224+
is by reading the docs for whatever feature you're using. You can also use the
225+
``php bin/console debug:container`` console command to get a hint
237226
to the class name for a service.
238227

239228
Handling Multiple Services
240229
--------------------------
241230

242-
Suppose you also want to email some site administrator each time a site update is
231+
Suppose you also want to email a site administrator each time a site update is
243232
made. To do that, you create a new class::
244233

245234
// src/AppBundle/Updates/SiteUpdateManager.php
@@ -289,7 +278,7 @@ the new ``Updates`` sub-directory:
289278
290279
# registers all classes in Services & Updates directories
291280
AppBundle\:
292-
resource: '../../src/AppBundle/{Service,Updates}'
281+
resource: '../../src/AppBundle/{Service,Updates,EventDispatcher,Twig,Form}'
293282
294283
.. code-block:: xml
295284
@@ -316,16 +305,15 @@ Now, you can use the service immediately::
316305
// ...
317306
}
318307

319-
Just like before, when you ask for the ``SiteUpdateManager`` service, the container
320-
will automatically instantiate it for you. By reading the type-hints on the ``__construct()``
321-
method in that class, it takes care of passing the correct services as arguments.
322-
All of that is taken care of for you.
308+
Thanks to autowiring and your type-hints in ``__construct()``, the container creates
309+
the ``SiteUpdateManager`` object and passes it the correct arguments. In most cases,
310+
this works perfectly.
323311

324312
Manually Wiring Arguments
325313
-------------------------
326314

327-
There are a few cases when an argument to a service cannot be autowired. For example,
328-
suppose you want to make the admin email configurable:
315+
But there are a few cases when an argument to a service cannot be autowired. For
316+
example, suppose you want to make the admin email configurable:
329317

330318
.. code-block:: diff
331319
@@ -394,7 +382,8 @@ pass here. No problem! In your configuration, you can explicitly set this argume
394382
TODO
395383
396384
Thanks to this, the container will pass ``manager@example.com`` as the third argument
397-
to ``__construct`` when creating the ``SiteUpdateManager`` service.
385+
to ``__construct`` when creating the ``SiteUpdateManager`` service. The other arguments
386+
will still be autowired.
398387

399388
.. _service-container-parameters:
400389

@@ -460,6 +449,67 @@ You can also fetch parameters directly from the container::
460449
461450
For more info about parameters, see :doc:`/service_container/parameters`.
462451

452+
Choose a Specific Service
453+
-------------------------
454+
455+
The ``MessageGenerator`` service created earlier requires a ``LoggerInterface`` argument::
456+
457+
// src/AppBundle/Service/MessageGenerator.php
458+
// ...
459+
460+
use Psr\Log\LoggerInterface;
461+
462+
class MessageGenerator
463+
{
464+
private $logger;
465+
466+
public function __construct(LoggerInterface $logger)
467+
{
468+
$this->logger = $logger;
469+
}
470+
// ...
471+
}
472+
473+
However, there are *multiple* services in the container that implement ``LoggerInterface``,
474+
such as ``logger``, ``monolog.logger.request``, ``monolog.logger.php``, etc. How
475+
does the container know which one to use?
476+
477+
In these situations, the container is usually configured to automatically choose
478+
one of the services - ``logger`` in this case (read more about why in :ref:`service-autowiring-alias`).
479+
But, you can control this and pass in a different logger:
480+
481+
.. configuration-block::
482+
483+
.. code-block:: yaml
484+
485+
# app/config/services.yml
486+
services:
487+
# ... same code as before
488+
489+
# explicitly configure the service
490+
AppBundle\Service\MessageGenerator:
491+
arguments:
492+
$logger: '@monolog.logger.request'
493+
494+
.. code-block:: xml
495+
496+
<!-- app/config/services.xml -->
497+
TODO
498+
499+
.. code-block:: php
500+
501+
// app/config/services.php
502+
TODO
503+
504+
This tells the container that the ``$logger`` argument to ``_construct`` should use
505+
service whose id is ``monolog.logger.request``.
506+
507+
.. tip::
508+
509+
The ``@`` symbol is important: that's what tells the container you want to pass
510+
the *service* whose id is ``monolog.logger.request``, and not just the *string*
511+
``monolog.logger.request``.
512+
463513
Learn more
464514
----------
465515

0 commit comments

Comments
 (0)
0