転職したらスマレジだった件

スマレジのエンジニアやまてのテックブログです。マジレス大歓迎です。

家族ユーザー招待機能 の詳細設計と実装(3) - はじめてのWebアプリ開発を振り返る Part7

こんにちは!

スマレジ・テックファームのWebエンジニアやまてと申します。

はじめに

今回は、Web業界実務未経験での転職活動用にポートフォリオとして作成した『はじめてのWebアプリ開発を振り返る』記事です。


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

qiita.com


実装したオリジナルの機能の一つである「家族ユーザー招待」機能について、記事にします。

概要と基本設計

ryamate.hatenablog.com

詳細設計と実装

(1) 家族招待メール送信フォームの作成

(2) マイグレーションファイルからのテーブル作成

(3) 家族招待メール(テキスト版)の送信処理の作成【今回】

(4) 家族招待メール(テキスト版)のテンプレートの作成

(5) ユーザー登録フォームと登録処理の作成

今回は、家族招待メール(テキスト版)を送信可能にするまでの作成手順です。

以下手順を行います。

  1. Mailable クラスを継承した BareMail クラスを作成します。
  2. 通知クラス(InvitationFamilyNotification クラス)を作成し、 BareMail クラスを用いたメール送信メソッドを追加します。
  3. Inviteモデルに、上記の通知クラスによる通知を行う sendPasswordResetNotification メソッドを追加します。


目次

使用技術、サービスなど

  • フロントエンド
  • バックエンド
    • PHP 7.4.13
    • Laravel 6.20.20
    • MySQL 8.0.23
  • メール関連
    • MailHog(開発者向けのメールテストツール、開発環境)

      github.com

    • SendGrid(メール配信サービス、本番環境)

      sendgrid.kke.co.jp


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

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

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

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

1-1. BareMail.php の作成

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

$ php artisan make:mail BareMail

※ docker-compose コマンドで実行する場合(app コンテナ内)

$ 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 を作成します。

$ php artisan make:notification InvitationFamilyNotification

※ docker-compose コマンドで実行する場合(app コンテナ内)

$ 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 モデルへのメソッドの追加

3-1. Invite モデルの作成

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

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

$ php artisan make:model Invite

※ docker-compose コマンドで実行する場合(app コンテナ内)

$ 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 メソッドに渡すことにより、次で作成するテキストメールが家族ユーザー招待メールとして送信されるようになります。

おわりに

今回の記事は以上です!

次回も、詳細設計と実装の続きについて書きます。

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



これまでの関連記事

これまでの関連記事です。

ryamate.hatenablog.com

ryamate.hatenablog.com

ryamate.hatenablog.com



これからも毎日継続して、どこまでいけるか楽しみです。