Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dispatch to DispatchSync with non queueable job #182

Merged
Merged
5 changes: 5 additions & 0 deletions config/sets/laravel100.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use RectorLaravel\Rector\Cast\DatabaseExpressionCastsToMethodCallRector;
use RectorLaravel\Rector\Class_\ReplaceExpectsMethodsInTestsRector;
use RectorLaravel\Rector\Class_\UnifyModelDatesWithCastsRector;
use RectorLaravel\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector;
use RectorLaravel\Rector\MethodCall\DatabaseExpressionToStringToMethodCallRector;
use RectorLaravel\Rector\MethodCall\ReplaceWithoutJobsEventsAndNotificationsWithFacadeFakeRector;
use RectorLaravel\Rector\StaticCall\ReplaceAssertTimesSendWithAssertSentTimesRector;
Expand Down Expand Up @@ -48,4 +49,8 @@
// https://github.com/laravel/framework/pull/42591/files
'dispatch_now' => 'dispatch_sync',
]);

// https://laravel.com/docs/10.x/upgrade#dispatch-return
$rectorConfig
->rule(DispatchNonShouldQueueToDispatchSyncRector::class);
};
19 changes: 18 additions & 1 deletion docs/rector_rules_overview.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 54 Rules Overview
# 56 Rules Overview

## AddArgumentDefaultValueRector

Expand Down Expand Up @@ -433,6 +433,23 @@ Convert DB Expression `__toString()` calls to `getValue()` method calls.

<br>

## DispatchNonShouldQueueToDispatchSyncRector

Dispatch non ShouldQueue jobs to dispatchSync

- class: [`RectorLaravel\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector`](../src/Rector/FuncCall/DispatchNonShouldQueueToDispatchSyncRector.php)

```diff
-dispatch(new SomeJob());
-Bus::dispatch(new SomeJob());
-$this->dispatch(new SomeJob());
+dispatch_sync(new SomeJob());
+Bus::dispatchSync(new SomeJob());
+$this->dispatchSync(new SomeJob());
```

<br>

## EloquentMagicMethodToQueryBuilderRector

The EloquentMagicMethodToQueryBuilderRule is designed to automatically transform certain magic method calls on Eloquent Models into corresponding Query Builder method calls.
Expand Down
156 changes: 156 additions & 0 deletions src/Rector/FuncCall/DispatchNonShouldQueueToDispatchSyncRector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
<?php

namespace RectorLaravel\Rector\FuncCall;

use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PHPStan\Broker\ClassNotFoundException;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\ObjectType;
use Rector\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

/**
* @see \RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\DispatchNonShouldQueueToDispatchSyncRectorTest
*/
class DispatchNonShouldQueueToDispatchSyncRector extends AbstractRector
{
public function __construct(private readonly ReflectionProvider $reflectionProvider)
{
}

public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
'Dispatch non ShouldQueue jobs to dispatchSync',
[
new CodeSample(
<<<'CODE_SAMPLE'
dispatch(new SomeJob());
Bus::dispatch(new SomeJob());
$this->dispatch(new SomeJob());
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
dispatch_sync(new SomeJob());
Bus::dispatchSync(new SomeJob());
$this->dispatchSync(new SomeJob());
CODE_SAMPLE
),
]
);
}

public function getNodeTypes(): array
{
return [FuncCall::class, MethodCall::class, StaticCall::class];
}

/**
* @param FuncCall|MethodCall|StaticCall $node
*/
public function refactor(Node $node): FuncCall|MethodCall|StaticCall|null
{
if (
$this->isName($node->name, 'dispatch') &&
count($node->args) === 1
) {
if (
$node instanceof MethodCall &&
! $this->isDispatchablesCall($node) &&
! $this->isCallOnDispatcherContract($node)
) {
return null;
}

if (
$node instanceof StaticCall
&& ! $this->isCallOnBusFacade($node)
) {
return null;
}

$newNode = $this->processCall($node);

if ($newNode !== null) {
return $newNode;
}
}

return null;
}

private function processCall(FuncCall|MethodCall|StaticCall $call): FuncCall|MethodCall|StaticCall|null
{
static $shouldQueueType = new ObjectType('Illuminate\Contracts\Queue\ShouldQueue');

if (! $call->args[0] instanceof Arg) {
return null;
}

if (
$this->getType($call->args[0]->value)->isSuperTypeOf(
$shouldQueueType
)->yes() ||
$this->isObjectType(
$call->args[0]->value,
$shouldQueueType
)
) {
return null;
}

$call->name = $call instanceof FuncCall ? new Name('dispatch_sync') : new Identifier('dispatchSync');

return $call;
}

private function isDispatchablesCall(MethodCall $methodCall): bool
{
$type = $this->getType($methodCall->var);
if (! $type instanceof ObjectType) {
return false;
}

try {
// Will trigger ClassNotFoundException if the class definition is not found
$reflection = $this->reflectionProvider->getClass(
$type->getClassName()
);

if ($this->usesDispatchablesTrait($reflection)) {
return true;
}

} catch (ClassNotFoundException) {
}

return false;
}

private function usesDispatchablesTrait(ClassReflection $classReflection): bool
{
return in_array(
'Illuminate\Foundation\Bus\Dispatchable',
array_keys($classReflection->getTraits(true)),
true
);
}

private function isCallOnBusFacade(StaticCall $staticCall): bool
{
return $this->isName($staticCall->class, 'Illuminate\Support\Facades\Bus');
}

private function isCallOnDispatcherContract(MethodCall $methodCall): bool
{
return $this->isObjectType($methodCall->var, new ObjectType('Illuminate\Contracts\Bus\Dispatcher'));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector;

use Iterator;
use PHPUnit\Framework\Attributes\DataProvider;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

final class DispatchNonShouldQueueToDispatchSyncRectorTest extends AbstractRectorTestCase
{
public static function provideData(): Iterator
{
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
}

/**
* @test
*/
#[DataProvider('provideData')]
public function test(string $filePath): void
{
$this->doTestFile($filePath);
}

public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Fixture;

use RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Source\SomeJob;

\Illuminate\Support\Facades\Bus::dispatch(new SomeJob());

?>
-----
<?php

namespace RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Fixture;

use RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Source\SomeJob;

\Illuminate\Support\Facades\Bus::dispatchSync(new SomeJob());

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Fixture;

use RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Source\ClassWithDispatchableTrait;
use RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Source\SomeJob;

(new ClassWithDispatchableTrait())->dispatch(new SomeJob());

?>
-----
<?php

namespace RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Fixture;

use RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Source\ClassWithDispatchableTrait;
use RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Source\SomeJob;

(new ClassWithDispatchableTrait())->dispatchSync(new SomeJob());

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Fixture;

use RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Source\SomeJob;

class SomeClass
{
public function run(\Illuminate\Contracts\Bus\Dispatcher $dispatcher)
{
$dispatcher->dispatch(new SomeJob());
}
}

?>
-----
<?php

namespace RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Fixture;

use RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Source\SomeJob;

class SomeClass
{
public function run(\Illuminate\Contracts\Bus\Dispatcher $dispatcher)
{
$dispatcher->dispatchSync(new SomeJob());
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Fixture;

use RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Source\SomeJob;

dispatch(new SomeJob());

$job = new SomeJob();
dispatch($job);

?>
-----
<?php

namespace RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Fixture;

use RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Source\SomeJob;

dispatch_sync(new SomeJob());

$job = new SomeJob();
dispatch_sync($job);

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Fixture;

use RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Source\SomeJob;

(new FooClass())->dispatch(new SomeJob());

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Fixture;

use RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Source\SomeJob;

SomeFacade::dispatch(new SomeJob());

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Fixture;

use RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Source\QueueableJob;

dispatch(new QueueableJob());

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Source;

use Illuminate\Foundation\Bus\Dispatchable;
use stdClass;

class ClassWithDispatchableTrait extends stdClass
{
use Dispatchable;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Source;

use Illuminate\Contracts\Queue\ShouldQueue;

class QueueableJob implements ShouldQueue
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace RectorLaravel\Tests\Rector\FuncCall\DispatchNonShouldQueueToDispatchSyncRector\Source;

class SomeJob
{
}
Loading