【図解Laravel】これできっといつでも簡単カスタム【初心者向け実践オブジェクト指向】
大抵のことはフレームワークがいい感じにしてくれます。
でも、デフォルト設定のままではなくちょっとカスタマイズしたい!ということもある。(ほとんどそうだと思う)
というわけで、MVCフレームワーク初心者が認証周りのカスタム実装を通して学んだ、 いつでもどこでも使える「カスタム実装の考え方」 を備忘録としてまとめます。Laravel以外でもきっと同じように考えられると思います。
話すこと
- オブジェクト指向にまつわる概念の実践について
- フレームワーク(Laravel)のコードの話
- フレームワークを使用した実装の考え方
話さないこと
- オブジェクト指向の詳しい話
- Laravel、Breezeの環境構築や各機能の詳しい話
この記事の題材
環境
- Laravel10
- breeze
実装する機能
-
ユーザー登録時のメール認証で送信されるメールのviewを任意のファイルで作成する
Laravel/breezeは基本的な認証機能が実装できるパッケージです。breezeを導入するだけで【ユーザー登録+メール認証、ログイン、パスワードの再設定、ログアウト、退会】がデフォルトで実装されます。
便利なことにUIも生成されます。しかし、UIは特にカスタムしたいところ。この記事では、ユーザー登録時に送信されるメールのUIを変更=独自のviewを使用するというテーマで話していきます。
前提(実装箇所の「オブジェクト」を見る)
クラス、継承、オーバーライドを改めて確認。
まず図解
MVCフレームワーク(Laravel)における「クラスの継承」をまず図解。
オブジェクト指向の「クラス」
オブジェクト指向プログラミングにおいて最も基本となる「クラス」とは、「モノ」のデータや振る舞い(メソッド)などを定義したものです。
では「モノ」とは何でしょう?オブジェクト指向を説明する時に、リアル生活に存在する動物や車などの例え話はとても分かりやすく理解を助けてくれます。そこで理解した上で、いざコードを書こうとすると「モノ」って何のこと?と思いました。
【Userモデル】
class User extends Authenticatable
{
// 中略
}
ここではUser
=ユーザーという「モノ」が定義されています。(モデルを定義する、という言い回しをよく使うため正確に理解できていませんでした)
さらにAuthenticatableというクラスを継承しています。(実際はIlluminate\Foundation\Auth\User as Authenticatable
としてインポートしています。)
継承
「継承」とは、とあるクラスで定義されているものを引き継ぐことです。
上記コードでいうextends Authenticatable
によってAuthenticatable
(Illuminate\Foundation\Auth\User
)で定義されているデータや振る舞い(メソッド)をUserクラスでそのまま使用することができます。
以下のように、継承元のクラス内でさらに様々なオブジェクトが使用されています。このクラスを継承しているUserモデル内で、以下の定義が全て適用されます。
<?php
namespace Illuminate\Foundation\Auth;
use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\MustVerifyEmail;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\Access\Authorizable;
class User extends Model implements
AuthenticatableContract,
AuthorizableContract,
CanResetPasswordContract
{
use Authenticatable, Authorizable, CanResetPassword, MustVerifyEmail;
}
オーバーライド
「オーバーライド」は継承したクラスの振る舞い(メソッド)を継承先の子クラスで再定義=上書きすることです。
上記例で言うとIlluminate\Foundation\Auth\User
を継承するUser
モデル内でIlluminate\Foundation\Auth\User
で定義されたメソッドを上書きすることができます。
下記コードのように、Userモデル内でsendEmailVerificationNotification()
とsendPasswordResetNotification($token)
は継承元Authenticatable
=Illuminate\Foundation\Auth\User
で定義されているメソッドです。
メソッドの内容には触れませんが、継承元の実装をこちらのUserモデルの実装で上書きしています。
class User extends Authenticatable implements CanResetPassword, MustVerifyEmail
{
// 中略
public function sendEmailVerificationNotification()
{
$this->notify(new CustomVerifyEmail());
}
public function sendPasswordResetNotification($token)
{
$this->notify(new CustomResetPassword($token));
}
}
具体例
いい感じにしてくれるフレームワークのデフォルト実装を実際にカスタムしていきます。
(どう考えたか、の備忘録)
やりたいこと
上記の通り。
breezeで簡単に実装された認証機能のうち、送信されるメールのUIを変更します。
中身を見る
まずメール送信を実装するにはデフォルトで実装されているUserモデル内でimplements MustVerifyEmail
を追記。
では、このMustVerifyEmail
の中身に変更を加えるには?ということで継承元を見にいきます。
(Illuminate
ディレクトリ=./vendor/laravel/framework/src/
下)
ここでもMustVerifyEmail
はインポートされているので、さらに見にいく。
このあたりからは情報も揃ってきている+それっぽいメソッド名から調べたりChatGPTに聞いたりしながらですが(ここが一番大変ではある)、どこをいじればいいか探していきます。
toMail()
メソッド内で確認メールの生成が行われているのでここをカスタムします。
最終的に辿り着いたVerifyEmailクラスを継承して、CustomVerifyEmail
クラスを作成。
php artisan make:notification CustomVerifyEmail
でファイルを作成しました。(調査の上で決定)
最終的にはこうなります。
コードはこちら。
<?php
namespace App\Notifications;
use Illuminate\Auth\Notifications\VerifyEmail;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
class CustomVerifyEmail extends VerifyEmail
{
use Queueable;
/**
* Get the mail representation of the notification.
*/
public function toMail($notifiable)
{
$verificationUrl = $this->verificationUrl($notifiable);
if (static::$toMailCallback) {
return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
}
return (new MailMessage)
->subject('メールアドレスのご確認')
->view('emails.verify-email', [
'verify_url' => $verificationUrl,
]);
}
}
そして、これを元にさらにUserモデル内でsendEmailVerificationNotification()
を上書きしていきます。辿ったところを戻っていくイメージ。(ゴールのコードはこちら)
実際、どうしたか
こちらの記事を参考にしました。
あれこれ調べて見つけた上記記事を参考にして実装したところうまくいきました。
そして改めて自分が何をしたのかを振り返ると上記で図解した手順を踏んでいたことが分かったという流れです。
中身を辿っていくことで必要な情報が揃ってくるので、調査も容易になっていくのではないかと思います。
考え方のまとめ
フレームワークがいい感じにしてくれている、の裏側を辿る
辿れば分かる。知らなくてもきっと大丈夫。
集まってきた情報を元に調査
ググる。ChatGPTに聞く。
継承した独自クラスを実装
オブジェクト指向をちゃんと意識する。(私はここが抜けていました)
カスタムしたい部分のみ、継承元のコードを参考に実装
コードを読む。調べる。書く。
おわりに
だいたいこの流れなんだなーと分かったので、応用が効く範囲はそこそこあると思います。
(実際、同じようにしてパスワードリセット用メール送信の実装をカスタムしました。)
私が知らなかったのは、 【vendorディレクトリの存在】 と 【フレームワークの構造+それらがオブジェクト指向で成り立っている】 ということです。
「モデルを定義する」ということをMVCフレームワークでのプログラミングにおいて行いますが、フレームワークが実装しているModelクラスを 継承することでモデル定義したクラスを用いてDB操作ができるとはっきり理解することができました。
今回の実装を経て、今まで単独で学んできたことの点と点がつながったように思います。この考え方だけでなんでもできるというわけではないですが、仕組みを理解・応用することを今後も意識していこうと思います。
Discussion