【Laravelお問合せ】初心者の方向けLaravelでお問い合わせフォームを実装する方法を解説!

【Laravelお問合せ】初心者の方向けLaravelでお問い合わせフォームを実装する方法を解説!

サイトを作成する際に、お問合せフォームの実装を検討していますか?

お問合せはサイトを作成するならほぼ必須と言える機能です。

これがないと閲覧者は気軽に疑問点などを質問することができませんし、何かあったときに連絡を取る手段がありません。

今回はお問合せフォームをLaravelで実装する方法を解説しています。

このような方におすすめ
  • Laravelでお問合せフォームを実装したい
  • お問合せとは何かを知りたい
  • お問合せが本当に必要かわからない
目次

お問合せの重要性

サイトを作成するにあたって、お問合せの機能はほぼ必須と言えます。

お問合せ機能はサイト管理者と閲覧者の唯一のコミュニケーションツールであり、閲覧者が疑問に思ったことや、間違いなどの指摘をお問合せによって行うのです。

そのため、Googleでもお問合せフォームが設置されているかを重要視しています。

事前準備

Gmailでお問合せを受け付ける場合は下記を設定してください。

  • 2段階認証の設定
  • アプリパスワードの設定

.envファイルにGmailの設定情報を追記します。

MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=example@example.com
MAIL_PASSWORD=16桁のアプリパスワード
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS="${MAIL_USERNAME}"

お問合せフォーム作成

実際にお問合せフォームを作成していきます。

ルーティングの設定

web.phpに下記ルーティングを追記します。

// お問い合わせ
Route::get('/contact', [ContactController::class, 'index'])->name('index');
//確認ページ
Route::post('/contact/confirm', [ContactController::class, 'confirm'])->name('confirm');
//送信完了ページ
Route::post('/contact/thanks', [ContactController::class, 'send'])->name('send');

フォーム画面、送信の確認画面、送信完了画面に分かれます。

コントローラーの作成

下記コマンドでコントローラーを作成していきます。

sail artisan make:controller ContactController

私はsailで作成していますが、sailを利用していないかたはsail部分をphpに変更してください。

作成したコントローラーを「App\Http\Controllers\Contact」フォルダへ移動します。
(こちらはお好みで)

ContactController.phpを下記のように編集します。

<?php

namespace App\Http\Controllers\Contact;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Requests\ContactFormRequest;
use App\Mail\ContactSendmail;
use Illuminate\Support\Facades\Mail;

class ContactController extends Controller
{
    public function index()
    {
        return view('contact.index');
    }

    public function confirm(ContactFormRequest $request)
    {
        // リクエスト内に必要のないものがある場合はスパムとみなす
        if (isset($request->honeypot)) {
            abort(404);
        }

        $contact = $request->all();
        return view('contact.confirm',compact('contact'));
    }

    public function send(ContactFormRequest $request)
    {
        $contact = $request->all();
        // TODO: メールアドレスはDBに持つ
        Mail::to('example@example.com')->send(new ContactSendmail($contact));
        $request->session()->regenerateToken();
        return view('contact.thanks');
    }
}

この時点ではエラーが出ますが先に進みます。

FormRequestクラスの作成

下記コマンドでFormRequestのクラスを作成します。

sail artisan make:request ContactFormRequest

下記のように編集します。

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class ContactFormRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'name' => 'required',
            'email' => 'required|email',
            'contact' => 'required'
        ];
    }
}

Viewの作成

ここからフォームのビューを作成します。

resources/views/contact/index.blade.php

@extends('layouts.app')

@section('content')
<div class="Form">
    <h2 class="h2-inquery">お問い合わせ内容入力</h2>
    <form method="POST" action="{{ route('confirm') }}">
        @csrf
        <div class="Form-Item">
        <p class="Form-Item-Label"><span class="Form-Item-Label-Required">必須</span>氏名</p>
        <input id="name" type="text" class="Form-Item-Input @error('name') is-invalid @enderror" name="name" value="{{ old('name') }}" autofocus placeholder="例)山田太郎">
        </div>
        <div class="error-field">
            @error('name')
                <span class="invalid-feedback" role="alert">
                    <strong>{{ $message }}</strong>
                </span>
            @enderror
        </div>
        <div class="Form-Item">
            <p class="Form-Item-Label"><span class="Form-Item-Label-Required">必須</span>メールアドレス</p>
            <input id="email" type="text" class="Form-Item-Input @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" autofocus placeholder="例)example@gmail.com">
        </div>
        <div class="error-field">
            @error('email')
                <span class="invalid-feedback" role="alert">
                    <strong>{{ $message }}</strong>
                </span>
            @enderror
        </div>
        <div class="Form-Item">
            <p class="Form-Item-Label isMsg"><span class="Form-Item-Label-Required">必須</span>お問い合わせ内容</p>
            <textarea id="contact" class="Form-Item-Textarea  @error('contact') is-invalid @enderror" name="contact" cols="30" rows="10"></textarea>
        </div>
        <div class="error-field">
            @error('contact')
                <span class="invalid-feedback" role="alert">
                    <strong>{{ $message }}</strong>
                </span>
            @enderror
        </div>
        <input id="honeypot" name="honeypot" type="hidden" style="display: none" />
        <input type="submit" class="Form-Btn" value="確認へ">
    </form>
</div>
@endsection

継承するビューファイルなどは各自で使用しているレイアウトを使用してください。

resources/views/contact/confirm.blade.php

@extends('layouts.app')

@section('content')
<div class="Form">
    <h2 class="h2-inquery">お問い合わせ内容確認</h2>
    <p class="text-message"><span class="confirm-message">下記内容で送信してもよろしいでしょうか?</span></p>
    <form method="POST" action="{{ route('send') }}">
        @csrf
        <div class="Form-Item">
        <p class="Form-Item-Label"><span class="Form-Item-Label-Required">必須</span>氏名</p>
        <input id="name" type="text" class="Form-Item-Input @error('name') is-invalid @enderror" name="name" value="{{ $contact['name'] }}" readonly>
        </div>
        <div class="error-field">
            @error('name')
                <span class="invalid-feedback" role="alert">
                    <strong>{{ $message }}</strong>
                </span>
            @enderror
        </div>
        <div class="Form-Item">
            <p class="Form-Item-Label"><span class="Form-Item-Label-Required">必須</span>メールアドレス</p>
            <input id="email" type="text" class="Form-Item-Input @error('email') is-invalid @enderror" name="email" value="{{ $contact['email'] }}" readonly>
        </div>
        <div class="error-field">
            @error('email')
                <span class="invalid-feedback" role="alert">
                    <strong>{{ $message }}</strong>
                </span>
            @enderror
        </div>
        <div class="Form-Item">
            <p class="Form-Item-Label isMsg"><span class="Form-Item-Label-Required">必須</span>お問い合わせ内容</p>
            <textarea id="contact" class="Form-Item-Textarea  @error('contact') is-invalid @enderror" name="contact" cols="30" rows="10" readonly>{{ $contact['contact'] }}</textarea>
        </div>
        <div class="error-field">
            @error('contact')
                <span class="invalid-feedback" role="alert">
                    <strong>{{ $message }}</strong>
                </span>
            @enderror
        </div>
        <div class="button-aria">
            <a href="{{ route('index') }}" class="btn-info">戻る</a>
            <input type="submit" class="Form-Btn" value="送信">
        </div>
    </form>
</div>
@endsection

下記はメール本文のビューです。

resources/views/contact/mail.blade.php

お問い合わせメールを受け付けました。<br>
<br>
◆氏名<br>
{!! $name !!}<br>
<br>
◆メールアドレス<br>
{!! $email !!}<br>
<br>
<br>
◆お問い合わせ内容<br>
{!! nl2br($contact) !!}

Mailableの作成

メールを送信する機能のクラスを作成します。

sail artisan make:mail ContactSendmail

下記のように編集します。

<?php

namespace App\Mail;

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

class ContactSendmail extends Mailable
{
    use Queueable, SerializesModels;

    private $name;
    private $email;
    private $contact;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct($contact)
    {
        $this->name = $contact['name'];
        $this->email = $contact['email'];
        $this->contact = $contact['contact'];
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this
        ->from($this->email)
        ->subject('自動送信メール')
        ->view('contact.mail')
        ->with([
            'name' => $this->name,
            'email' => $this->email,
            'contact' => $this->contact,
        ]);
    }
}

送信完了ページの作成

送信完了後のビューを作成します。

resources/views/contact/thanks.blade.php

@extends('layouts.app')

@section('content')
<div class="conrainer">
    <div class="card">
        <h2 class="h2-layout">送信完了</h2>
        <p class="text-message">
            送信しました。<br>お問い合わせありがとうございました。
        </p>
        <a href="{{ route('index') }}" class="btn-info">戻る</a>
    </div>
</div>
@endsection

以上で設定は完了になります。

CSSの適用

CSSの例を載せておきます。

レイアウトはお好みで構いません。

・PC版

/* お問合せ */
.Form {
    margin-left: auto;
    margin-right: auto;
    max-width: 720px;
  }
  .Form-Item {
    border-top: 1px solid #ddd;
    padding-bottom: 24px;
    width: 100%;
    display: flex;
    align-items: center;
  }
  .Form-Item:nth-child(5) {
    border-bottom: 1px solid #ddd;
  }
  .Form-Item-Label {
    width: 100%;
    max-width: 248px;
    letter-spacing: 0.05em;
    font-weight: bold;
    font-size: 18px;
  }
  .Form-Item-Label.isMsg {
    margin-top: 8px;
    margin-bottom: auto;
  }
  .Form-Item-Label-Required {
    border-radius: 6px;
    margin-right: 8px;
    padding-top: 8px;
    padding-bottom: 8px;
    width: 48px;
    display: inline-block;
    text-align: center;
    background: red;
    color: #fff;
    font-size: 14px;
  }
  .Form-Item-Input {
    border: 1px solid #ddd;
    border-radius: 6px;
    margin-left: 40px;
    padding-left: 1em;
    padding-right: 1em;
    height: 48px;
    flex: 1;
    width: 100%;
    max-width: 410px;
    background: #eaedf2;
    font-size: 18px;
  }
  .Form-Item-Textarea {
    border: 1px solid #ddd;
    border-radius: 6px;
    margin-left: 40px;
    margin-top: 18px;
    padding-left: 1em;
    padding-right: 1em;
    height: 216px;
    flex: 1;
    width: 100%;
    max-width: 410px;
    background: #eaedf2;
    font-size: 18px;
  }
  .Form-Btn {
    border-radius: 6px;
  margin-top: 32px;
  margin-left: auto;
  margin-right: auto;
  padding-top: 20px;
  padding-bottom: 20px;
  width: 280px;
  display: block;
  letter-spacing: 0.05em;
  background: #5bc8ac;
  color: #fff;
  font-weight: bold;
  font-size: 20px;
}

.invalid-feedback {
    color: red;
    font-size: 20px;
}

.error-field {
    margin-left: 300px;
    margin-bottom: 20px;
}

/* 戻るボタン */
.btn-info {
    font-family:'sans-serif';
    display:block;
    margin-top: 32px;
    margin-left: auto;
    margin-right: auto;
    padding:10px 10px;
    padding-top: 20px;
    padding-bottom: 20px;
    border-radius:5px;
    background-color:#ff838b;
    text-decoration: none;
    text-align: center;
    font-size: 20px;
    border-radius: 6px;
    width: 260px;
    display: block;
    letter-spacing: 0.05em;
    color: #fff;
    font-weight: bold;
    font-size: 20px;
}

/* 確認メッセージ */
.confirm-message {
    color: red;
    font-size: 20px;
}
/* お問合せ */

・スマホ版

/* お問合せ */
.Form {
    margin-top: 40px;
  }
  .Form-Item {
    padding-left: 14px;
    padding-right: 14px;
    padding-top: 16px;
    padding-bottom: 16px;
    flex-wrap: wrap;
  }
  .Form-Item-Label {
    max-width: inherit;
    display: flex;
    align-items: center;
    font-size: 3rem;
  }
  .Form-Item-Label.isMsg {
    margin-top: 0;
  }
  .Form-Item-Label-Required {
    border-radius: 6px;
    margin-right: 8px;
    padding-top: 8px;
    padding-bottom: 8px;
    width: 120px;
    display: inline-block;
    text-align: center;
    background: red;
    color: #fff;
    font-size: 3rem;
  }
  .Form-Item-Input {
    margin-left: 0;
    margin-top: 18px;
    height: 70px;
    flex: inherit;
    font-size: 3rem;
  }
  .Form-Item-Textarea {
    margin-top: 18px;
    margin-left: 0;
    height: 200px;
    flex: inherit;
    font-size: 2rem;
  }
  .Form-Btn {
    margin-top: 24px;
    margin-left: 20px;
    padding-top: 20px;
    padding-bottom: 20px;
    width: 250px;
    background: #5bc8ac;
    color: #fff;
    font-size: 20px;
  }

  .invalid-feedback {
    color: red;
    font-size: 20px;
}

.error-field {
    /* margin-left: 300px; */
    margin-bottom: 20px;
}

/* 戻るボタン */
.btn-info {
    font-family:'sans-serif';
    display:block;
    margin-top: 32px;
    margin-left: 20px;
    margin-right: auto;
    padding:10px 10px;
    padding-top: 20px;
    padding-bottom: 20px;
    border-radius:5px;
    background-color:#ff838b;
    text-decoration: none;
    text-align: center;
    font-size: 20px;
    border-radius: 6px;
    width: 230px;
    display: block;
    letter-spacing: 0.05em;
    color: #fff;
    font-weight: bold;
    font-size: 20px;
}

/* 確認メッセージ */
.confirm-message {
    color: red;
    font-size: 2rem;
}

/* 文章 */
.text-message {
    margin: 20px 0px 20px 0px;
    font-size: 2rem;
}
/* お問合せ */

以上、参考までに。

送信できない場合

受信するメーラーによってsmtpの設定が異なります。

各自、使用するメーラーのsmtpを調べて.envファイルに設定してください。

Gmailを利用する場合は本記事と同じように、2段階認証をオンにした上で、アプリパスワードを作成してください。

まとめ

今回はお問合せフォームをLaravelで実装しました。

お問合せがいかに重要かを説明しましたが、必須ではありません。

掲示板のような質疑応答ができる機能を追加すれば問題はないと思います。

ですが他の方に質問を見られたくないという人も少なからずいると思うので、個人的に質問できるお問合せを設置するのがよいでしょう。

関連記事

参考サイト

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

フリーランスエンジニアとして活動。
主に業務システムの要件定義~保守まで幅広く担当しています。
お気軽にお問い合わせください。

【趣味】
筋トレ/読書/プログラミング/資格の勉強

コメント

コメントする

目次