🛫

LaravelのQueueとJobを利用してメール送信をする

2021/06/17に公開

はじめに

今回、実務で初めてLaravelのJobとQueueでメールの送信機能を実装し、その結果をAjaxで受け取るという実装をしました。
初めて知ることも多く、勉強になったのでまとめていきたいと思います。

バージョン
Laravel 7.30.4

JobとQueueとは

まず、Larevelの公式ドキュメントをチェック
Laravel 7.x キュー

「キュー」とはキュー済みのジョブのスタック、もしくは積み重ねのことです。
queue接続ファイルのqueue属性を含んでいる、各接続設定例に注目してください。ジョブがディスパッチされ、指定された接続へ送られた時にのデフォルトキューです。言い換えれば、どのキューへディスパッチするのか明確に定義していないジョブをディスパッチすると、そのジョブは接続設定のqueue属性で定義したキューへ送られます。

…よくわかりません。

そこでもう少し調べてみると、わかりやすい記事を発見!
LaravelでQueueとJobを使ってみる基礎基礎メモ

簡単に説明すると、jobとQueueは処理を非同期で行うことができる機能です。
では、非同期で処理を行うことができると、どういったメリットが考えられるのでしょうか。

わかりやすい例だと、会員登録を行った際に、よくメールが送られてくる機能があると思います。
この時に、非同期で行っていない場合だと、ユーザーはメールの送信処理が完了するまで画面を動かすことができません。
一方で、非同期で処理を行なった場合は、メール送信をサーバー側で行なっている間に、フロント側では「登録完了」ページへ推移することができるので、ユーザーにとってメリットが大きいと言えます。

フロント画面の実装

今回はすでにLaravelのプロジェクトは用意されているものとします。
機能としては、IDとPWを登録し、そのデータがメールで送られてくる処理を書いていきたいと思います。

まずは、IDとPWを登録する画面を作っていきます。

register.blade.php
<h1>会員情報</h1>
<form action="">
    <p>IDを入力</p>
    <input type="text" name="member_id">
    <p>PWを入力</p>
    <input type="text" name="password">
    <p>メールアドレスを入力<p>
    <input type="text" name="email">
    <br><br>
    <button>登録</button>
</form>
web.php
Route::get('/', function () {
    return view('register');
});

とてもシンプルな画面ができました。

また、送信後に推移する画面も作成しておきます。

finish.blade.php
<!doctype html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Fin</title>
</head>
<body>
<h1>登録が完了しました!</h1>
</body>
</html>

サーバー側の実装

まず、membersテーブルを用意します。

members_table.php
class CreateMembersTable extends Migration
{
    public function up()
    {
        Schema::create('members', function (Blueprint $table) {
            $table->id();
            $table->string("member_id");
            $table->string("password");
	    $table->string("email");
            $table->timestamps();
        });
    }

続いて、Controllerを作成していきます。

MemberController
function index() {
        return view('register');
    }

    function store(Request $request) {
        $data = $request->all();
    }

先ほどはweb.phpにてregister.balde.phpの画面を返すようにしましたが、Controllerに書き換えています。

web.php
Route::get('/', 'App\Http\Controllers\MemberController@index');
Route::post('register', 'App\Http\Controllers\MemberController@store')->name('register');

そして、register.blade.phpのformタグを書き換えます。

register.blade.php
<form method="POST" action="{{ route('register') }}">
省略
</form>

これで、簡単な会員登録フォームは完成です。

メール送信処理をかく

続いて、メールを送信するための処理を書いていきます。
ローカルでは実際にメールを送ることができないため、今回はMailTrapを利用します。
MailTrapの利用方法は以前記事に書いたので、こちらをご参照ください。
LaravelでMailTrapを利用し、ローカル環境でもメールのテスト送信をする方法

RegistrationMail.php
 protected $data;

    public function __construct($data)
    {
        $this->data = $data;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this
            ->from('test@test.com')
            ->subject('会員登録完了')
            ->view('mail')
            ->with(['data' => $this->data]);
    }
mail.blade.php
会員登録が完了しました。
ID: {{ $data->member_id }}
PW: {{ $data->password }}

メールの送信処理に関しては詳しい説明は割愛します。
RegistrationMail.phpではIDとPWが入った$dataをメール本文で利用できるようにwithで渡し、メール本文はmail.blade.phpに書いているので、viewの欄はmailと指定しています。

Jobに処理を書いていく

やっと今回の本題であるJobの出番です。

まず、.envのQUEUE_CONNECTIONを以下のように変更します。

QUEUE_CONNECTION=database

続いて、ジョブを保存するためのjobsテーブルを作成し

php artisan queue:table

マイグレーションを実行

php artisan migrate

これで、jobsテーブルが作成されました。

続いて、ジョブクラスを作成します。

php artisan make:job SendMail

そして、新しく生成されたジョブを以下のように編集します。

SendMail.php
 public function handle()
    {
        Mail::to($this->data['email'])->send(new RegistrationMail($data));
    }

あとはコントローラーのstoreメソッドにJobを使用する記述を追加します。

MemberController
function store(Request $request) {
        $data = $request->all();
        SendMail::dispatch($data);

        return view('finish');
    }

これで、フォームから入力した値を、Jobを通してメールで送ることができました!

さいごに

今回、初めてJobとQueueを利用してみましたが、思ったよりも簡単に実装を行うことができました。
これからも用途に合わせて利用していきたいと思います!

最後まで読んでいただきありがとうございました!

Discussion