1212use PhpParser \Node \Identifier ;
1313use PhpParser \Node \Name ;
1414use PHPStan \Broker \ClassNotFoundException ;
15- use PHPStan \Reflection \ClassReflection ;
1615use PHPStan \Reflection \ReflectionProvider ;
1716use PHPStan \Type \ClosureType ;
1817use PHPStan \Type \ObjectType ;
1918use Rector \Rector \AbstractRector ;
19+ use Rector \StaticTypeMapper \ValueObject \Type \AliasedObjectType ;
2020use Symplify \RuleDocGenerator \ValueObject \CodeSample \CodeSample ;
2121use Symplify \RuleDocGenerator \ValueObject \RuleDefinition ;
2222
2525 */
2626class DispatchNonShouldQueueToDispatchSyncRector extends AbstractRector
2727{
28+ private const string SHOULD_QUEUE_INTERFACE = 'Illuminate\Contracts\Queue\ShouldQueue ' ;
29+
30+ private const string BUS_FACADE = 'Illuminate\Support\Facades\Bus ' ;
31+
32+ private const string DISPATCHER_INTERFACE = 'Illuminate\Contracts\Bus\Dispatcher ' ;
33+
34+ private const string DISPATCHABLE_TRAIT = 'Illuminate\Foundation\Bus\Dispatchable ' ;
35+
2836 public function __construct (private readonly ReflectionProvider $ reflectionProvider )
2937 {
3038 }
@@ -92,20 +100,17 @@ public function refactor(Node $node): FuncCall|MethodCall|StaticCall|null
92100
93101 private function processCall (FuncCall |MethodCall |StaticCall $ call ): FuncCall |MethodCall |StaticCall |null
94102 {
95- static $ shouldQueueType = new ObjectType ('Illuminate\Contracts\Queue\ShouldQueue ' );
96-
97103 if (! $ call ->args [0 ] instanceof Arg) {
98104 return null ;
99105 }
100106
107+ static $ objectType = new ObjectType (self ::SHOULD_QUEUE_INTERFACE );
108+ $ argumentType = $ this ->getType ($ call ->args [0 ]->value );
109+
101110 if (
102- $ this ->getType ($ call ->args [0 ]->value )->isSuperTypeOf (
103- $ shouldQueueType
104- )->yes () ||
105- $ this ->isObjectType (
106- $ call ->args [0 ]->value ,
107- $ shouldQueueType
108- )
111+ $ argumentType ->isSuperTypeOf ($ objectType )->yes () ||
112+ $ this ->isObjectType ($ call ->args [0 ]->value , $ objectType ) ||
113+ $ argumentType instanceof AliasedObjectType && $ this ->isSubclassOfShouldQueueInterface ($ argumentType )
109114 ) {
110115 return null ;
111116 }
@@ -141,7 +146,7 @@ private function isDispatchablesCall(MethodCall $methodCall): bool
141146 $ type ->getClassName ()
142147 );
143148
144- if ($ this -> usesDispatchablesTrait ( $ reflection )) {
149+ if ($ reflection -> hasTraitUse ( self :: DISPATCHABLE_TRAIT )) {
145150 return true ;
146151 }
147152
@@ -151,22 +156,26 @@ private function isDispatchablesCall(MethodCall $methodCall): bool
151156 return false ;
152157 }
153158
154- private function usesDispatchablesTrait ( ClassReflection $ classReflection ): bool
159+ private function isSubclassOfShouldQueueInterface ( AliasedObjectType $ aliasedObjectType ): bool
155160 {
156- return in_array (
157- 'Illuminate\Foundation\Bus\Dispatchable ' ,
158- array_keys ($ classReflection ->getTraits (true )),
159- true
160- );
161+ try {
162+ $ reflection = $ this ->reflectionProvider ->getClass (
163+ $ aliasedObjectType ->getFullyQualifiedName (),
164+ );
165+ } catch (ClassNotFoundException ) {
166+ return false ;
167+ }
168+
169+ return $ reflection ->isSubclassOf (self ::SHOULD_QUEUE_INTERFACE );
161170 }
162171
163172 private function isCallOnBusFacade (StaticCall $ staticCall ): bool
164173 {
165- return $ this ->isName ($ staticCall ->class , ' Illuminate\Support\Facades\Bus ' );
174+ return $ this ->isName ($ staticCall ->class , self :: BUS_FACADE );
166175 }
167176
168177 private function isCallOnDispatcherContract (MethodCall $ methodCall ): bool
169178 {
170- return $ this ->isObjectType ($ methodCall ->var , new ObjectType (' Illuminate\Contracts\Bus\Dispatcher ' ));
179+ return $ this ->isObjectType ($ methodCall ->var , new ObjectType (self :: DISPATCHER_INTERFACE ));
171180 }
172181}
0 commit comments