Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 858d602

Browse filesBrowse files
committed
[DI] Add section about Service Locators
1 parent 7893772 commit 858d602
Copy full SHA for 858d602

File tree

1 file changed

+155
-0
lines changed
Filter options

1 file changed

+155
-0
lines changed
+155Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
.. index::
2+
single: DependencyInjection; Service Locators
3+
4+
Service Locators
5+
================
6+
7+
What is a Service Locator
8+
-------------------------
9+
10+
Sometimes, a service needs the ability to access other services without being sure
11+
that all of them will actually be used.
12+
13+
In such cases, you may want the instantiation of these services to be lazy, that is
14+
not possible using explicit dependency injection since services are not all meant to
15+
be ``lazy`` (see :doc:`/service_container/lazy_services`).
16+
17+
Service Locators are intended to solve this problem by giving access to a set of
18+
identified services while instantiating them only when really needed, providing
19+
laziness.
20+
21+
A real-world example being a CommandBus which maps CommandHandler services by Command
22+
class names and use them to handle their respective command when it is asked for::
23+
24+
// ...
25+
class CommandBus
26+
{
27+
/**
28+
* @var CommandHandler[]
29+
*/
30+
private $handlerMap;
31+
32+
// ...
33+
34+
public function handle(Command $command)
35+
{
36+
foreach (handlerMap as $commandClass => $handler) {
37+
if ($commandClass === get_class($command)) {
38+
return $handler->handle($command);
39+
}
40+
}
41+
}
42+
}
43+
44+
// ...
45+
$commandBus->handle(new FooCommand());
46+
47+
Because only one command is handled at a time, other CommandHandler services are not
48+
used.
49+
50+
Configuration
51+
-------------
52+
53+
For injecting a service locator in a service, use the `service_locator` argument
54+
type and define the set of services that needs to be accessible from:
55+
56+
.. configuration-block::
57+
58+
.. code-block:: yaml
59+
60+
services:
61+
62+
app.command_bus:
63+
class: AppBundle\CommandBus
64+
arguments:
65+
- =service_locator:
66+
AppBundle\FooCommand: '@app.command_handler.foo'
67+
AppBundle\BarCommand: '@app.command_handler.bar'
68+
69+
.. code-block:: xml
70+
71+
<?xml version="1.0" encoding="UTF-8" ?>
72+
<container xmlns="http://symfony.com/schema/dic/services"
73+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
74+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
75+
76+
<services>
77+
78+
<service id="app.command_bus" class="AppBundle\CommandBus">
79+
<argument type="service-locator">
80+
<argument key="AppBundle\FooCommand" type="service" id="app.command_handler.foo" />
81+
<argument key="AppBundle\BarCommand" type="service" id="app.command_handler.bar" />
82+
</argument>
83+
</service>
84+
85+
</services>
86+
</container>
87+
88+
.. code-block:: php
89+
90+
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
91+
use Symfony\Component\DependencyInjection\Reference;
92+
93+
//...
94+
95+
$container
96+
->register('app.command_bus')
97+
->setArguments(array(new ServiceLocatorArgument(array(
98+
'AppBundle\FooCommand' => new Reference('app.command_handler.foo'),
99+
'AppBundle\BarCommand' => new Reference('app.command_handler.bar'),
100+
))))
101+
;
102+
103+
.. note::
104+
105+
The services defined in the service locator argument must be keyed,
106+
as keys become their unique identifier inside the locator.
107+
108+
.. tip::
109+
110+
Not only services can be passed accessible through a service locator,
111+
but all types which are supported by the configuration format used to
112+
configure it.
113+
114+
Usage
115+
-----
116+
117+
Back to our CommandBus which would now look like::
118+
119+
// ...
120+
use Symfony\Component\DependencyInjection\ServiceLocator;
121+
122+
class CommandBus
123+
{
124+
/**
125+
* @var ServiceLocator
126+
*/
127+
private $handlerMap;
128+
129+
// ...
130+
131+
public function handle(Command $command)
132+
{
133+
$commandClass = get_class($command);
134+
$handler = $this->handlerMap->get($commandClass);
135+
136+
return $handler->handle($command);
137+
}
138+
}
139+
140+
A :class:`Symfony\\Component\\DependencyInjection\\ServiceLocator` instance
141+
can also be invoked for accessing a service::
142+
143+
// ...
144+
$handlerMap = $this->handlerMap;
145+
146+
return $handlerMap($handlerId)->handle($command);
147+
148+
Or can be used in a loop to iterate over all available services::
149+
150+
// ...
151+
foreach ($this->handlerMap as $commandClass => $handler) {
152+
if ($commandClass === get_class($command)) {
153+
return $handler->handle($command);
154+
}
155+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.