88use PhpParser \Node \Expr \Closure ;
99use PhpParser \Node \Expr \PropertyFetch ;
1010use PhpParser \Node \Expr \Variable ;
11- use PhpParser \Node \Identifier ;
1211use PhpParser \Node \Name \FullyQualified ;
1312use PhpParser \Node \Stmt \Class_ ;
1413use PhpParser \Node \Stmt \ClassMethod ;
15- use Rector \ Doctrine \ NodeAnalyzer \ AttributeFinder ;
14+ use PHPStan \ Type \ ObjectType ;
1615use Rector \NodeManipulator \ClassDependencyManipulator ;
1716use Rector \NodeTypeResolver \Node \AttributeKey ;
18- use Rector \PhpParser \Node \Value \ValueResolver ;
1917use Rector \PostRector \ValueObject \PropertyMetadata ;
2018use Rector \Rector \AbstractRector ;
2119use Rector \StaticTypeMapper \StaticTypeMapper ;
2220use Rector \Symfony \Bridge \NodeAnalyzer \ControllerMethodAnalyzer ;
21+ use Rector \Symfony \CodeQuality \NodeAnalyzer \ParamConverterClassesResolver ;
2322use Rector \Symfony \Enum \FosClass ;
24- use Rector \Symfony \Enum \SensioAttribute ;
2523use Rector \Symfony \Enum \SymfonyClass ;
2624use Rector \Symfony \TypeAnalyzer \ControllerAnalyzer ;
2725use Rector \ValueObject \MethodName ;
@@ -44,8 +42,7 @@ public function __construct(
4442 private readonly ControllerMethodAnalyzer $ controllerMethodAnalyzer ,
4543 private readonly ClassDependencyManipulator $ classDependencyManipulator ,
4644 private readonly StaticTypeMapper $ staticTypeMapper ,
47- private readonly AttributeFinder $ attributeFinder ,
48- private readonly ValueResolver $ valueResolver ,
45+ private readonly ParamConverterClassesResolver $ paramConverterClassesResolver ,
4946 private readonly ParentClassMethodTypeOverrideGuard $ parentClassMethodTypeOverrideGuard
5047 ) {
5148 }
@@ -126,7 +123,7 @@ public function refactor(Node $node): ?Node
126123 continue ;
127124 }
128125
129- $ entityClasses = $ this ->resolveParamConverterEntityClasses ($ classMethod );
126+ $ entityClasses = $ this ->paramConverterClassesResolver -> resolveEntityClasses ($ classMethod );
130127
131128 foreach ($ classMethod ->getParams () as $ key => $ param ) {
132129 // skip scalar and empty values, as not services
@@ -139,12 +136,11 @@ public function refactor(Node $node): ?Node
139136 continue ;
140137 }
141138
142- // request is allowed
143- if ($ this ->isNames ($ param ->type , [SymfonyClass::REQUEST , FosClass::PARAM_FETCHER ])) {
144- continue ;
145- }
146-
147- if ($ this ->isNames ($ param ->type , $ entityClasses )) {
139+ // skip allowed known objectsallowed
140+ if ($ this ->isNames (
141+ $ param ->type ,
142+ [SymfonyClass::USER_INTERFACE , SymfonyClass::REQUEST , FosClass::PARAM_FETCHER , ...$ entityClasses ]
143+ )) {
148144 continue ;
149145 }
150146
@@ -154,10 +150,15 @@ public function refactor(Node $node): ?Node
154150 }
155151 }
156152
157- // @todo allow parameter converter
158- unset($ classMethod ->params [$ key ]);
159-
160153 $ paramType = $ this ->staticTypeMapper ->mapPhpParserNodePHPStanType ($ param ->type );
154+
155+ if ($ paramType instanceof ObjectType) {
156+ if ($ paramType ->isEnum ()->yes ()) {
157+ continue ;
158+ }
159+ }
160+
161+ unset($ classMethod ->params [$ key ]);
161162 $ propertyMetadatas [] = new PropertyMetadata ($ this ->getName ($ param ->var ), $ paramType );
162163 }
163164 }
@@ -182,39 +183,9 @@ public function refactor(Node $node): ?Node
182183 continue ;
183184 }
184185
185- // replace param use with property fetch
186- $ this ->traverseNodesWithCallable ((array ) $ classMethod ->stmts , function (Node $ node ) use (
187- $ paramNamesToReplace
188- ): Closure |null |PropertyFetch {
189- if ($ node instanceof Closure) {
190- foreach ($ node ->uses as $ key => $ closureUse ) {
191- if ($ this ->isNames ($ closureUse ->var , $ paramNamesToReplace )) {
192- unset($ node ->uses [$ key ]);
193- }
194- }
195-
196- return $ node ;
197- }
198-
199- if (! $ node instanceof Variable) {
200- return null ;
201- }
202-
203- if (! $ this ->isNames ($ node , $ paramNamesToReplace )) {
204- return null ;
205- }
206-
207- if ($ node ->getAttribute (AttributeKey::IS_BEING_ASSIGNED ) === true ) {
208- return null ;
209- }
210-
211- $ propertyName = $ this ->getName ($ node );
212- return new PropertyFetch (new Variable ('this ' ), $ propertyName );
213- });
186+ $ this ->replaceParamUseWithPropertyFetch ($ classMethod , $ paramNamesToReplace );
214187 }
215188
216- // 2. replace in method bodies
217-
218189 return $ node ;
219190 }
220191
@@ -232,29 +203,41 @@ private function shouldSkipClassMethod(ClassMethod $classMethod): bool
232203 }
233204
234205 /**
235- * @return string[]
206+ * @param string[] $paramNamesToReplace
236207 */
237- private function resolveParamConverterEntityClasses (ClassMethod $ classMethod ): array
208+ private function replaceParamUseWithPropertyFetch (ClassMethod $ classMethod, array $ paramNamesToReplace ): void
238209 {
239- $ entityClasses = [];
210+ if ($ classMethod ->stmts === null ) {
211+ return ;
212+ }
240213
241- $ paramConverterAttributes = $ this ->attributeFinder ->findManyByClass (
242- $ classMethod ,
243- SensioAttribute::PARAM_CONVERTER
244- );
245- foreach ($ paramConverterAttributes as $ paramConverterAttribute ) {
246- foreach ($ paramConverterAttribute ->args as $ arg ) {
247- if ($ arg ->name instanceof Identifier && $ this ->isName ($ arg ->name , 'class ' )) {
248- $ entityClass = $ this ->valueResolver ->getValue ($ arg ->value );
249- if (! is_string ($ entityClass )) {
250- continue ;
214+ $ this ->traverseNodesWithCallable ($ classMethod ->stmts , function (Node $ node ) use (
215+ $ paramNamesToReplace
216+ ): Closure |null |PropertyFetch {
217+ if ($ node instanceof Closure) {
218+ foreach ($ node ->uses as $ key => $ closureUse ) {
219+ if ($ this ->isNames ($ closureUse ->var , $ paramNamesToReplace )) {
220+ unset($ node ->uses [$ key ]);
251221 }
252-
253- $ entityClasses [] = $ entityClass ;
254222 }
223+
224+ return $ node ;
225+ }
226+
227+ if (! $ node instanceof Variable) {
228+ return null ;
229+ }
230+
231+ if (! $ this ->isNames ($ node , $ paramNamesToReplace )) {
232+ return null ;
233+ }
234+
235+ if ($ node ->getAttribute (AttributeKey::IS_BEING_ASSIGNED ) === true ) {
236+ return null ;
255237 }
256- }
257238
258- return $ entityClasses ;
239+ $ propertyName = $ this ->getName ($ node );
240+ return new PropertyFetch (new Variable ('this ' ), $ propertyName );
241+ });
259242 }
260243}
0 commit comments