1212use PhpParser \Node \Name ;
1313use PhpParser \Node \Stmt \Class_ ;
1414use PhpParser \Node \Stmt \ClassMethod ;
15+ use Rector \Doctrine \NodeAnalyzer \AttributeFinder ;
1516use Rector \NodeManipulator \ClassDependencyManipulator ;
17+ use Rector \PhpParser \Node \Value \ValueResolver ;
1618use Rector \PostRector \ValueObject \PropertyMetadata ;
1719use Rector \Rector \AbstractRector ;
1820use Rector \StaticTypeMapper \StaticTypeMapper ;
1921use Rector \Symfony \Bridge \NodeAnalyzer \ControllerMethodAnalyzer ;
22+ use Rector \Symfony \Enum \SensioAttribute ;
2023use Rector \Symfony \Enum \SymfonyClass ;
2124use Rector \Symfony \TypeAnalyzer \ControllerAnalyzer ;
2225use Rector \ValueObject \MethodName ;
@@ -33,6 +36,8 @@ public function __construct(
3336 private readonly ControllerMethodAnalyzer $ controllerMethodAnalyzer ,
3437 private readonly ClassDependencyManipulator $ classDependencyManipulator ,
3538 private readonly StaticTypeMapper $ staticTypeMapper ,
39+ private readonly AttributeFinder $ attributeFinder ,
40+ private readonly ValueResolver $ valueResolver ,
3641 ) {
3742 }
3843
@@ -108,15 +113,23 @@ public function refactor(Node $node): ?Node
108113 continue ;
109114 }
110115
116+ $ entityClasses = $ this ->resolveParamConverterEntityClasses ($ classMethod );
117+
111118 foreach ($ classMethod ->getParams () as $ key => $ param ) {
112119 // skip scalar and empty values, as not services
113120 if ($ param ->type === null || $ param ->type instanceof Identifier) {
114121 continue ;
115122 }
116123
117124 // request is allowed
118- if ($ param ->type instanceof Name && $ this ->isName ($ param ->type , SymfonyClass::REQUEST )) {
119- continue ;
125+ if ($ param ->type instanceof Name) {
126+ if ($ this ->isName ($ param ->type , SymfonyClass::REQUEST )) {
127+ continue ;
128+ }
129+
130+ if ($ this ->isNames ($ param ->type , $ entityClasses )) {
131+ continue ;
132+ }
120133 }
121134
122135 // @todo allow parameter converter
@@ -188,4 +201,31 @@ private function shouldSkipClassMethod(ClassMethod $classMethod): bool
188201
189202 return ! $ this ->controllerMethodAnalyzer ->isAction ($ classMethod );
190203 }
204+
205+ /**
206+ * @return string[]
207+ */
208+ private function resolveParamConverterEntityClasses (ClassMethod $ classMethod ): array
209+ {
210+ $ entityClasses = [];
211+
212+ $ paramConverterAttributes = $ this ->attributeFinder ->findManyByClass (
213+ $ classMethod ,
214+ SensioAttribute::PARAM_CONVERTER
215+ );
216+ foreach ($ paramConverterAttributes as $ paramConverterAttribute ) {
217+ foreach ($ paramConverterAttribute ->args as $ arg ) {
218+ if ($ arg ->name instanceof Identifier && $ this ->isName ($ arg ->name , 'class ' )) {
219+ $ entityClass = $ this ->valueResolver ->getValue ($ arg ->value );
220+ if (! is_string ($ entityClass )) {
221+ continue ;
222+ }
223+
224+ $ entityClasses [] = $ entityClass ;
225+ }
226+ }
227+ }
228+
229+ return $ entityClasses ;
230+ }
191231}
0 commit comments