25
25
use Symfony \Component \DependencyInjection \Reference ;
26
26
use Symfony \Component \DependencyInjection \TypedReference ;
27
27
use Symfony \Component \VarExporter \ProxyHelper ;
28
- use Symfony \Contracts \Service \Attribute \SubscribedService ;
29
28
30
29
/**
31
30
* Inspects existing service definitions and wires the autowired ones using the type hints of their classes.
@@ -106,18 +105,19 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
106
105
private function doProcessValue (mixed $ value , bool $ isRoot = false ): mixed
107
106
{
108
107
if ($ value instanceof TypedReference) {
109
- if ($ attributes = $ value ->getAttributes ()) {
110
- $ attribute = array_pop ($ attributes );
111
-
112
- if ($ attributes ) {
113
- throw new AutowiringFailedException ($ this ->currentId , sprintf ('Using multiple attributes with "%s" is not supported. ' , SubscribedService::class));
108
+ foreach ($ value ->getAttributes () as $ attribute ) {
109
+ if ($ attribute === $ v = $ this ->processValue ($ attribute )) {
110
+ continue ;
114
111
}
115
-
116
- if (!$ attribute instanceof Target) {
117
- return $ this ->processAttribute ($ attribute , ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $ value ->getInvalidBehavior ());
112
+ if (!$ attribute instanceof Autowire || !$ v instanceof Reference) {
113
+ return $ v ;
118
114
}
119
115
120
- $ value = new TypedReference ($ value ->getType (), $ value ->getType (), $ value ->getInvalidBehavior (), $ attribute ->name , [$ attribute ]);
116
+ $ invalidBehavior = ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE !== $ v ->getInvalidBehavior () ? $ v ->getInvalidBehavior () : $ value ->getInvalidBehavior ();
117
+ $ value = $ v instanceof TypedReference
118
+ ? new TypedReference ($ v , $ v ->getType (), $ invalidBehavior , $ v ->getName () ?? $ value ->getName (), array_merge ($ v ->getAttributes (), $ value ->getAttributes ()))
119
+ : new TypedReference ($ v , $ value ->getType (), $ invalidBehavior , $ value ->getName (), $ value ->getAttributes ());
120
+ break ;
121
121
}
122
122
if ($ ref = $ this ->getAutowiredReference ($ value , true )) {
123
123
return $ ref ;
@@ -173,22 +173,6 @@ private function doProcessValue(mixed $value, bool $isRoot = false): mixed
173
173
return $ value ;
174
174
}
175
175
176
- private function processAttribute (object $ attribute , bool $ isOptional = false ): mixed
177
- {
178
- switch (true ) {
179
- case $ attribute instanceof Autowire:
180
- if ($ isOptional && $ attribute ->value instanceof Reference) {
181
- return new Reference ($ attribute ->value , ContainerInterface::NULL_ON_INVALID_REFERENCE );
182
- }
183
- // no break
184
- case $ attribute instanceof AutowireDecorated:
185
- case $ attribute instanceof MapDecorated:
186
- return $ this ->processValue ($ attribute );
187
- }
188
-
189
- throw new AutowiringFailedException ($ this ->currentId , sprintf ('"%s" is an unsupported attribute. ' , $ attribute ::class));
190
- }
191
-
192
176
private function autowireCalls (\ReflectionClass $ reflectionClass , bool $ isRoot , bool $ checkAttributes ): array
193
177
{
194
178
$ this ->decoratedId = null ;
@@ -281,11 +265,15 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
281
265
}
282
266
283
267
$ type = ProxyHelper::exportType ($ parameter , true );
268
+ $ target = null ;
269
+ $ name = Target::parseName ($ parameter , $ target );
270
+ $ target = $ target ? [$ target ] : [];
284
271
285
272
if ($ checkAttributes ) {
286
273
foreach ($ parameter ->getAttributes (Autowire::class, \ReflectionAttribute::IS_INSTANCEOF ) as $ attribute ) {
287
274
$ attribute = $ attribute ->newInstance ();
288
- $ value = $ this ->processAttribute ($ attribute , $ parameter ->allowsNull ());
275
+ $ invalidBehavior = $ parameter ->allowsNull () ? ContainerInterface::NULL_ON_INVALID_REFERENCE : ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE ;
276
+ $ value = $ this ->processValue (new TypedReference ($ type ?: '? ' , $ type ?: 'mixed ' , $ invalidBehavior , $ name , [$ attribute , ...$ target ]));
289
277
290
278
if ($ attribute instanceof AutowireCallable || 'Closure ' === $ type && \is_array ($ value )) {
291
279
$ value = (new Definition ('Closure ' ))
@@ -299,13 +287,13 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
299
287
}
300
288
301
289
foreach ($ parameter ->getAttributes (AutowireDecorated::class) as $ attribute ) {
302
- $ arguments [$ index ] = $ this ->processAttribute ($ attribute ->newInstance (), $ parameter -> allowsNull ());
290
+ $ arguments [$ index ] = $ this ->processValue ($ attribute ->newInstance ());
303
291
304
292
continue 2 ;
305
293
}
306
294
307
295
foreach ($ parameter ->getAttributes (MapDecorated::class) as $ attribute ) {
308
- $ arguments [$ index ] = $ this ->processAttribute ($ attribute ->newInstance (), $ parameter -> allowsNull ());
296
+ $ arguments [$ index ] = $ this ->processValue ($ attribute ->newInstance ());
309
297
310
298
continue 2 ;
311
299
}
@@ -338,9 +326,8 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
338
326
continue ;
339
327
}
340
328
341
- $ getValue = function () use ($ type , $ parameter , $ class , $ method ) {
342
- $ name = Target::parseName ($ parameter , $ target );
343
- if (!$ value = $ this ->getAutowiredReference ($ ref = new TypedReference ($ type , $ type , ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE , $ name , $ target ? [$ target ] : []), false )) {
329
+ $ getValue = function () use ($ type , $ parameter , $ class , $ method , $ name , $ target ) {
330
+ if (!$ value = $ this ->getAutowiredReference ($ ref = new TypedReference ($ type , $ type , ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE , $ name , $ target ), false )) {
344
331
$ failureMessage = $ this ->createTypeNotFoundMessageCallback ($ ref , sprintf ('argument "$%s" of method "%s()" ' , $ parameter ->name , $ class !== $ this ->currentId ? $ class .':: ' .$ method : $ method ));
345
332
346
333
if ($ parameter ->isDefaultValueAvailable ()) {
@@ -354,7 +341,7 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
354
341
return $ value ;
355
342
};
356
343
357
- if ($ this ->decoratedClass && $ isDecorated = is_a ($ this ->decoratedClass , $ type , true )) {
344
+ if ($ this ->decoratedClass && is_a ($ this ->decoratedClass , $ type , true )) {
358
345
if ($ this ->getPreviousValue ) {
359
346
// The inner service is injected only if there is only 1 argument matching the type of the decorated class
360
347
// across all arguments of all autowired methods.
@@ -412,7 +399,9 @@ private function getAutowiredReference(TypedReference $reference, bool $filterTy
412
399
$ type = implode ($ m [0 ], $ types );
413
400
}
414
401
415
- if (null !== $ name = $ reference ->getName ()) {
402
+ $ name = (array_filter ($ reference ->getAttributes (), static fn ($ a ) => $ a instanceof Target)[0 ] ?? null )?->name;
403
+
404
+ if (null !== $ name ??= $ reference ->getName ()) {
416
405
if ($ this ->container ->has ($ alias = $ type .' $ ' .$ name ) && !$ this ->container ->findDefinition ($ alias )->isAbstract ()) {
417
406
return new TypedReference ($ alias , $ type , $ reference ->getInvalidBehavior ());
418
407
}
0 commit comments