@@ -32,6 +32,12 @@ class AutowirePass extends AbstractRecursivePass
32
32
private $ autowired = array ();
33
33
private $ lastFailure ;
34
34
private $ throwOnAutowiringException ;
35
+ private $ decoratedClass ;
36
+ private $ decoratedId ;
37
+ private $ methodCalls ;
38
+ private $ getPreviousValue ;
39
+ private $ decoratedMethodIndex ;
40
+ private $ decoratedMethodArgumentIndex ;
35
41
36
42
public function __construct (bool $ throwOnAutowireException = true )
37
43
{
@@ -49,6 +55,12 @@ public function process(ContainerBuilder $container)
49
55
$ this ->types = null ;
50
56
$ this ->ambiguousServiceTypes = array ();
51
57
$ this ->autowired = array ();
58
+ $ this ->decoratedClass = null ;
59
+ $ this ->decoratedId = null ;
60
+ $ this ->methodCalls = null ;
61
+ $ this ->getPreviousValue = null ;
62
+ $ this ->decoratedMethodIndex = null ;
63
+ $ this ->decoratedMethodArgumentIndex = null ;
52
64
}
53
65
}
54
66
@@ -89,7 +101,7 @@ private function doProcessValue($value, $isRoot = false)
89
101
return $ value ;
90
102
}
91
103
92
- $ methodCalls = $ value ->getMethodCalls ();
104
+ $ this -> methodCalls = $ value ->getMethodCalls ();
93
105
94
106
try {
95
107
$ constructor = $ this ->getConstructor ($ value , false );
@@ -98,35 +110,42 @@ private function doProcessValue($value, $isRoot = false)
98
110
}
99
111
100
112
if ($ constructor ) {
101
- array_unshift ($ methodCalls , array ($ constructor , $ value ->getArguments ()));
113
+ array_unshift ($ this -> methodCalls , array ($ constructor , $ value ->getArguments ()));
102
114
}
103
115
104
- $ methodCalls = $ this ->autowireCalls ($ reflectionClass , $ methodCalls );
116
+ $ this -> methodCalls = $ this ->autowireCalls ($ reflectionClass , $ isRoot );
105
117
106
118
if ($ constructor ) {
107
- list (, $ arguments ) = array_shift ($ methodCalls );
119
+ list (, $ arguments ) = array_shift ($ this -> methodCalls );
108
120
109
121
if ($ arguments !== $ value ->getArguments ()) {
110
122
$ value ->setArguments ($ arguments );
111
123
}
112
124
}
113
125
114
- if ($ methodCalls !== $ value ->getMethodCalls ()) {
115
- $ value ->setMethodCalls ($ methodCalls );
126
+ if ($ this -> methodCalls !== $ value ->getMethodCalls ()) {
127
+ $ value ->setMethodCalls ($ this -> methodCalls );
116
128
}
117
129
118
130
return $ value ;
119
131
}
120
132
121
133
/**
122
134
* @param \ReflectionClass $reflectionClass
123
- * @param array $methodCalls
124
135
*
125
136
* @return array
126
137
*/
127
- private function autowireCalls (\ReflectionClass $ reflectionClass , array $ methodCalls )
138
+ private function autowireCalls (\ReflectionClass $ reflectionClass , bool $ isRoot ): array
128
139
{
129
- foreach ($ methodCalls as $ i => $ call ) {
140
+ if ($ isRoot && ($ definition = $ this ->container ->getDefinition ($ this ->currentId )) && $ this ->container ->has ($ this ->decoratedId = $ definition ->innerServiceId )) {
141
+ $ this ->decoratedClass = $ this ->container ->findDefinition ($ this ->decoratedId )->getClass ();
142
+ } else {
143
+ $ this ->decoratedId = null ;
144
+ $ this ->decoratedClass = null ;
145
+ }
146
+
147
+ foreach ($ this ->methodCalls as $ i => $ call ) {
148
+ $ this ->decoratedMethodIndex = $ i ;
130
149
list ($ method , $ arguments ) = $ call ;
131
150
132
151
if ($ method instanceof \ReflectionFunctionAbstract) {
@@ -138,11 +157,11 @@ private function autowireCalls(\ReflectionClass $reflectionClass, array $methodC
138
157
$ arguments = $ this ->autowireMethod ($ reflectionMethod , $ arguments );
139
158
140
159
if ($ arguments !== $ call [1 ]) {
141
- $ methodCalls [$ i ][1 ] = $ arguments ;
160
+ $ this -> methodCalls [$ i ][1 ] = $ arguments ;
142
161
}
143
162
}
144
163
145
- return $ methodCalls ;
164
+ return $ this -> methodCalls ;
146
165
}
147
166
148
167
/**
@@ -190,18 +209,40 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
190
209
continue ;
191
210
}
192
211
193
- if (!$ value = $ this ->getAutowiredReference ($ ref = new TypedReference ($ type , $ type , !$ parameter ->isOptional () ? $ class : '' ), 'for ' .sprintf ('argument "$%s" of method "%s()" ' , $ parameter ->name , $ class .':: ' .$ method ))) {
194
- $ failureMessage = $ this ->createTypeNotFoundMessage ($ ref , sprintf ('argument "$%s" of method "%s()" ' , $ parameter ->name , $ class !== $ this ->currentId ? $ class .':: ' .$ method : $ method ));
212
+ $ getValue = function () use ($ type , $ parameter , $ class , $ method ) {
213
+ if (!$ value = $ this ->getAutowiredReference ($ ref = new TypedReference ($ type , $ type , !$ parameter ->isOptional () ? $ class : '' ), 'for ' .sprintf ('argument "$%s" of method "%s()" ' , $ parameter ->name , $ class .':: ' .$ method ))) {
214
+ $ failureMessage = $ this ->createTypeNotFoundMessage ($ ref , sprintf ('argument "$%s" of method "%s()" ' , $ parameter ->name , $ class !== $ this ->currentId ? $ class .':: ' .$ method : $ method ));
215
+
216
+ if ($ parameter ->isDefaultValueAvailable ()) {
217
+ $ value = $ parameter ->getDefaultValue ();
218
+ } elseif (!$ parameter ->allowsNull ()) {
219
+ throw new AutowiringFailedException ($ this ->currentId , $ failureMessage );
220
+ }
221
+ $ this ->container ->log ($ this , $ failureMessage );
222
+ }
223
+
224
+ return $ value ;
225
+ };
226
+
227
+ if ($ this ->decoratedClass && $ isDecorated = is_a ($ this ->decoratedClass , $ type , true )) {
228
+ if ($ this ->getPreviousValue ) {
229
+ // The inner service is injected only if there is only 1 argument matching the type of the decorated class
230
+ // across all arguments of all autowired methods.
231
+ // If a second matching argument is found, the default behavior is restored.
195
232
196
- if ($ parameter ->isDefaultValueAvailable ()) {
197
- $ value = $ parameter ->getDefaultValue ();
198
- } elseif (!$ parameter ->allowsNull ()) {
199
- throw new AutowiringFailedException ($ this ->currentId , $ failureMessage );
233
+ $ getPreviousValue = $ this ->getPreviousValue ;
234
+ $ this ->methodCalls [$ this ->decoratedMethodIndex ][1 ][$ this ->decoratedMethodArgumentIndex ] = $ getPreviousValue ();
235
+ $ this ->decoratedClass = null ; // Prevent further checks
236
+ } else {
237
+ $ arguments [$ index ] = new TypedReference ($ this ->decoratedId , $ this ->decoratedClass );
238
+ $ this ->getPreviousValue = $ getValue ;
239
+ $ this ->decoratedMethodArgumentIndex = $ index ;
240
+
241
+ continue ;
200
242
}
201
- $ this ->container ->log ($ this , $ failureMessage );
202
243
}
203
244
204
- $ arguments [$ index ] = $ value ;
245
+ $ arguments [$ index ] = $ getValue () ;
205
246
}
206
247
207
248
if ($ parameters && !isset ($ arguments [++$ index ])) {
0 commit comments