Laravel 8 + Livewire でメールフォームを作るチュートリアル
Laravel 8 と Livewireを使って、メールフォームを作る機会がありましたので、その作成手順をシェアします。
フォームはシンプルな、入力、確認、完了の3画面の一般的なお問い合わせメールフォームです。
完成したソースコード
テンプレートリポジトリとしてgithubにおきました。
https://github.com/hdmt/livewire-contact-template
開発環境
Laravel Sailを使ったMac+Docker環境を用意します。構築手順は以下の記事のとおりです。
上記で作ったLaravelに Livewire
をインストールします。
プロジェクトディレクトリ直下で次のコマンドを実行します。
./vendor/bin/sail composer require livewire/livewire
以上で開発の準備が整いました。
Livewireコンポーネント作成
お問い合わせフォームの入力、確認、完了の3画面にあたるLivewireコンポーネントを作成します。
// 入力画面
./vendor/bin/sail php artisan make:livewire Input
// 確認画面
./vendor/bin/sail php artisan make:livewire Confirm
// 完了画面
./vendor/bin/sail php artisan make:livewire Complete
上のコマンドにより、livewireのクラスとbladeファイルのひな形が生成されます。
ルーティングの設定
次に、お問い合わせフォームの入力、確認、完了の3画面について、ルーティングを設定します。
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Livewire\Input;
use App\Http\Livewire\Confirm;
use App\Http\Livewire\Complete;
Route::get('/', Input::class)->name('home'); //入力画面
Route::get('/confirm', Confirm::class)->name('confirm'); //確認画面
Route::get('/complete', Complete::class)->name('complete'); //完了画面
入力画面のコンポーネント実装
まず、入力画面を制御する、Inputコンポーネントを実装します。
ビューで扱う3つの変数 $posts
、$requestList
、$prefectures
をプロパティとして定義します。
Livewireに定められた特別のメソッド(ライフサイクルフック)の一つ、mount
メソッドでこれらの変数に値を設定することで、ビューに値を渡せるようになります。
class Input extends Component
{
public $posts; // ユーザが入力する値
public $requestList; // チェックボックスで表示するリスト
public $prefectures; // selectで表示する都道府県のリスト
public function mount()
{
// チェックボックスで表示すデータをconfigファイルから取得する
$this->requestList = config('contact.requests');
// チェックボックスで表示すデータをconfigファイルから取得する
$this->prefectures = config('contact.prefectures');
// 確認画面から入力に戻ったときのため、sessionに保存した入力値を取得
$this->posts = session()->get('posts');
}
ビューを表示するrender()
メソッドは、make:livewire
コマンドで生成されたときのデフォルトから変更せず、そのまま使用します。
public function render()
{
return view('livewire.input');
}
チェックボックス、都道府県のselectタグに表示する情報は、configファイルにそれぞれ定義して、config
ヘルパで取得します。
return [
'資料・サンプルが欲しい',
'価格が知りたい',
'その他'
];
return [
'1' => '北海道',
'2' => '青森県',
(略)
'47' => '沖縄県',
];
ビュー作成
まずlayoutのbladeを作り、$slot
でLivewireのコンポーネントがレンダーされます。
<!DOCTYPE html>
<html lang="ja">
<head>
@livewireStyles
</head>
<body class="antialiased overflow-x-hidden">
{{ $slot }}
@livewireScripts
</body>
次に入力画面のformのbladeを作成します。
formタグには、livewireのディレクティブでイベントとアクションをwire:submit.prevent="confirm"
のように指定しています。
ディレクティブの形式は、wire:[ディスパッチされたブラウザイベント]="[アクション]"
です。
これでsubmitされたときに、あとで Livewire/Input.php に実装するconfirm
メソッドが実行れます。
inputタグには、wire:model="posts.name"
を指定します。
<form wire:submit.prevent="confirm">
@csrf
<div>
<div>
<span >お名前(必須)</span>
<input
wire:model="posts.name"
type="text" placeholder="鈴木一郎">
@error('posts.name') <span>{{ $message }}</span> @enderror
</div>
(略)
<button>内容確認</button>
</div>
</form>
ここまでで、次ような入力画面が http://localhost/
で表示できるようになりました。
内容確認ボタン押下時の処理
つづいて、入力内容の確認ボタンを押下した時の処理を実装します。
入力値のバリデーションのため、Inputクラスにバリデーションルールとエラーメッセージを追加します。
class Input extends Component
{
(略)
protected $rules = [
// name を必須
'posts.name' => 'required',
// email を必須 かつ メールアドレス形式
'posts.mail' => 'required|email',
// request(チェックボックスの選択)を必須 かつ 配列形式
'posts.request' => 'required|array',
];
// エラーメッセージの設定
protected $messages = [
'posts.*.required' => '必須項目です',
'posts.mail.email' => '正しいメールアドレスを入力ください',
];
確認ボタンが押されたときに、実行するconfirm()
メソッドを次のように記述します。
public function confirm()
{
// バリデーションの実行
$this->validate();
// 入力されたpostプロパティを、セッション名'posts'で
// セッションに保存
session()->put('posts', $this->posts);
// 確認画面へリダイレクト
return redirect()->route('confirm');
}
Inputクラスの完成版コード
ここまでで、入力画面が完成です。
確認画面のコンポーネント
確認画面のLivewireコンポーネントは、mount()
で次のように実装します。
セッションに保持した入力情報を、session()->get('posts')
で取得し、確認画面のビューに渡すようにします。
・・・
class Confirm extends Component
{
public $posts;
public $requestList;
public $prefectures;
public function mount()
{
$this->requestList = config('contact.requests');
$this->prefectures = config('contact.prefectures');
// sessionに保存した入力値を取得
$this->posts = session()->get('posts');
// 入力なしで確認画面に直接アクセスがあったらhomeへリダイレクト
if(empty($this->posts)){
return redirect()->route('home');
}
}
・・・
メール送信処理
メール送信ボタン押下時に実行する submit()
メソッドを実装します。
$recipients
にユーザが入力したメールアドレスと、configファイルに設定した管理者アドレスを格納し、Mailableクラスを使って、それぞれに送信を実行します。
・・・
use Illuminate\Support\Facades\Mail;
use App\Mail\Contact;
・・・
public function submit()
{
// メール送信
$recipients = [
Arr::get($this->posts, 'mail'),
config('app.admin_address')
];
foreach ($recipients as $recipient) {
Mail::to($recipient)->send(new Contact($this->posts));
}
// 完了画面へ
return redirect()->route('complete');
}
・・・
Mailableクラス
Mailableクラスをmakeコマンドで生成します。
sail php artisan make:mail Contact
コンストラクタで入力内容など、メール本文に渡したいプロパティを定義し、build()
メソッドでメール本文のビューを指定します。
class Contact extends Mailable
{
use Queueable, SerializesModels;
public $posts;
public $requestList;
public $prefectures;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct($posts)
{
$this->requestList = config('contact.requests');
$this->prefectures = config('contact.prefectures');
$this->posts = $posts;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->text('email.contact');
}
}
メール本文は、次のようにビューを用意します。
それぞれ取得したプロパティを表示させるようにします。
■お名前
{{ Arr::get($posts, 'name') }}
■メールアドレス
{{ Arr::get($posts, 'mail') }}
■ご要望
@foreach ($posts['request'] as $request)
{{$requestList[$request]}}
@endforeach
■郵便番号
{{ Arr::get($posts, 'zip', '-') }}
■都道府県
{{ @$prefectures[ $posts['prefecture'] ] }}
■ご希望・ご質問
{{ Arr::get($posts, 'comment', '-') }}
.envの設定
メールの送信元や、管理用アドレスの設定を、.envに以下のとおり記載します。
・・・
MAIL_FROM_ADDRESS=from@example.com
MAIL_FROM_NAME="${APP_NAME}"
MAIL_TO_ADDRESS=to@example.com
・・・
メール送信結果
Laravel Sailで構築した環境にデフォルトで付属するメール送信ツール・MailHogで、メールの送信結果を確認します。
MailHogはhttp://localhost:8025/
でアクセスできます。
確認画面のblade
確認画面では、セッションに保存したposts
プロパティのデータを表示します。
// nameの表示
<dd>{{ @$posts['name'] }}</dd>
// チェックボックス選択したrequestの表示
@foreach ($posts['request'] as $request)
{{$requestList[$request]}}<br>
@endforeach
// selectボックス選択した都道府県の表示
{{ @$prefectures[ $posts['prefecture'] ] }}
確認画面の表示イメージ
完了画面のコンポーネント
完了画面のコンポーネントでやることはシンプルです。
次のとおり、mount
でセッションのチェックと削除、ビューの表示のみを行っています。
(略)
class Complete extends Component
{
public function mount()
{
// 完了画面に直接アクセスされたときの対策
// sessionにデータがなければ、homeへ戻す
if(empty(session()->get('posts'))){
return redirect()->route('home');
}
// セッションクリア
session()->flush();
}
public function render()
{
return view('livewire.complete');
}
}
完了画面のblade
ビューは、送信完了のメッセージを表示します。
<div>送信が完了しました。<br>お問い合わせいただき、ありがとうございました。</div>
完了画面の表示イメージ
おわりに
以上、Laravel と Livewire でメールフォームを作るチュートリアルをご紹介しました。
内容に誤りや不足があれば、コメントでご指摘いただけるとうれしいです。
参考
Discussion