12
12
namespace Symfony \Component \DependencyInjection \Compiler ;
13
13
14
14
use Symfony \Component \DependencyInjection \Argument \IteratorArgument ;
15
+ use Symfony \Component \DependencyInjection \Container ;
15
16
use Symfony \Component \DependencyInjection \Definition ;
16
17
use Symfony \Component \DependencyInjection \Exception \InvalidArgumentException ;
17
18
use Symfony \Component \DependencyInjection \Exception \InvalidParameterTypeException ;
@@ -79,27 +80,27 @@ protected function processValue($value, $isRoot = false)
79
80
/**
80
81
* @throws InvalidArgumentException When not enough parameters are defined for the method
81
82
*/
82
- private function checkTypeDeclarations (Definition $ checkedDefinition , \ReflectionFunctionAbstract $ reflectionFunction , array $ configurationArguments ): void
83
+ private function checkTypeDeclarations (Definition $ checkedDefinition , \ReflectionFunctionAbstract $ reflectionFunction , array $ values ): void
83
84
{
84
85
$ numberOfRequiredParameters = $ reflectionFunction ->getNumberOfRequiredParameters ();
85
86
86
- if (\count ($ configurationArguments ) < $ numberOfRequiredParameters ) {
87
- throw new InvalidArgumentException (sprintf ('Invalid definition for service "%s": "%s::%s()" requires %d arguments, %d passed. ' , $ this ->currentId , $ reflectionFunction ->class , $ reflectionFunction ->name , $ numberOfRequiredParameters , \count ($ configurationArguments )));
87
+ if (\count ($ values ) < $ numberOfRequiredParameters ) {
88
+ throw new InvalidArgumentException (sprintf ('Invalid definition for service "%s": "%s::%s()" requires %d arguments, %d passed. ' , $ this ->currentId , $ reflectionFunction ->class , $ reflectionFunction ->name , $ numberOfRequiredParameters , \count ($ values )));
88
89
}
89
90
90
91
$ reflectionParameters = $ reflectionFunction ->getParameters ();
91
- $ checksCount = min ($ reflectionFunction ->getNumberOfParameters (), \count ($ configurationArguments ));
92
+ $ checksCount = min ($ reflectionFunction ->getNumberOfParameters (), \count ($ values ));
92
93
93
94
for ($ i = 0 ; $ i < $ checksCount ; ++$ i ) {
94
95
if (!$ reflectionParameters [$ i ]->hasType () || $ reflectionParameters [$ i ]->isVariadic ()) {
95
96
continue ;
96
97
}
97
98
98
- $ this ->checkType ($ checkedDefinition , $ configurationArguments [$ i ], $ reflectionParameters [$ i ]);
99
+ $ this ->checkType ($ checkedDefinition , $ values [$ i ], $ reflectionParameters [$ i ]);
99
100
}
100
101
101
102
if ($ reflectionFunction ->isVariadic () && ($ lastParameter = end ($ reflectionParameters ))->hasType ()) {
102
- $ variadicParameters = \array_slice ($ configurationArguments , $ lastParameter ->getPosition ());
103
+ $ variadicParameters = \array_slice ($ values , $ lastParameter ->getPosition ());
103
104
104
105
foreach ($ variadicParameters as $ variadicParameter ) {
105
106
$ this ->checkType ($ checkedDefinition , $ variadicParameter , $ lastParameter );
@@ -110,63 +111,82 @@ private function checkTypeDeclarations(Definition $checkedDefinition, \Reflectio
110
111
/**
111
112
* @throws InvalidParameterTypeException When a parameter is not compatible with the declared type
112
113
*/
113
- private function checkType (Definition $ checkedDefinition , $ configurationArgument , \ReflectionParameter $ parameter ): void
114
+ private function checkType (Definition $ checkedDefinition , $ value , \ReflectionParameter $ parameter ): void
114
115
{
115
- $ parameterTypeName = $ parameter ->getType ()->getName ();
116
+ $ type = $ parameter ->getType ()->getName ();
116
117
117
- $ referencedDefinition = $ configurationArgument ;
118
+ if ($ value instanceof Reference) {
119
+ if (!$ this ->container ->has ($ value = (string ) $ value )) {
120
+ return ;
121
+ }
118
122
119
- if ($ referencedDefinition instanceof Reference) {
120
- if (!$ this ->container ->has ($ referencedDefinition )) {
123
+ if ('service_container ' === $ value && is_a ($ type , Container::class, true )) {
121
124
return ;
122
125
}
123
126
124
- $ referencedDefinition = $ this ->container ->findDefinition (( string ) $ referencedDefinition );
127
+ $ value = $ this ->container ->findDefinition ($ value );
125
128
}
126
129
127
- if ('self ' === $ parameterTypeName ) {
128
- $ parameterTypeName = $ parameter ->getDeclaringClass ()->getName ();
130
+ if ('self ' === $ type ) {
131
+ $ type = $ parameter ->getDeclaringClass ()->getName ();
129
132
}
130
- if ('static ' === $ parameterTypeName ) {
131
- $ parameterTypeName = $ checkedDefinition ->getClass ();
133
+
134
+ if ('static ' === $ type ) {
135
+ $ type = $ checkedDefinition ->getClass ();
132
136
}
133
137
134
- if ($ referencedDefinition instanceof Definition) {
135
- $ class = $ referencedDefinition ->getClass ();
138
+ if ($ value instanceof Definition) {
139
+ $ class = $ value ->getClass ();
136
140
137
141
if (!$ class || (!$ this ->autoload && !class_exists ($ class , false ) && !interface_exists ($ class , false ))) {
138
142
return ;
139
143
}
140
144
141
- if (!is_a ($ class , $ parameterTypeName , true )) {
142
- throw new InvalidParameterTypeException ($ this ->currentId , $ class , $ parameter );
143
- }
144
- } else {
145
- if (null === $ configurationArgument && $ parameter ->allowsNull ()) {
145
+ if ('callable ' === $ type && method_exists ($ class , '__invoke ' )) {
146
146
return ;
147
147
}
148
148
149
- if (\in_array ( $ parameterTypeName , self :: SCALAR_TYPES , true ) && is_scalar ( $ configurationArgument )) {
149
+ if (' iterable ' === $ type && is_subclass_of ( $ class , ' Traversable ' )) {
150
150
return ;
151
151
}
152
152
153
- if (' iterable ' === $ parameterTypeName && $ configurationArgument instanceof IteratorArgument ) {
153
+ if (is_a ( $ class , $ type , true ) ) {
154
154
return ;
155
155
}
156
156
157
- if ('Traversable ' === $ parameterTypeName && $ configurationArgument instanceof IteratorArgument) {
158
- return ;
159
- }
157
+ throw new InvalidParameterTypeException ($ this ->currentId , $ class , $ parameter );
158
+ }
160
159
161
- if ($ configurationArgument instanceof Parameter) {
162
- return ;
163
- }
160
+ if ($ value instanceof Parameter) {
161
+ $ value = $ this ->container ->getParameter ($ value );
162
+ } elseif (\is_string ($ value ) && '% ' === ($ value [0 ] ?? '' ) && preg_match ('/^%([^%]+)%$/ ' , $ value , $ match )) {
163
+ $ value = $ this ->container ->getParameter ($ match [1 ]);
164
+ }
164
165
165
- $ checkFunction = sprintf ('is_%s ' , $ parameter ->getType ()->getName ());
166
+ if (null === $ value && $ parameter ->allowsNull ()) {
167
+ return ;
168
+ }
166
169
167
- if (!$ parameter ->getType ()->isBuiltin () || !$ checkFunction ($ configurationArgument )) {
168
- throw new InvalidParameterTypeException ($ this ->currentId , \gettype ($ configurationArgument ), $ parameter );
169
- }
170
+ if (\in_array ($ type , self ::SCALAR_TYPES , true ) && is_scalar ($ value )) {
171
+ return ;
172
+ }
173
+
174
+ if ('callable ' === $ type && \is_array ($ value ) && isset ($ value [0 ]) && ($ value [0 ] instanceof Reference || $ value [0 ] instanceof Definition)) {
175
+ return ;
176
+ }
177
+
178
+ if ('iterable ' === $ type && (\is_array ($ value ) || $ value instanceof \Traversable || $ value instanceof IteratorArgument)) {
179
+ return ;
180
+ }
181
+
182
+ if ('Traversable ' === $ type && ($ value instanceof \Traversable || $ value instanceof IteratorArgument)) {
183
+ return ;
184
+ }
185
+
186
+ $ checkFunction = sprintf ('is_%s ' , $ parameter ->getType ()->getName ());
187
+
188
+ if (!$ parameter ->getType ()->isBuiltin () || !$ checkFunction ($ value )) {
189
+ throw new InvalidParameterTypeException ($ this ->currentId , \gettype ($ value ), $ parameter );
170
190
}
171
191
}
172
192
}
0 commit comments