Laravel 新 Mailable を試してみる
前書き
Laravel 9.35 から、新 Mailable が使えるようになりましたので、それを試してみました。
気が早い事に、コマンド使って Mailable 作成すると、新 Mailable の雛形で出来上がりますので、早めに慣れておくと良さそうです。
日本語ドキュメントも既に新 Mailable に説明が変わっています。
本題
という事で、コマンドで新 Mailable を作ります。(以降、.env でメールの設定が適切に行われ、users テーブルには、データが入っている想定で行きます)
以下のコマンドを叩きます。
php artisan make:mail ContactMail
でも今回は、裏技で
php artisan make:mail ContactMail -m emails.contact
今回は裏技を使って作成していきます。-m は、markdown の略で、-m テンプレ名とすると、そのテンプレを作ってくれます。(中身は、マークダウンのサンプルが書かれている)
また、出来上がる Mailable ファイルにも「markdown: 'emails.contact',」と埋まっています↓
以下、上記コマンドで作成された ContactMail.php です。(紙面の都合上、DocBlock 略)
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class ContactMail extends Mailable
{
use Queueable, SerializesModels;
public function __construct()
{
//
}
public function envelope()
{
return new Envelope(
subject: 'Contact Mail',
);
}
public function content()
{
return new Content(
markdown: 'emails.contact', // ← ここ!
);
}
public function attachments()
{
return [];
}
}
さて、上記で必要な箇所を編集して行きます。
/**
* Get the message envelope.
*
* @return \Illuminate\Mail\Mailables\Envelope
*/
public function envelope()
{
return new Envelope(
subject: 'Contact Mail',
+ from: 'foo@example.net',
+ to: 'foo@example.net',
);
}
/**
* Get the message content definition.
*
* @return \Illuminate\Mail\Mailables\Content
*/
public function content()
{
return new Content(
- markdown: 'emails.contact',
+ text: 'emails.contact',
);
}
Envelope の所に、差出人などを適宜設定します。ここは、PHP8 からの新機能の名前付き引数(Named Arguments)の書き方になっていますね。
上記の書き方とは別に、インスタンス化した Envelope に ->from() などのメソッドを呼び出す事もできます↓
public function envelope()
{
$envelope = new Envelope();
return $envelope->subject('Contact Mail')
->from('foo@example.net')
->to('foo@example.net');
}
また、メールは、実際はマークダウンではなく単なるテキストで送るため、text: と変更しています。(この作業を忘れないように。最初から --text というコマンドオプションがあったら良いのですが、残念ながらありません。)
せっかくですので、メール本文にユーザー名が記載されるようにします。
コンストラクタを以下のように変更します。
use App\Models\User;
public function __construct(public User $user)
{
//
}
コンストラクタで、user
プロパティを初期化しています。
PHP8 からの Constructor property promotion を使うと上記で済むので楽ですね。
旧式の Mailable でもそうですが、public なプロパティは、テンプレート(ビュー)側に自動で渡るので、明示して渡す必要はありません。
テンプレートは、取りあえず以下で。
{!! $user->name !!} です。
web.php は、以下の感じ。
Route::get('/', function () {
$user = User::first();
Mail::send(new ContactMail($user));
return view('welcome');
});
これで、トップページにアクセスすると、「Walter Bernhard です。」などと名前が書かれたメールが届きます。簡単ですね。
で、何が良くなったのか。
その辺は人それぞれかも知れませんが、私が感じたのは、旧式 Mailable の build() メソッド内で from とか to とか設定していると、下記のようなテストは通りませんでしたが、新 Mailable では通るので、そこは少し嬉しいですね。
public function test_example()
{
\Mail::fake();
$response = $this->get('/');
Mail::assertSent(ContactMail::class, function ($mail) {
return $mail->hasTo('foo@example.net') &&
$mail->hasFrom('foo@example.net');
});
}
ところで、名前付き引数(Named Arguments)って…。
話は少し逸れますが、上記でも見たように、新 Mailable では、名前付き引数(Named Arguments)機能が利用されたりします。(ドキュメントもそうなっている)
本来、Laravelでは、名前付き引数を使うのは、「サポートしませんよ。自己責任でよろしく。」的な感じになっていますが、この新 Mailable では、それがある意味サポートされている感じになっています。実際、ソースコード上にも、「@named-arguments-supported」とアノテーションが書かれていたり。
まぁ、「新 Mailable は、ちょっと例外なのね」、と理解していましたが、最近微妙にそうでない所でも、ドキュメント上で名前付き引数が書かれ始めているんですね…。
data_set($data, 'products.desk.price', 200, overwrite: false);
Benchmark::dd(fn () => User::count(), iterations: 10); // 0.5 ms
「おいおい、自己責任と言いつつ、ドキュメントにサラッと書くのか…💦」的な。(笑
実際、引数(パラメータ)の名前は「綴りミス」などによりサクッと変更されたりもしますので、その辺お気を付けて。
雑感
という事で、新 Mailable を軽く試してみました。
新機能や新しい書き方の情報を追うのも大変ですが、頑張って行きましょう。
ミスや間違い等ありましたら、コメント下さい🙇♂️
Discussion