4
4
Using a Factory to Create Services
5
5
==================================
6
6
7
- Symfony's Service Container provides a powerful way of controlling the
8
- creation of objects, allowing you to specify arguments passed to the constructor
9
- as well as calling methods and setting parameters. Sometimes, however, this
10
- will not provide you with everything you need to construct your objects.
11
- For this situation, you can use a factory to create the object and tell
12
- the service container to call a method on the factory rather than directly
13
- instantiating the class.
7
+ Symfony's Service Container provides multiple features to control the creation
8
+ of objects, allowing you to specify arguments passed to the constructor as well
9
+ as calling methods and setting parameters.
10
+
11
+ However, sometimes you need to apply the `factory design pattern `_ to delegate
12
+ the object creation to some special object called "the factory". In those cases,
13
+ the service container can call a method on your factory to create the object
14
+ rather than directly instantiating the class.
15
+
16
+ Static Factories
17
+ ----------------
14
18
15
19
Suppose you have a factory that configures and returns a new ``NewsletterManager ``
16
20
object by calling the static ``createNewsletterManager() `` method::
@@ -27,9 +31,9 @@ object by calling the static ``createNewsletterManager()`` method::
27
31
}
28
32
}
29
33
30
- To make the ``NewsletterManager `` object available as a service, you can
31
- configure the service container to use the
32
- `` NewsletterManagerStaticFactory::createNewsletterManager() `` factory method :
34
+ To make the ``NewsletterManager `` object available as a service, use the
35
+ `` factory `` option to define which method of which class must be called to
36
+ create its object :
33
37
34
38
.. configuration-block ::
35
39
@@ -40,7 +44,7 @@ configure the service container to use the
40
44
# ...
41
45
42
46
App\Email\NewsletterManager :
43
- # call the static method
47
+ # the first argument is the class and the second argument is the static method
44
48
factory : ['App\Email\NewsletterManagerStaticFactory', 'createNewsletterManager']
45
49
46
50
.. code-block :: xml
@@ -54,7 +58,7 @@ configure the service container to use the
54
58
55
59
<services >
56
60
<service id =" App\Email\NewsletterManager" >
57
- <!-- call the static method -->
61
+ <!-- the first argument is the class and the second argument is the static method -->
58
62
<factory class =" App\Email\NewsletterManagerStaticFactory" method =" createNewsletterManager" />
59
63
60
64
<!-- if the factory class is the same as the service class, you can omit
@@ -77,8 +81,8 @@ configure the service container to use the
77
81
return function(ContainerConfigurator $configurator) {
78
82
$services = $configurator->services();
79
83
80
- // call the static method
81
84
$services->set(NewsletterManager::class)
85
+ // the first argument is the class and the second argument is the static method
82
86
->factory([NewsletterManagerStaticFactory::class, 'createNewsletterManager']);
83
87
};
84
88
@@ -91,11 +95,11 @@ configure the service container to use the
91
95
the configured class name may be used by compiler passes and therefore
92
96
should be set to a sensible value.
93
97
94
- If your factory is not using a static function to configure and create your
95
- service, but a regular method, you can instantiate the factory itself as a
96
- service too. Later, in the ":ref: `factories-passing-arguments-factory-method `"
97
- section, you learn how you can inject arguments in this method.
98
+ Non-Static Factories
99
+ --------------------
98
100
101
+ If your factory is using a regular method instead of a static one to configure
102
+ and create the service, instantiate the factory itself as a service too.
99
103
Configuration of the service container then looks like this:
100
104
101
105
.. configuration-block ::
@@ -106,10 +110,12 @@ Configuration of the service container then looks like this:
106
110
services :
107
111
# ...
108
112
113
+ # first, create a service for the factory
109
114
App\Email\NewsletterManagerFactory : ~
110
115
116
+ # second, use the factory service as the first argument of the 'factory'
117
+ # option and the factory method as the second argument
111
118
App\Email\NewsletterManager :
112
- # call a method on the specified factory service
113
119
factory : ['@App\Email\NewsletterManagerFactory', 'createNewsletterManager']
114
120
115
121
.. code-block :: xml
@@ -122,10 +128,12 @@ Configuration of the service container then looks like this:
122
128
https://symfony.com/schema/dic/services/services-1.0.xsd" >
123
129
124
130
<services >
131
+ <!-- first, create a service for the factory -->
125
132
<service id =" App\Email\NewsletterManagerFactory" />
126
133
134
+ <!-- second, use the factory service as the first argument of the 'factory'
135
+ option and the factory method as the second argument -->
127
136
<service id =" App\Email\NewsletterManager" >
128
- <!-- call a method on the specified factory service -->
129
137
<factory service =" App\Email\NewsletterManagerFactory"
130
138
method =" createNewsletterManager"
131
139
/>
@@ -144,15 +152,20 @@ Configuration of the service container then looks like this:
144
152
return function(ContainerConfigurator $configurator) {
145
153
$services = $configurator->services();
146
154
155
+ // first, create a service for the factory
147
156
$services->set(NewsletterManagerFactory::class);
148
157
149
- // call a method on the specified factory service
158
+ // second, use the factory service as the first argument of the 'factory'
159
+ // method and the factory method as the second argument
150
160
$services->set(NewsletterManager::class)
151
161
->factory([ref(NewsletterManagerFactory::class), 'createNewsletterManager']);
152
162
};
153
163
154
164
.. _factories-invokable :
155
165
166
+ Invokable Factories
167
+ -------------------
168
+
156
169
Suppose you now change your factory method to ``__invoke() `` so that your
157
170
factory service can be used as a callback::
158
171
@@ -230,8 +243,8 @@ Passing Arguments to the Factory Method
230
243
that's enabled for your service.
231
244
232
245
If you need to pass arguments to the factory method you can use the ``arguments ``
233
- options . For example, suppose the ``createNewsletterManager() `` method in the previous
234
- example takes the ``templating `` service as an argument:
246
+ option . For example, suppose the ``createNewsletterManager() `` method in the
247
+ previous examples takes the ``templating `` service as an argument:
235
248
236
249
.. configuration-block ::
237
250
@@ -281,3 +294,4 @@ example takes the ``templating`` service as an argument:
281
294
;
282
295
};
283
296
297
+ .. _`factory design pattern` : https://en.wikipedia.org/wiki/Factory_(object-oriented_programming)
0 commit comments