77use PhpParser \Node ;
88use PhpParser \Node \Arg ;
99use PhpParser \Node \Attribute ;
10+ use PhpParser \Node \Expr ;
1011use PhpParser \Node \Expr \MethodCall ;
1112use PhpParser \Node \Expr \Variable ;
1213use PhpParser \Node \Identifier ;
1920use PhpParser \NodeVisitor ;
2021use PHPStan \Reflection \ReflectionProvider ;
2122use PHPStan \Type \ObjectType ;
23+ use Rector \Doctrine \NodeAnalyzer \AttributeFinder ;
2224use Rector \NodeTypeResolver \Node \AttributeKey ;
2325use Rector \Rector \AbstractRector ;
2426use Rector \Symfony \Enum \CommandMethodName ;
@@ -38,6 +40,7 @@ final class CommandHelpToAttributeRector extends AbstractRector implements MinPh
3840{
3941 public function __construct (
4042 private readonly ReflectionProvider $ reflectionProvider ,
43+ private readonly AttributeFinder $ attributeFinder
4144 ) {
4245 }
4346
@@ -53,8 +56,10 @@ public function getRuleDefinition(): RuleDefinition
5356 [
5457 new CodeSample (
5558 <<<'CODE_SAMPLE'
59+ use Symfony\Component\Console\Attribute\AsCommand;
5660use Symfony\Component\Console\Command\Command;
5761
62+ #[AsCommand(name: 'app:some')]
5863final class SomeCommand extends Command
5964{
6065 protected function configure(): void
@@ -105,8 +110,8 @@ public function refactor(Node $node): ?Node
105110 return null ;
106111 }
107112
108- $ asCommandAttribute = $ this ->getAsCommandAttribute ($ node );
109- if ($ asCommandAttribute === null ) {
113+ $ asCommandAttribute = $ this ->attributeFinder -> findAttributeByClass ($ node, SymfonyAttribute:: AS_COMMAND );
114+ if (! $ asCommandAttribute instanceof Attribute ) {
110115 return null ;
111116 }
112117
@@ -126,15 +131,15 @@ public function refactor(Node $node): ?Node
126131 return null ;
127132 }
128133
129- $ wrappedHelp = new String_ (
134+ $ wrappedHelpString = new String_ (
130135 $ helpExpr ->value ,
131136 [
132137 Attributekey::KIND => String_::KIND_NOWDOC ,
133138 AttributeKey::DOC_LABEL => 'TXT ' ,
134139 ]
135140 );
136141
137- $ asCommandAttribute ->args [] = new Arg ($ wrappedHelp , false , false , [], new Identifier ('help ' ));
142+ $ asCommandAttribute ->args [] = new Arg ($ wrappedHelpString , false , false , [], new Identifier ('help ' ));
138143
139144 if ($ configureClassMethod ->stmts === []) {
140145 unset($ configureClassMethod );
@@ -143,29 +148,16 @@ public function refactor(Node $node): ?Node
143148 return $ node ;
144149 }
145150
146- private function getAsCommandAttribute (Class_ $ class ): ?Attribute
147- {
148- foreach ($ class ->attrGroups as $ attrGroup ) {
149- foreach ($ attrGroup ->attrs as $ attribute ) {
150- if ($ this ->nodeNameResolver ->isName ($ attribute ->name , SymfonyAttribute::AS_COMMAND )) {
151- return $ attribute ;
152- }
153- }
154- }
155-
156- return null ;
157- }
158-
159151 /**
160152 * Returns the argument passed to setHelp() and removes the MethodCall node.
161153 */
162- private function findAndRemoveSetHelpExpr (ClassMethod $ configureMethod ): ?String_
154+ private function findAndRemoveSetHelpExpr (ClassMethod $ configureClassMethod ): ?String_
163155 {
164156 $ helpString = null ;
165157
166158 $ this ->traverseNodesWithCallable (
167- (array ) $ configureMethod ->stmts ,
168- function (Node $ node ) use (&$ helpString ) {
159+ (array ) $ configureClassMethod ->stmts ,
160+ function (Node $ node ) use (&$ helpString ): int | null | Expr {
169161 if ($ node instanceof Class_ || $ node instanceof Function_) {
170162 return NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN ;
171163 }
@@ -196,9 +188,9 @@ function (Node $node) use (&$helpString) {
196188 }
197189 );
198190
199- foreach ((array ) $ configureMethod ->stmts as $ key => $ stmt ) {
191+ foreach ((array ) $ configureClassMethod ->stmts as $ key => $ stmt ) {
200192 if ($ this ->isExpressionVariableThis ($ stmt )) {
201- unset($ configureMethod ->stmts [$ key ]);
193+ unset($ configureClassMethod ->stmts [$ key ]);
202194 }
203195 }
204196
0 commit comments