この記事は、PHPのフレームワーク「Laravel」でお問い合わせフォームを作成するための解説記事です。
私(わや@wayasblog)自身、Laravelを最近勉強し始めたので、かなり丁寧に解説した初心者向けの記事となっています。
コードだけ見たい!という方は、こちら(GitHub)からどうぞ。
» Laravelで作成したアプリやアウトプットの一覧はこちら
スポンサーリンク
Laravelで作るお問い合わせフォームのイメージ
スクリーンショットで紹介していきます。
今回は、Bootstrapで簡単にスタイルを作成しました。
お問い合わせページ

お問い合わせページのバリデーション

確認ページ

完了ページ

お問い合わせ受け付けメール

初期設定
初期設定は、お問い合わせフォームに限らず毎回実施することです。
Laravelのインストール
composer create-project --prefer-dist laravel/laravel contact_form
phpMyAdimnでDB作成
今回は「contact」というDBを作成しました。
.envファイルの設定
DBとメールの設定のため、.envファイルを編集します。
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=contact
DB_USERNAME=root
DB_PASSWORD=root
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=XXXXX
MAIL_PASSWORD=XXXXX
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=test@test.com
MAIL_FROM_NAME="${APP_NAME}"
今回メールは「MialTrap」を使用しています。
使い方は以下の記事を参考にしてみてください。
» メールの環境設定(ララ帳)
configファイルの設定
config/app.phpで日本語と時間の設定をします。
'timezone' => 'Asia/Tokyo',
'locale' => 'ja',
以上で、初期設定は終わりです。
コントローラーの作成
コントローラーの役割は、以下の通りです。
- ルートから受け取った情報をモデルに処理をお願いする
- モデルから受け取った情報をビューに表示する
具体的には、DBとの接続と処理、メール送信、バリデーション等を書いていきます。
php artisan make:controller ContactsController
※Laravelの規約に従うため、コントローラー名は必ず複数形にします。
app/Http/Controllers/ContactsController.phpが作成されました。
ここに、以下のfunctionを作っていきます。
- index
- confirm
- process
- complete
※processは、DB挿入とメール送信のためのものでページは作成しないので、viewは渡しません。
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ContactsController extends Controller
{
public function index()
{
return view('contacts.index');
}
public function confirm()
{
return view('contacts.confirm');
}
public function process()
{
}
public function complete()
{
return view('contacts.complete');
}
}
ルーティングの設定
routes/web.phpを編集します。
// お問い合わせ入力ページ
Route::get('/', 'ContactsController@index')->name('contact');
// 確認ページ
Route::post('/confirm', 'ContactsController@confirm')->name('confirm');
// DB挿入、メール送信
Route::post('/process', 'ContactsController@process')->name('process');
// 完了ページ
Route::get('/complete', 'ContactsController@complete')->name('complete');
ビューの作成
まず、resources/viewsにcontactsフォルダを作成し、
- index
- confirm
- complete
以上の3つのbladeテンプレート作成します。
フォームは「Laravel Collective」の「Forms & HTML」を使うので、インストールします。
※参考:Laravel Collective
composer require laravelcollective/html
index.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>お問い合わせ</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h1 class="text-center mt-2 mb-5">お問い合わせ</h1>
<div class="container">
{!! Form::open(['route' => 'confirm', 'method' => 'POST']) !!}
{{ csrf_field() }}
<div class="form-group row">
<p class="col-sm-4 col-form-label">お名前(10文字以内)<span class="badge badge-danger ml-1">必須</span></p>
<div class="col-sm-8">
{{ Form::text('name', null, ['class' => 'form-control']) }}
</div>
</div>
<div class="form-group row">
<p class="col-sm-4 col-form-label">メールアドレス<span class="badge badge-danger ml-1">必須</span></p>
<div class="col-sm-8">
{{ Form::text('email', null, ['class' => 'form-control']) }}
</div>
</div>
<div class="form-group row">
<p class="col-sm-4 col-form-label">電話番号</p>
<div class="col-sm-8">
{{ Form::text('tel', null, ['class' => 'form-control']) }}
</div>
</div>
<div class="form-group row">
<p class="col-sm-4 col-form-label">性別<span class="badge badge-danger ml-1">必須</span></p>
<div class="col-sm-8">
<label>{{ Form::radio('gender', "男性") }}男性</label>
<label>{{ Form::radio('gender', "女性") }}女性</label>
</div>
</div>
<div class="form-group row">
<p class="col-sm-4 col-form-label">お問い合わせ内容<span class="badge badge-danger ml-1">必須</span></p>
<div class="col-sm-8">
{{ Form::textarea('contents', null, ['class' => 'form-control']) }}
</div>
</div>
<div class="text-center">
{{ Form::submit('確認画面へ', ['class' => 'btn btn-primary']) }}
</div>
{!! Form::close() !!}
</div>
</div>
</body>
</html>
confirm.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>お問い合わせ - 確認</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h1 class="text-center mt-2 mb-5">お問い合わせ確認</h1>
<div class="container">
{!! Form::open(['route' => 'process', 'method' => 'POST']) !!}
{{ csrf_field() }}
<div class="form-group row">
<p class="col-sm-4 col-form-label">お名前(10文字以内)<span class="badge badge-danger ml-1">必須</span></p>
<div class="col-sm-8">
</div>
</div>
<div class="form-group row">
<p class="col-sm-4 col-form-label">メールアドレス<span class="badge badge-danger ml-1">必須</span></p>
<div class="col-sm-8">
</div>
</div>
<div class="form-group row">
<p class="col-sm-4 col-form-label">電話番号</p>
<div class="col-sm-8">
</div>
</div>
<div class="form-group row">
<p class="col-sm-4 col-form-label">性別<span class="badge badge-danger ml-1">必須</span></p>
<div class="col-sm-8">
</div>
</div>
<div class="form-group row">
<p class="col-sm-4 col-form-label">お問い合わせ内容<span class="badge badge-danger ml-1">必須</span></p>
<div class="col-sm-8">
</div>
</div>
<div class="text-center">
<button name="action" type="submit" value="return" class="btn btn-dark">入力画面に戻る</button>
<button name="action" type="submit" value="submit" class="btn btn-primary">送信</button>
</div>
{!! Form::close() !!}
</div>
</div>
</body>
</html>
complete.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>お問い合わせ - 完了</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
</head>
<body>
<div class="text-center">
<h1 class="text-center mt-2 mb-5">お問い合わせありがとうございました。</h1>
<a href="{{ route('contact') }}" class="btn btn-primary">お問い合わせ入力画面に戻る</a>
</div>
</body>
</html>
レイアウトを共通化する
すべてのファイルに共通している部分を、共通化していきます。
resources/viewsにlayout.blade.phpを作成します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>{{ $title }}</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
</head>
<body>
<div class="container">
@yield('content')
</div>
</body>
</html>
先ほど作成した以下のファイルに、埋め込んでいきます。
- index
- confirm
- complete
たとえば、index.blade.phpの場合は、以下の通り。
@php
$title = 'お問い合わせ';
@endphp
@extends('layout')
@section('content')
<h1 class="text-center mt-2 mb-5">お問い合わせ</h1>
〜略〜
</div>
@endsection
モデルとマイグレーションの作成
モデルはDBとの連携を行う機能で、マイグレーションはDBを管理する機能です。
php artisan make:model Contact -m
※Laravelの規約に従うため、モデル名は必ず単数形にします。そしてここの名前は、先ほど作成したDB名と統一しておきます。
app/Contact.phpが作成されるので、中身を書いていきましょう。
namespace App;
use Illuminate\Database\Eloquent\Model;
class Contact extends Model
{
// Primary Key
public $primaryKey = 'id';
// Timestamps
public $timestamps = true;
protected $fillable = [
'name',
'email',
'tel',
'gender',
'contents',
];
}
コマンドで-mを付けると、database/migrationsにマイグレーションファイルも一緒に作られるので、中身を書いていきます。
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateContactsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('contacts', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('email');
$table->string('tel')->nullable();
$table->string('gender');
$table->string('contents');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('contacts');
}
}
ここまで完了したら、以下のコマンドでDBにテーブルが作成されます。
php artisan migrate
バリデーションの設定
app/Http/Controllers/ContactsController.phpのconfirm の中に書いていきます。
public function confirm(Request $request)
{
$request->validate([
'name' => 'required|max:10',
'email' => 'required|email',
'tel' => 'nullable|numeric',
'gender' => 'required',
'contents' => 'required',
]);
return view('contacts.confirm');
}
index.blade.phpにエラーを表示させます。
@php
$title = 'お問い合わせ';
@endphp
@extends('layout')
@section('content')
<h1 class="text-center mt-2 mb-5">お問い合わせ</h1>
<div class="container">
{!! Form::open(['route' => 'confirm', 'method' => 'POST']) !!}
{{ csrf_field() }}
<div class="form-group row">
<p class="col-sm-4 col-form-label">お名前(10文字以内)<span class="badge badge-danger ml-1">必須</span></p>
<div class="col-sm-8">
{{ Form::text('name', null, ['class' => 'form-control']) }}
</div>
</div>
@if ($errors->has('name'))
<p class="alert alert-danger">{{ $errors->first('name') }}</p>
@endif
<div class="form-group row">
<p class="col-sm-4 col-form-label">メールアドレス<span class="badge badge-danger ml-1">必須</span></p>
<div class="col-sm-8">
{{ Form::text('email', null, ['class' => 'form-control']) }}
</div>
</div>
@if ($errors->has('email'))
<p class="alert alert-danger">{{ $errors->first('email') }}</p>
@endif
<div class="form-group row">
<p class="col-sm-4 col-form-label">電話番号</p>
<div class="col-sm-8">
{{ Form::text('tel', null, ['class' => 'form-control']) }}
</div>
</div>
@if ($errors->has('tel'))
<p class="alert alert-danger">{{ $errors->first('tel') }}</p>
@endif
<div class="form-group row">
<p class="col-sm-4 col-form-label">性別<span class="badge badge-danger ml-1">必須</span></p>
<div class="col-sm-8">
<label>{{ Form::radio('gender', "男性") }}男性</label>
<label>{{ Form::radio('gender', "女性") }}女性</label>
</div>
</div>
@if ($errors->has('gender'))
<p class="alert alert-danger">{{ $errors->first('gender') }}</p>
@endif
<div class="form-group row">
<p class="col-sm-4 col-form-label">お問い合わせ内容<span class="badge badge-danger ml-1">必須</span></p>
<div class="col-sm-8">
{{ Form::textarea('contents', null, ['class' => 'form-control']) }}
</div>
</div>
@if ($errors->has('contents'))
<p class="alert alert-danger">{{ $errors->first('contents') }}</p>
@endif
<div class="text-center">
{{ Form::submit('確認画面へ', ['class' => 'btn btn-primary']) }}
</div>
{!! Form::close() !!}
</div>
@endsection
このままだと英語で表示されるので、日本語化していきます。
resources/langのenフォルダと同階層にjaフォルダを作成し、validation.phpをコピペ。
修正した箇所は以下の通りです。
'email' => ':attributeが正しくありません。', 'max' => [ 'string' => ':attributeは:max文字以内で入力してください。', ], 'numeric' => ':attributeは数字で入力してください。', 'required' => ':attributeは必須項目です。', 'attributes' => [ 'name' => 'お名前', 'email' => 'メールアドレス', 'tel' => '電話番号', 'gender' => '性別', 'contents' => 'お問い合わせ内容', ],
お問い合わせで入力した情報を、確認画面で表示する
app/Http/Controllers/ContactsController.phpのconfirmに追記します。
public function confirm(Request $request)
{
$request->validate([
'name' => 'required|max:10',
'email' => 'required|email',
'tel' => 'nullable|numeric',
'gender' => 'required',
'contents' => 'required',
]);
// ここを追記
// フォームから受け取ったすべてのinputの値を取得
$inputs = $request->all();
return view('contacts.confirm', ['inputs' => $inputs]);
}
DBに挿入するために、confirm.blade.phpにhiddenでインプット内容を保持しておきます。
@php
$title = 'お問い合わせ - 確認';
@endphp
@extends('layout')
@section('content')
<h1 class="text-center mt-2 mb-5">お問い合わせ確認</h1>
<div class="container">
{!! Form::open(['route' => 'process', 'method' => 'POST']) !!}
{{ csrf_field() }}
<div class="form-group row">
<p class="col-sm-4 col-form-label">お名前(10文字以内)<span class="badge badge-danger ml-1">必須</span></p>
<div class="col-sm-8">
{{ $inputs['name'] }}
</div>
</div>
<input type="hidden" name="name" value="{{ $inputs['name'] }}">
<div class="form-group row">
<p class="col-sm-4 col-form-label">メールアドレス<span class="badge badge-danger ml-1">必須</span></p>
<div class="col-sm-8">
{{ $inputs['email'] }}
</div>
</div>
<input type="hidden" name="email" value="{{ $inputs['email'] }}">
<div class="form-group row">
<p class="col-sm-4 col-form-label">電話番号</p>
<div class="col-sm-8">
{{ $inputs['tel'] }}
</div>
</div>
<input type="hidden" name="tel" value="{{ $inputs['tel'] }}">
<div class="form-group row">
<p class="col-sm-4 col-form-label">性別<span class="badge badge-danger ml-1">必須</span></p>
<div class="col-sm-8">
{{ $inputs['gender'] }}
</div>
</div>
<input type="hidden" name="gender" value="{{ $inputs['gender'] }}">
<div class="form-group row">
<p class="col-sm-4 col-form-label">お問い合わせ内容<span class="badge badge-danger ml-1">必須</span></p>
<div class="col-sm-8">
{{ $inputs['contents'] }}
</div>
</div>
<input type="hidden" name="contents" value="{{ $inputs['contents'] }}">
<div class="text-center">
<button name="action" type="submit" value="return" class="btn btn-dark">入力画面に戻る</button>
<button name="action" type="submit" value="submit" class="btn btn-primary">送信</button>
</div>
{!! Form::close() !!}
</div>
@endsection
DBにデータ保存、メール送信
app/Http/Controllers/ContactsController.phpのprocessにDBにデータ保存、メール送信、入力画面に戻るボタンの動作を記述します。
public function process(Request $request)
{
$action = $request->get('action', 'return');
$input = $request->except('action');
if($action === 'submit') {
// DBにデータを保存
$contact = new Contact();
$contact->fill($input);
$contact->save();
// メール送信
Mail::to($input['email'])->send(new ContactMail('mails.contact', 'お問い合わせありがとうございます', $input));
return redirect()->route('complete');
} else {
return redirect()->route('contact')->withInput($input);
}
}
Mailableクラス作成
メール送信のためのMailableクラスを作成します。
php artisan make:mail ContactMail
これで、app/Mail/ContactMail.phpが作成されるので、編集していきます。
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class ContactMail extends Mailable
{
use Queueable, SerializesModels;
public $view;
public $subject;
public $data;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct($template, $subject, $data)
{
$this->template = $template;
$this->subject = $subject;
$this->data = $data;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->text($this->template)->subject($this->subject);
}
}
resources/views/mails/contact.blade.phpを作成し、送信するメールを書いていきます。
{{ $data["name"] }} 様
お問い合わせありがとうございます。
以下の内容で受け付けました。
=================
お名前: {{ $data["name"] }}
メールアドレス: {{ $data["email"] }}
電話番号: {{ $data["tel"] }}
性別: {{ $data["gender"] }}
お問い合わせ内容: {{ $data["contents"] }}
=================
app/Http/Controllers/ContactsController.phpにuse宣言も忘れずに書きましょう。
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Mail; use App\Contact; use App\Mail\ContactMail;
以上で、お問合せフォームが完成です。
お疲れさまでした\(^o^)/
【まとめ】お問い合わせフォームの作成手順【Laravel7】
初めてLaravelでお問合せフォームを作ってみたので、アウトプットしてみました。
コードだけ見たい!という方は、こちら(GitHub)からどうぞ。
Laravelの基礎的な知識は、以下のYouTube動画にお世話になりました。
2つ目は英語ですが、コードを見ながらであれば理解できると思います。
以上です。
最後まで見てくださり、ありがとうございました。
Laravelでいろいろ作っていこうと思っているので、またアウトプットします。
» Laravelで作成したアプリやアウトプットの一覧はこちら
最後に宣伝
ココナラで、コーディングの相談を受け付けています。
- CSSが上手く作れない
- JavaScriptが思ったように動かない
- ブログのデザインを修正したい
- 勉強中でわからないところがあるから教えてほしい
このようなお悩みを解決していますので、「こんなの解決できる?」ということがあったら、ぜひ質問だけでも以下のリンクよりどうぞ。




コメント