77use PhpParser \Node ;
88use PhpParser \Node \Arg ;
99use PhpParser \Node \Expr ;
10+ use PhpParser \Node \Expr \BinaryOp ;
1011use PhpParser \Node \Expr \BinaryOp \Equal ;
1112use PhpParser \Node \Expr \BinaryOp \Identical ;
13+ use PhpParser \Node \Expr \BinaryOp \NotEqual ;
14+ use PhpParser \Node \Expr \BinaryOp \NotIdentical ;
15+ use PhpParser \Node \Expr \BooleanNot ;
16+ use PhpParser \Node \Expr \FuncCall ;
1217use PhpParser \Node \Expr \MethodCall ;
1318use PhpParser \Node \Expr \StaticCall ;
19+ use PhpParser \Node \Identifier ;
1420use PhpParser \Node \Scalar \String_ ;
1521use PHPStan \Type \ObjectType ;
1622use RectorLaravel \AbstractRector ;
@@ -25,82 +31,145 @@ class AppEnvironmentComparisonToParameterRector extends AbstractRector
2531 public function getRuleDefinition (): RuleDefinition
2632 {
2733 return new RuleDefinition (
28- 'Replace `$ app-> environment() === \' local \' ` with `$app->environment( \' local \' )` ' ,
34+ 'Replace app environment comparison with parameter or method call ' ,
2935 [
3036 new CodeSample (
3137 <<<'CODE_SAMPLE'
32- $app->environment() === 'production';
38+ $app->environment() === 'local';
39+ $app->environment() !== 'production';
40+ $app->environment() === 'testing';
41+ in_array($app->environment(), ['local', 'testing']);
3342CODE_SAMPLE
3443 ,
3544 <<<'CODE_SAMPLE'
36- $app->environment('production');
45+ $app->isLocal();
46+ ! $app->isProduction();
47+ $app->environment('testing');
48+ $app->environment(['local', 'testing']);
3749CODE_SAMPLE
3850 ),
3951 ]
4052 );
4153 }
4254
55+ /** @return list<class-string<Node>> */
4356 public function getNodeTypes (): array
4457 {
45- return [Expr ::class];
58+ return [FuncCall::class, Identical::class, Equal::class, NotIdentical::class, NotEqual ::class];
4659 }
4760
48- public function refactor (Node $ node ): MethodCall |StaticCall |null
61+ /** @param FuncCall|Identical|Equal|NotIdentical|NotEqual $node */
62+ public function refactor (Node $ node ): ?Expr
4963 {
50- if (! $ node instanceof Identical && ! $ node instanceof Equal) {
64+ if ($ node instanceof FuncCall) {
65+ [$ methodCall , $ otherNode ] = $ this ->handleFuncCall ($ node );
66+ } else {
67+ [$ methodCall , $ otherNode ] = $ this ->handleBinaryOp ($ node );
68+ }
69+
70+ if ($ methodCall === null || $ otherNode === null ) {
5171 return null ;
5272 }
5373
54- /** @var MethodCall|StaticCall|null $methodCall */
74+ $ methodName = null ;
75+
76+ if ($ otherNode instanceof String_) {
77+ $ methodName = $ this ->getMethodName ($ methodCall , $ otherNode ->value );
78+ }
79+
80+ if ($ methodName === null ) {
81+ $ methodCall ->args [] = new Arg ($ otherNode );
82+ } else {
83+ $ methodCall ->name = new Identifier ($ methodName );
84+ }
85+
86+ if ($ node instanceof NotIdentical || $ node instanceof NotEqual) {
87+ return new BooleanNot ($ methodCall );
88+ }
89+
90+ return $ methodCall ;
91+ }
92+
93+ /** @return array{0: MethodCall|StaticCall|null, 1: Expr|null} */
94+ private function handleFuncCall (FuncCall $ funcCall ): array
95+ {
96+ if (! $ this ->isName ($ funcCall ->name , 'in_array ' )) {
97+ return [null , null ];
98+ }
99+
100+ $ methodCall = $ funcCall ->getArg ('needle ' , 0 );
101+ $ haystack = $ funcCall ->getArg ('haystack ' , 1 );
102+
103+ if (! $ haystack instanceof Arg || ! $ methodCall instanceof Arg || ! $ this ->validMethodCall ($ methodCall ->value )) {
104+ return [null , null ];
105+ }
106+
107+ return [$ methodCall ->value , $ haystack ->value ];
108+ }
109+
110+ /** @return array{0: MethodCall|StaticCall|null, 1: Expr|null} */
111+ private function handleBinaryOp (BinaryOp $ binaryOp ): array
112+ {
55113 $ methodCall = array_values (
56114 array_filter (
57- [$ node ->left , $ node ->right ],
58- fn ($ node ) => ($ node instanceof MethodCall || $ node instanceof StaticCall) && $ this ->isName (
59- $ node ->name ,
60- 'environment '
61- )
115+ [$ binaryOp ->left , $ binaryOp ->right ],
116+ fn ($ node ) => $ this ->validMethodCall ($ node ),
62117 )
63118 )[0 ] ?? null ;
64119
65- if ($ methodCall === null || ! $ this ->validMethodCall ($ methodCall )) {
66- return null ;
67- }
68-
69- /** @var Expr $otherNode */
70120 $ otherNode = array_values (
71- array_filter ([$ node ->left , $ node ->right ], static fn ($ node ) => $ node !== $ methodCall )
121+ array_filter ([$ binaryOp ->left , $ binaryOp ->right ], static fn ($ node ) => $ node !== $ methodCall )
72122 )[0 ] ?? null ;
73123
74- if (! $ otherNode instanceof String_) {
75- return null ;
76- }
124+ return [$ methodCall , $ otherNode ];
125+ }
77126
78- // make sure the method call has no arguments
79- if ($ methodCall ->getArgs () !== []) {
80- return null ;
127+ /** @phpstan-assert-if-true MethodCall|StaticCall $node */
128+ private function validMethodCall (Node $ node ): bool
129+ {
130+ if (! $ node instanceof MethodCall && ! $ node instanceof StaticCall) {
131+ return false ;
81132 }
82133
83- $ methodCall ->args [] = new Arg ($ otherNode );
134+ if (! $ this ->isName ($ node ->name , 'environment ' )) {
135+ return false ;
136+ }
84137
85- return $ methodCall ;
86- }
138+ // make sure the method call has no arguments
139+ if ($ node ->getArgs () !== []) {
140+ return false ;
141+ }
87142
88- private function validMethodCall (MethodCall |StaticCall $ methodCall ): bool
89- {
90143 return match (true ) {
91- $ methodCall instanceof MethodCall && $ this ->isObjectType (
92- $ methodCall ->var ,
144+ $ node instanceof MethodCall && $ this ->isObjectType (
145+ $ node ->var ,
93146 new ObjectType ('Illuminate\Contracts\Foundation\Application ' )
94147 ) => true ,
95- $ methodCall instanceof StaticCall && $ this ->isObjectType (
96- $ methodCall ->class ,
148+ $ node instanceof StaticCall && $ this ->isObjectType (
149+ $ node ->class ,
97150 new ObjectType ('Illuminate\Support\Facades\App ' )
98151 ) => true ,
99- $ methodCall instanceof StaticCall && $ this ->isObjectType (
100- $ methodCall ->class ,
152+ $ node instanceof StaticCall && $ this ->isObjectType (
153+ $ node ->class ,
101154 new ObjectType ('App ' )
102155 ) => true ,
103156 default => false ,
104157 };
105158 }
159+
160+ private function getMethodName (MethodCall |StaticCall $ methodCall , string $ environment ): ?string
161+ {
162+ if (
163+ $ methodCall instanceof MethodCall
164+ && ! $ this ->isObjectType ($ methodCall ->var , new ObjectType ('Illuminate\Foundation\Application ' ))
165+ ) {
166+ return null ;
167+ }
168+
169+ return match ($ environment ) {
170+ 'local ' => 'isLocal ' ,
171+ 'production ' => 'isProduction ' ,
172+ default => null ,
173+ };
174+ }
106175}
0 commit comments