6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Laravel6 / MailHog】ユーザー招待機能の詳細設計と実装(3)招待メール送信処理

Last updated at Posted at 2022-12-20

はじめに

ユーザー招待機能の詳細設計と実装(3) 招待メール送信処理 について投稿します。

Web業界実務未経験での転職活動用にポートフォリオとしてはじめて作成したWebアプリ開発のオリジナルの機能として 家族ユーザー招待機能 を実装したときのものです。

※ 作成したポートフォリオは、絵本を読み聞かせしたことの記録・管理を、家族と共有できるWebアプリケーションです(作成期間は、2021年2月末〜7月)

投稿内容(全5回)

本連載は以下の順番で投稿します。

今回は、ユーザー招待機能の詳細設計と実装(3) 招待メール送信処理 についてです。

目次

以下、本記事の目次です。

  1. Mailable クラスを継承したクラスの作成
  2. 通知クラスの作成
  3. Invite モデルへのメソッドの追加

使用技術、サービスなど

  • PHP 7.4.13
  • Laravel 6.20.20
  • MySQL 8.0.23
  • MailHog(開発者向けのメールテストツール、開発環境)

1. Mailable クラスを継承したクラスの作成

Mailable クラスを継承した BareMail クラスを作成します。

Laravel では、メールを取り扱うクラスが複数ありますが、Mailable クラスを利用します。Mailable クラスを選択する理由は、 HTML メールではなくテキストメールを送るにはMailableクラスを使う必要があるためです。

(このアプリの作成の際は「メールを利用したパスワード再設定」機能追加時に作成したファイルを、家族招待通知でも再利用しました。)

1-1. BareMail.php の作成

以下コマンドを実行して、 backend/app/Mail/ ディレクトリ以下に、 BareMail.php を作成します。

docker-compose exec app php artisan make:mail BareMail

1-2. BareMail.php の編集

作成されたファイルを編集します。

編集:backend/app/Mail/BareMail.php
<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class BareMail extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this;
    }
}

メールの種類ごとの細かい設定は持たせず、空の設定のメールとして使用していくため、 build メソッドでは何も設定せず、そのまま自分自身を返します。

宛先や件名、使用するテンプレートなどは、次に作成する通知クラスで設定します。

2. 通知クラスの作成

通知クラス(InvitationFamilyNotification クラス)を作成し、 BareMail クラスを用いたメール送信メソッドを追加します。

2-1. InvitationFamilyNotification.php の作成

以下コマンドを実行して、 backend/app/Notifications/ ディレクトリ以下に、 InvitationFamilyNotification.php を作成します。

docker-compose exec app php artisan make:notification InvitationFamilyNotification

2-2. InvitationFamilyNotification.php の編集

作成されたファイルを編集します。

編集:backend/app/Notifications/InvitationFamilyNotification.php
<?php

namespace App\Notifications;

use App\Mail\BareMail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;

class InvitationFamilyNotification extends Notification
{
    use Queueable;

    public $token;
    public $mail;

    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct(string $token, BareMail $mail)
    {
        $this->token = $token;
        $this->mail = $mail;
    }

    /**
     * Get the notification's delivery channels.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function via($notifiable)
    {
        return ['mail'];
    }

    /**
     * Get the mail representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return \\Illuminate\\Notifications\\Messages\\MailMessage
     */
    public function toMail($notifiable)
    {
        return $this->mail
            ->from(config('mail.from.address'), config('mail.from.name'))
            ->to($notifiable->email)
            ->subject('[よんで] 家族招待')
            ->text('emails.invite')
            ->with([
                'url' => route('register.invited.{token}', [
                    'token' => $notifiable->token,
                ]),
            ]);
    }

    /**
     * Get the array representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function toArray($notifiable)
    {
        return [
            //
        ];
    }
}

2-3. 参考

コンストラクタインジェクション

クラスのインスタンスをコンストラクタで注入(DI)することを、コンストラクタインジェクションと言う。

public $token;
public $mail;

InvitationFamilyNotification クラスに $token プロパティと $mail プロパティを定義している。

public function __construct(string $token, BareMail $mail)
{
    $this->token = $token;
    $this->mail = $mail;
}

__construct メソッドで、引数として、文字列の $tokenと、BaraMail クラスのインスタンスの $mail を、それぞれプロパティに代入している。

toMail メソッド

toMail メソッド内で、メールの具体的な設定を行なっている。

public function toMail($notifiable)
{
    return $this->mail
        ->from(config('mail.from.address'), config('mail.from.name'))
        ->to($notifiable->email)
        ->subject('[よんで] 家族招待')
        ->text('emails.invite')
        ->with([
            'url' => route('register.invited.{token}', [
                'token' => $notifiable->token,
            ]),
        ]);
}

from メソッド

Mailable クラスの from メソッドに以下の引数を渡す。

  • 第一引数には、送信元メールアドレス
  • 第二引数には、メールの送信者名(省略可)

参考:from メソッドの使用 - Laravel公式

引数については、config 関数を使って、 backend/config/mail.php の以下の値を取得している。

確認:backend/config/mail.php
<?php

return [
// 略
    'from' => [
        'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
        'name' => env('MAIL_FROM_NAME', 'Example'),
    ],
// 略
];

addressnameそれぞれについて、 env 関数を使って取得した環境変数の値になっている。( env 関数の第二引数は、第一引数の環境変数が存在しない場合のデフォルト値)

  • 確認:backend/.env
APP_NAME=Yonde

# 省略

MAIL_FROM_NAME="${APP_NAME}"
MAIL_FROM_ADDRESS=no-reply@example.com

to メソッド

->to($notifiable->email)

toメソッドには、送信先メールアドレスを渡す。

$notifiable には、メール送信先となる User モデルが代入されているので、 $notifiable->email で、メール送信先ユーザーのメールアドレスを取得している。

subject メソッド

->subject('[よんで] 家族招待')

subjectメソッドには、メールの件名を渡す。

text メソッド

->text('emails.invite')

textメソッドは、テキスト形式のメールを送る場合に使うメソッド。

引数で、メールのテンプレートを指定する。 'emails.invite' とすることで、backend/resources/views/emails/ ディレクトリの invite.blade.php がテンプレートとして使用される。

with メソッド

->with([
    'url' => route('register.invited.{token}', [
        'token' => $notifiable->token,
    ]),

テンプレートとなる Blade に渡す変数を、 with メソッドに連想配列形式で渡す。

キー url の値には、 route 関数を使って register.invited.{token} のルーティングをセットしている。

  • register.invited.{token} のルーティングは、以下のとおり。
+--------+-----------+-----------------------------------+--------------------------------+-------------------------------------------------------------------------------+------------------------------------------------------+
| Domain | Method    | URI                               | Name                           | Action                                                                        | Middleware                                           |
+--------+-----------+-----------------------------------+--------------------------------+-------------------------------------------------------------------------------+------------------------------------------------------+
// 略
|        | GET|HEAD  | register/invited/{token}          | register.invited.{token}       | App\\Http\\Controllers\\Auth\\RegisterController@showInvitedUserRegistrationForm  | web,guest                                            |
// 略

3. Invite モデルへのメソッドの追加

Invite モデルを作成して、メソッドを追加します。

3-1. Invite モデルの作成

下記コマンドを実行して、Invite モデルを作成します。

以下コマンドを実行して、 backend/app/ ディレクトリ以下に、 Invite.php を作成します。

docker-compose exec app php artisan make:model Invite

3-2. Invite モデルへのメソッドの追加

Invite モデルに sendInvitationFamilyNotification メソッドを定義します。

編集:backend/app/Invite.php
<?php

namespace App;

use App\Mail\BareMail;
use Illuminate\Database\Eloquent\Model;
use App\Notifications\InvitationFamilyNotification;
use Illuminate\Notifications\Notifiable;

class Invite extends Model
{
    use Notifiable;

    protected $fillable = [
        'family_id',
        'email',
        'token',
    ];

    // 家族招待通知送信
    public function sendInvitationFamilyNotification($token)
    {
        $this->notify(new InvitationFamilyNotification($token, new BareMail()));
    }
}

先ほど作成した通知クラスである InvitationFamilyNotification クラスのインスタンスを生成して、 notify メソッドに渡すことにより、次で作成するテキストメールが家族ユーザー招待メールとして送信されるようになります。

おわりに

今回は、招待ユーザー機能の詳細設計と実装(3) 招待メール送信処理 についてでした。
次回は、 (4) 招待メールのテンプレート についてです。

ありがとうございました。

6
0
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
6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?