PHP
laravel
laravel5.5

LaravelでMailableなオブジェクトをqueueで送信したら"Serialization of 'Closure' is not allowed"というエラーになった件の解決方法

Laravelでメールを送信する処理を実装することになったのでMailableクラスを利用することにしました。
しかしMail::queueメソッドで送信しようとしたときにエラーになってハマったのでメモ。

エラーについて

Mailableを継承したクラスは以下のように定義しました。

App\Mail\UserRegistered.php
<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Http\Request;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\Models\Eloquent\User;

class UserRegistered extends Mailable
{
    use Queueable, SerializesModels;

    public $request;
    public $user;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct(Request $request, User $user)
    {
        $this->request = $request;
        $this->user = $user;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this->view('emails.user_registered')
            ->to($this->request->input('email'), __('common.address_name', ['NAME' => $this->request->input('name')]))
            ->subject(\Config::get('mail.user_registered.subject_prefix').__('mail.mailsubject.user_registered'));
    }
}

そして呼び元からはMail::queueで送信。

\Mail::queue(new UserRegistered($request, $user));

送信できたかと思ったら以下のエラーになりました。

Serialization of 'Closure' is not allowed
/var/www/application/vendor/laravel/framework/src/Illuminate/Queue/Queue.php#128

しかし\Mail::queueでは送信できませんでしたが、\Mail::sendだと送信することができました。
なぜだろう?

環境

名前 バージョン
PHP 7.1.8
Laravel 5.5.5

解決策

結論からいうと、
Serialization of 'Closure' is not allowed in Laravel 5.3 Email Queue
のリンクにあるとおり

You cannot serialize request. Only eloquent model can be serialized and unserialzed. See here: https://laravel.com/docs/5.2/queues#writing-job-classes
You should use $request->all() instead of $request. Since Request is treated as closure.

MailableオブジェクトにIlluminate\Http\Requestを渡していたからNGとのこと。
$request->all()して配列を渡すように変更したところ\Mail::queueでも送信することができるようになりました。

NG.php
\Mail::queue(new UserRegistered($request, $user));
OK.php
\Mail::queue(new UserRegistered($request->all(), $user));

当然Mailableオブジェクトの中身の処理も配列で渡ってくることを前提とした処理に変更しました。

App\Mail\UserRegistered.php
<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\Models\Eloquent\User;

class UserRegistered extends Mailable
{
    use Queueable, SerializesModels;

    public $inputs;  // ★$request -> $inputsに変更しました
    public $user;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct(array $inputs, User $user)
    {
        $this->inputs = $inputs;  // ★$request -> $inputsに変更しました
        $this->user = $user;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        // ★$request -> $inputsに変更し配列から取得するようにしました
        return $this->view('emails.user_registered')
            ->to($this->inputs['email'], __('common.address_name', ['NAME' => $this->inputs['name']]))
            ->subject(\Config::get('mail.user_registered.subject_prefix').__('mail.mailsubject.user_registered'));
    }
}

これで無事queueでメールが送信されるようになりました!