2022-12-13
Laravel
Laravel10 DispatchNow削除後に備える
1年前の記事です。
Laravelは古い情報は全く役に立たないので絶対に参考にしないでください。
コメントに新しい情報がないか確認してください。
非推奨になっていたJob::dispatchNow()
やdispatch_now()
がLaravel 10で削除される。
問題ない使い方
TestJob::dispatchNow();
dispatch_now(new TestJob());
Syncに書き換えるだけでいい。Laravel9の内に書き換えておく。
TestJob::dispatchSync();
dispatch_sync(new TestJob());
問題になる使い方
dispatchNow()は同期的に実行したジョブから返り値を取得できる。
$test = TestJob::dispatchNow();
$test = dispatch_now(new TestJob());
Syncでは取得できない。「ジョブの実行に成功したかどうか」の結果が帰ってくる。
$test = TestJob::dispatchSync();
$test = dispatch_sync(new TestJob());
dd($test);
// 0
さらに細かい話で「JobクラスにInteractsWithQueueかQueueableがなければ返り値を取得できる」
こんなJobクラスなら以前のdispatchNow()と同じ使い方はできる。
class DispatchSyncReturnJob
{
use Dispatchable, SerializesModels;
public function handle(): string
{
return 'test';
}
}
テストコードで書けばこう。
public function test_sync()
{
$res = DispatchSyncReturnJob::dispatchSync();
$this->assertSame('test', $res);
$res = DispatchSyncNoReturnJob::dispatchSync();
$this->assertNotSame('test', $res);
$this->assertSame(0, $res);
}
トレイトの有無で変わるので使用時に選べない。
//ここでは同期で返り値を得る。
$test = TestJob::dispatchSync();
//別の場所では非同期で実行。
TestJob::dispatch();
- 同じJobクラスを同期・非同期で使い分けはできない。
- 同期でしか使わないJobなら返り値を得る使い方も一応使い続けられる。
対処方法
「Jobクラスから返り値を得るって使い方を捨てる」
本来のJobはキューに投げて非同期で実行するための機能なので返り値を得る使い方は正しくない。スパッと切り捨て。
代わりの手段は難しく考える必要はなくただのクラスとして作る。
class Test
{
public function __invoke(string $test): string
{
return $test;
}
}
置く場所はapp/Test/Test.php
でもapp/Actions/Test.php
でも好きな場所に置けばいい。
使う時は
use App\Test\Test;
$test = 'hello';
$res = app()->call(Test::class, compact('test'));
dd($res);
// hello
サービスコンテナから実行すればDI含めてJobと同じような動作。
call()での引数の指定は分かりやすくないのでこれでもいい。
$res = app(Test::class)($test);
引数もサービスコンテナからでもいいけどどんどん分かりにくくなる。
$res = app(Test::class)(app(Request::class));
テストではBus::fake()などが使えないので普通にモック。
$this->mock(Test::class, function ($mock) {
$mock->shouldReceive('__invoke')->once()->andReturn('test');
})