@@ -112,12 +112,12 @@ private function parseImports(\DOMDocument $xml, string $file)
112
112
}
113
113
}
114
114
115
- private function parseDefinitions (\DOMDocument $ xml , string $ file , array $ defaults )
115
+ private function parseDefinitions (\DOMDocument $ xml , string $ file , Definition $ defaults )
116
116
{
117
117
$ xpath = new \DOMXPath ($ xml );
118
118
$ xpath ->registerNamespace ('container ' , self ::NS );
119
119
120
- if (false === $ services = $ xpath ->query ('//container:services/container:service|//container:services/container:prototype ' )) {
120
+ if (false === $ services = $ xpath ->query ('//container:services/container:service|//container:services/container:prototype|//container:services/container:stack ' )) {
121
121
return ;
122
122
}
123
123
$ this ->setCurrentDir (\dirname ($ file ));
@@ -126,12 +126,34 @@ private function parseDefinitions(\DOMDocument $xml, string $file, array $defaul
126
126
$ this ->isLoadingInstanceof = true ;
127
127
$ instanceof = $ xpath ->query ('//container:services/container:instanceof ' );
128
128
foreach ($ instanceof as $ service ) {
129
- $ this ->setDefinition ((string ) $ service ->getAttribute ('id ' ), $ this ->parseDefinition ($ service , $ file , [] ));
129
+ $ this ->setDefinition ((string ) $ service ->getAttribute ('id ' ), $ this ->parseDefinition ($ service , $ file , new Definition () ));
130
130
}
131
131
132
132
$ this ->isLoadingInstanceof = false ;
133
133
foreach ($ services as $ service ) {
134
- if (null !== $ definition = $ this ->parseDefinition ($ service , $ file , $ defaults )) {
134
+ if ('stack ' === $ service ->tagName ) {
135
+ $ service ->setAttribute ('parent ' , '- ' );
136
+ $ definition = $ this ->parseDefinition ($ service , $ file , $ defaults )
137
+ ->setTags (array_merge_recursive (['container.stack ' => [[]]], $ defaults ->getTags ()))
138
+ ;
139
+ $ this ->setDefinition ($ id = (string ) $ service ->getAttribute ('id ' ), $ definition );
140
+ $ stack = [];
141
+
142
+ foreach ($ this ->getChildren ($ service , 'service ' ) as $ k => $ frame ) {
143
+ $ k = $ frame ->getAttribute ('id ' ) ?: $ k ;
144
+ $ frame ->setAttribute ('id ' , $ id .'" at index " ' .$ k );
145
+
146
+ if ($ alias = $ frame ->getAttribute ('alias ' )) {
147
+ $ this ->validateAlias ($ frame , $ file );
148
+ $ stack [$ k ] = new Reference ($ alias );
149
+ } else {
150
+ $ stack [$ k ] = $ this ->parseDefinition ($ frame , $ file , $ defaults )
151
+ ->setInstanceofConditionals ($ this ->instanceof );
152
+ }
153
+ }
154
+
155
+ $ definition ->setArguments ($ stack );
156
+ } elseif (null !== $ definition = $ this ->parseDefinition ($ service , $ file , $ defaults )) {
135
157
if ('prototype ' === $ service ->tagName ) {
136
158
$ excludes = array_column ($ this ->getChildren ($ service , 'exclude ' ), 'nodeValue ' );
137
159
if ($ service ->hasAttribute ('exclude ' )) {
@@ -148,60 +170,33 @@ private function parseDefinitions(\DOMDocument $xml, string $file, array $defaul
148
170
}
149
171
}
150
172
151
- /**
152
- * Get service defaults.
153
- */
154
- private function getServiceDefaults (\DOMDocument $ xml , string $ file ): array
173
+ private function getServiceDefaults (\DOMDocument $ xml , string $ file ): Definition
155
174
{
156
175
$ xpath = new \DOMXPath ($ xml );
157
176
$ xpath ->registerNamespace ('container ' , self ::NS );
158
177
159
178
if (null === $ defaultsNode = $ xpath ->query ('//container:services/container:defaults ' )->item (0 )) {
160
- return [];
161
- }
162
-
163
- $ bindings = [];
164
- foreach ($ this ->getArgumentsAsPhp ($ defaultsNode , 'bind ' , $ file ) as $ argument => $ value ) {
165
- $ bindings [$ argument ] = new BoundArgument ($ value , true , BoundArgument::DEFAULTS_BINDING , $ file );
179
+ return new Definition ();
166
180
}
167
181
168
- $ defaults = [
169
- 'tags ' => $ this ->getChildren ($ defaultsNode , 'tag ' ),
170
- 'bind ' => $ bindings ,
171
- ];
172
-
173
- foreach ($ defaults ['tags ' ] as $ tag ) {
174
- if ('' === $ tag ->getAttribute ('name ' )) {
175
- throw new InvalidArgumentException (sprintf ('The tag name for tag "<defaults>" in "%s" must be a non-empty string. ' , $ file ));
176
- }
177
- }
182
+ $ defaultsNode ->setAttribute ('id ' , '<defaults> ' );
178
183
179
- if ($ defaultsNode ->hasAttribute ('autowire ' )) {
180
- $ defaults ['autowire ' ] = XmlUtils::phpize ($ defaultsNode ->getAttribute ('autowire ' ));
181
- }
182
- if ($ defaultsNode ->hasAttribute ('public ' )) {
183
- $ defaults ['public ' ] = XmlUtils::phpize ($ defaultsNode ->getAttribute ('public ' ));
184
- }
185
- if ($ defaultsNode ->hasAttribute ('autoconfigure ' )) {
186
- $ defaults ['autoconfigure ' ] = XmlUtils::phpize ($ defaultsNode ->getAttribute ('autoconfigure ' ));
187
- }
188
-
189
- return $ defaults ;
184
+ return $ this ->parseDefinition ($ defaultsNode , $ file , new Definition ());
190
185
}
191
186
192
187
/**
193
188
* Parses an individual Definition.
194
189
*/
195
- private function parseDefinition (\DOMElement $ service , string $ file , array $ defaults ): ?Definition
190
+ private function parseDefinition (\DOMElement $ service , string $ file , Definition $ defaults ): ?Definition
196
191
{
197
192
if ($ alias = $ service ->getAttribute ('alias ' )) {
198
193
$ this ->validateAlias ($ service , $ file );
199
194
200
195
$ this ->container ->setAlias ((string ) $ service ->getAttribute ('id ' ), $ alias = new Alias ($ alias ));
201
196
if ($ publicAttr = $ service ->getAttribute<
10000
/span>('public ' )) {
202
197
$ alias ->setPublic (XmlUtils::phpize ($ publicAttr ));
203
- } elseif (isset ( $ defaults ['public ' ]) ) {
204
- $ alias ->setPublic ($ defaults[ ' public ' ] );
198
+ } elseif ($ defaults-> getChanges () ['public ' ] ?? false ) {
199
+ $ alias ->setPublic ($ defaults-> isPublic () );
205
200
}
206
201
207
202
if ($ deprecated = $ this ->getChildren ($ service , 'deprecated ' )) {
@@ -231,16 +226,11 @@ private function parseDefinition(\DOMElement $service, string $file, array $defa
231
226
$ definition = new Definition ();
232
227
}
233
228
234
- if (isset ( $ defaults ['public ' ]) ) {
235
- $ definition ->setPublic ($ defaults[ ' public ' ] );
229
+ if ($ defaults-> getChanges () ['public ' ] ?? false ) {
230
+ $ definition ->setPublic ($ defaults-> isPublic () );
236
231
}
237
- if (isset ($ defaults ['autowire ' ])) {
238
- $ definition ->setAutowired ($ defaults ['autowire ' ]);
239
- }
240
- if (isset ($ defaults ['autoconfigure ' ])) {
241
- $ definition ->setAutoconfigured ($ defaults ['autoconfigure ' ]);
242
- }
243
-
232
+ $ definition ->setAutowired ($ defaults ->isAutowired ());
233
+ $ definition ->setAutoconfigured ($ defaults ->isAutoconfigured ());
244
234
$ definition ->setChanges ([]);
245
235
246
236
foreach (['class ' , 'public ' , 'shared ' , 'synthetic ' , 'abstract ' ] as $ key ) {
@@ -324,10 +314,6 @@ private function parseDefinition(\DOMElement $service, string $file, array $defa
324
314
325
315
$ tags = $ this ->getChildren ($ service , 'tag ' );
326
316
327
- if (!empty ($ defaults ['tags ' ])) {
328
- $ tags = array_merge ($ tags , $ defaults ['tags ' ]);
329
- }
330
-
331
317
foreach ($ tags as $ tag ) {
332
318
$ parameters = [];
333
319
foreach ($ tag ->attributes as $ name => $ node ) {
@@ -349,16 +335,17 @@ private function parseDefinition(\DOMElement $service, string $file, array $defa
349
335
$ definition->addTag ($ tag ->getAttribute ('name ' ), $ parameters );
350
336
}
351
337
338
+ $ definition ->setTags (array_merge_recursive ($ definition ->getTags (), $ defaults ->getTags ()));
339
+
352
340
$ bindings = $ this ->getArgumentsAsPhp ($ service , 'bind ' , $ file );
353
341
$ bindingType = $ this ->isLoadingInstanceof ? BoundArgument::INSTANCEOF_BINDING : BoundArgument::SERVICE_BINDING ;
354
342
foreach ($ bindings as $ argument => $ value ) {
355
343
$ bindings [$ argument ] = new BoundArgument ($ value , true , $ bindingType , $ file );
356
344
}
357
345
358
- if (isset ($ defaults ['bind ' ])) {
359
- // deep clone, to avoid multiple process of the same instance in the passes
360
- $ bindings = array_merge (unserialize (serialize ($ defaults ['bind ' ])), $ bindings );
361
- }
346
+ // deep clone, to avoid multiple process of the same instance in the passes
347
+ $ bindings = array_merge (unserialize (serialize ($ defaults ->getBindings ())), $ bindings );
348
+
362
349
if ($ bindings ) {
363
350
$ definition ->setBindings ($ bindings );
364
351
}
@@ -443,7 +430,7 @@ private function processAnonymousServices(\DOMDocument $xml, string $file)
443
430
// resolve definitions
444
431
uksort ($ definitions , 'strnatcmp ' );
445
432
foreach (array_reverse ($ definitions ) as $ id => list ($ domElement , $ file )) {
446
- if (null !== $ definition = $ this ->parseDefinition ($ domElement , $ file , [] )) {
433
+ if (null !== $ definition = $ this ->parseDefinition ($ domElement , $ file , new Definition () )) {
447
434
$ this ->setDefinition ($ id , $ definition );
448
435
}
449
436
}
0 commit comments