LoginSignup
13
9

More than 5 years have passed since last update.

Laravel5.5 dispatch_now()一つで非常に分かりやすくなった

Posted at

Laravel に限らず Web アプリケーションフレームワークは基本的に
ルーティング→コントローラー→(なにか処理)→ビューという流れ。
この(なにか処理)をどこに書くかというのが問題になる。

  • コントローラーに書くのはファットコントローラーになるからやめろと言われる。
  • MVCの時代にはモデルに書くとされてたけどほぼモデル=DBなWebMVCではなんとなく違う。Eloquent にメソッド増やしたくない。
  • 少し前はサービスクラスを作れと言われてたけどサービスクラスって何?な曖昧な状態では上手く作れない。コントローラーに書いてたことを分離しただけみたいなことは自分もまだやってしまう。

俺が悪かった。素直に間違いを認めるから、もうサービスクラスとか作るのは止めてくれ

Laravel 5.5 では

キューで使うJobクラスをサービスクラスの代わりにするといいと気付いた。かなり前に気付いてたけどやりたいことはできないと思ってた。
https://readouble.com/laravel/5.5/ja/queues.html

「サービス」よりは「ジョブ」のほうが一つの処理の塊としては理解しやすい。
なんならジョブクラスから更にサービスクラスを呼んでもいい。
ジョブならキューで非同期な実行と dispatch_now() で即実行を使い分けられる。

実は5.4でも

syncドライバーなら返り値を得られたらしい。もしくはimplements ShouldQueueを削除するか。

$bar = dispatch(new FooJob());

$job = (new FooJob())->onConnection('sync');
$bar = dispatch($job);

前に試した時はジョブ内でreturn response()とかやろうとしてたから間違ってた。
5.4以前のことはもう考慮しないので忘れる。

実際に作ってみる

Job

php artisan make:job FooJob

サンプルだとこういう↑シンプルな例が多いけど My/FooJob などでディレクトリを分けられるから規模が大きくなったら分ける。コントローラーやコマンドでも同じ。

php artisan make:job My/FooJob

handle()内になにかの処理を書く。


    /**
     * @var string
     */
    protected $foo;

    /**
     * Create a new job instance.
     *
     * @param string|null $foo
     */
    public function __construct(string $foo = null)
    {
        $this->foo = $foo;
    }

    /**
     * Execute the job.
     *
     * @return string
     */
    public function handle(): string
    {
        return 'Bar';
    }

Controller

php artisan make:controller FooController

数行だけの小さいコントローラーにできる。

use App\Jobs\FooJob;

class FooController extends Controller
{
    public function __invoke(Request $request)
    {
        $foo = $request->input('foo');

        $bar = dispatch_now(new FooJob($foo));

        return view('foo')->with(compact('bar'));
    }
}

これはコントローラーの仕事を完璧に遂行してる…。

artisanコマンド

php artisan make:command FooCommand

同じジョブをartisanコマンドからも使う。キューで実行。

    public function handle()
    {
        FooJob::dispatch('foo');
    }

こっちも dispatch_now() で使ってもいい。

一番使いそうなコントローラーとartisanコマンドを例にしてるけどアプリ内ならどこからでも使える。

テスト

コントローラーのテストは Bus::fake() でモックできるのでジョブクラスは無視できる。なるべく new は使いたくないけどジョブクラスは使っても大丈夫そう。
https://readouble.com/laravel/5.5/ja/mocking.html

ジョブのテストは handle() を実行すればいいだけなので単体で可能。

$job = new FooJob($foo);
$bar = $job->handle();

おわり

キューを前提にしてるけどそもそもキューはどのくらい使われてるんだろう…。dispatch_now() だけ使うならキューなしというか sync ドライバーでも大丈夫なはず。

13
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
9