@@ -32,6 +32,12 @@ class AutowirePass extends AbstractRecursivePass
3232 private $ autowired = array ();
3333 private $ lastFailure ;
3434 private $ throwOnAutowiringException ;
35+ private $ decoratedClass ;
36+ private $ decoratedId ;
37+ private $ methodCalls ;
38+ private $ getPreviousValue ;
39+ private $ decoratedMethodIndex ;
40+ private $ decoratedMethodArgumentIndex ;
3541
3642 public function __construct (bool $ throwOnAutowireException = true )
3743 {
@@ -49,6 +55,12 @@ public function process(ContainerBuilder $container)
4955 $ this ->types = null ;
5056 $ this ->ambiguousServiceTypes = array ();
5157 $ 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 ;
5264 }
5365 }
5466
@@ -89,7 +101,7 @@ private function doProcessValue($value, $isRoot = false)
89101 return $ value ;
90102 }
91103
92- $ methodCalls = $ value ->getMethodCalls ();
104+ $ this -> methodCalls = $ value ->getMethodCalls ();
93105
94106 try {
95107 $ constructor = $ this ->getConstructor ($ value , false );
@@ -98,35 +110,42 @@ private function doProcessValue($value, $isRoot = false)
98110 }
99111
100112 if ($ constructor ) {
101- array_unshift ($ methodCalls , array ($ constructor , $ value ->getArguments ()));
113+ array_unshift ($ this -> methodCalls , array ($ constructor , $ value ->getArguments ()));
102114 }
103115
104- $ methodCalls = $ this ->autowireCalls ($ reflectionClass , $ methodCalls );
116+ $ this -> methodCalls = $ this ->autowireCalls ($ reflectionClass , $ isRoot );
105117
106118 if ($ constructor ) {
107- list (, $ arguments ) = array_shift ($ methodCalls );
119+ list (, $ arguments ) = array_shift ($ this -> methodCalls );
108120
109121 if ($ arguments !== $ value ->getArguments ()) {
110122 $ value ->setArguments ($ arguments );
111123 }
112124 }
113125
114- if ($ methodCalls !== $ value ->getMethodCalls ()) {
115- $ value ->setMethodCalls ($ methodCalls );
126+ if ($ this -> methodCalls !== $ value ->getMethodCalls ()) {
127+ $ value ->setMethodCalls ($ this -> methodCalls );
116128 }
117129
118130 return $ value ;
119131 }
120132
121133 /**
122134 * @param \ReflectionClass $reflectionClass
123- * @param array $methodCalls
124135 *
125136 * @return array
126137 */
127- private function autowireCalls (\ReflectionClass $ reflectionClass , array $ methodCalls )
138+ private function autowireCalls (\ReflectionClass $ reflectionClass , bool $ isRoot ): array
128139 {
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 ;
130149 list ($ method , $ arguments ) = $ call ;
131150
132151 if ($ method instanceof \ReflectionFunctionAbstract) {
@@ -138,11 +157,11 @@ private function autowireCalls(\ReflectionClass $reflectionClass, array $methodC
138157 $ arguments = $ this ->autowireMethod ($ reflectionMethod , $ arguments );
139158
140159 if ($ arguments !== $ call [1 ]) {
141- $ methodCalls [$ i ][1 ] = $ arguments ;
160+ $ this -> methodCalls [$ i ][1 ] = $ arguments ;
142161 }
143162 }
144163
145- return $ methodCalls ;
164+ return $ this -> methodCalls ;
146165 }
147166
148167 /**
@@ -190,18 +209,40 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
190209 continue ;
191210 }
192211
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.
195232
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 ;
200242 }
201- $ this ->container ->log ($ this , $ failureMessage );
202243 }
203244
204- $ arguments [$ index ] = $ value ;
245+ $ arguments [$ index ] = $ getValue () ;
205246 }
206247
207248 if ($ parameters && !isset ($ arguments [++$ index ])) {
0 commit comments