エラーが起きた経緯
Laravelで以下のようにユーザ登録をしたときにユーザにメール通知を送るようにしていました。
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
$user->registered($request);
registered関数はNotificationクラスを使って通知を送るものです。
今回、通知を非同期処理にしようと思い、Notificationクラスにimplements ShouldQueue
を追記しました。
すると、ジョブは正常にキューに追加できずに
Serialization of 'Closure' is not allowed
というエラーが発生しました。
エラー文の解読
-
Serializationとは:
シリアライズとは、オブジェクトを文字列やバイナリの形式に変換するプロセスのことを指します。Laravelのキューシステムでは、ジョブをキューに追加する際に、ジョブに関連するデータがシリアライズされ、後でデシリアライズされて処理されるそうです。 -
Closureのシリアライズ:
エラーメッセージは、Closure
をシリアライズすることはできないと指摘しています。
一般的に、クロージャ(無名関数)やリソースへの参照(例えばデータベースの接続やファイルハンドルなど)はシリアライズできず、Request
オブジェクトにはそれらが含まれている可能性があります。
$requestの中身
実際、ddでリクエストの中身を見てみると、Closureが確認できました
解決策: $request->all()
を使用する
冒頭のコードのregistered関数に与える引数を変更しました
$user->registered($request->all());
$request->all()
は、リクエストの入力データを連想配列として取得できます。この連想配列はシリアライズ可能なので、ジョブのクラスに渡して使用することができます。
要するに、ジョブやイベントをキューに追加する際には、シリアライズ可能なデータのみを渡す必要があるみたいです。ここでも、リクエストオブジェクトそのものを渡すのではなく、必要なデータだけを取り出してジョブに渡す必要があります。
補足
メールのフォーマットに渡すデータをオブジェクトではなく連想配列にしたので、その取り出し方の記述も以下のように変えた
//変更前
{{ $user->name }}さん、こんにちは。<br>
//変更後
{{ $user['name'] }}さん、こんにちは。<br>