投稿日:2024年7月25日

Laravelを勉強して数ヶ月が経ちました。
色々な教材やサイトを参考にし、申し込みフォームを作ってみました。

▲簡易的なものを作ってみました。
クリックでフォームに遷移します。実際に動きますがメールは送信されません。

 フォームに必要な機能 

入力ページ、入力内容確認ページ、完了ページの作成。
バリデーションの表示。
バリデーションが表示されても入力した内容は保持すること。
入力内容確認ページから入力ページに戻った際、入力した内容は保持されていること。
管理者(Gmail)と申し込み者へのメール送信。
受付番号とタイムスタンプを付与しCSVへ書き出し(追記)。
データベースへの保存は今回行っていません。

全ては書き切れないので、今回は、
テキスト、テキストエリア、プルダウン、ラジオボタン、チェックボックスの入力ページ(index.blade.php)と、入力内容確認ページ(confirm.blade.php)。
それとバリデーション表示時と、入力内容確認ページから入力ページに戻った際、入力した内容を保持させる記述を紹介します。
いろいろなサイトを検索して自分なりにまとめてあります。

 テキスト 

入力ページ
index.blade.php

<tr>
    <th>お名前<span>必須</span></th>
    <td>
        <div class="inptBox">
            <div>
                <input id="name" type="text" name="name" size="30" value="{{ old('name') }}">
                @error('name')
                    <p class="errMessege">{{$message}}</p>
                @enderror
            </div>
    </td>
</tr>

▲6行目、value="{{ old('name') }}" はold関数と呼ばれるもので、この記述で画面遷移の際、入力値を保持してくれます。
7〜9行目、エラー処理です。@error('項目名') と書くことで $message へ値を渡し、エラーがあった場合にバリデーションを表示してくれます。

以下がお名前の確認画面ページです。
confirm.blade.php

<tr>
    <th>お名前</th>
    <td>
        <div class="inptBox">
            <div>{{ $contents['name'] }}
                <input name="name" type="hidden" value="{{ $contents['name'] }}">
            </div>
        </div>
    </td>
</tr>

value="{{ old('name') }}" と書くことがセオリーですが上記のように記述しておきました。
value="{{ $contents['name'] }}" という記述でコントローラーから受け取った値を表示させます。
hiddenで非表示にしながら値を渡すようにしています。
これは確認ページの全ての項目で同じ書き方にしています。

確認画面のボタン

<input id="backBtn" type="button" onClick="history.back()" value="戻る">
<input id="submitConf" type="submit" name="submitBtnVal" value="この内容で送信">

▲以下で説明する、ラジオボタンプルダウンメニューの場合、old('項目名') だと値が保持されないため1行目のように history.back() を実装しています。
何か他に方法があるとは思いますが、今回は history.back() で実装しました。

 ラジオボタン 

入力ページ
index.blade.php

<tr>
    <th>次回の案内を<br>希望しますか?<span>必須</span></th>
    <td>
        <div class="inptBox">
            <div>
                <div id="next_guidance">
                    <div class="radioWrap">
                        <label><input id="next_guidance01" name="next_guidance" type="radio" value="はい" {{ old ('next_guidance') == 'はい' ? 'checked' : '' }} checked>はい</label>
                    </div>
                    <div class="radioWrap">
                        <label><input id="next_guidance02" name="next_guidance" type="radio" value="いいえ" {{ old ('next_guidance') == 'いいえ' ? 'checked' : '' }}>いいえ</label>
                    </div>
                </div>
            </div>
        </div>
    </td>
</tr>

▲8、11行目。
{{ old ('next_guidance') == 'はい' ? 'checked' : '' }}
{{ old ('next_guidance') == 'いいえ' ? 'checked' : '' }}
の記述でバリデーション表示の際、値を保持させます。

確認ページ
confirm.blade.php

<tr>
    <th>次回の案内</th>
    <td>
        <div class="inptBox">
            <div>{{ $contents['next_guidance'] }}
                <input name="next_guidance" type="hidden" value="{{ $contents['next_guidance'] }}">
            </div>
        </div>
    </td>
</tr>

▲テキスト同様、value="{{ $contents['next_guidance'] }}" という記述でコントローラーから受け取った値を表示させてます。

 プルダウンメニュー 

入力ページ
index.blade.php

<tr>
    <th>都道府県<span>必須</span></th>
    <td>
        <div class="inptBox">
            <div>
                <select name="pref" id="pref">
                    @foreach(config('pref') as $key => $prefVal)
                        <option value="{{$prefVal}}" @if($prefVal ==old('pref')) selected @endif>{{$prefVal}}</option>
                    @endforeach
                </select>
                @error('pref')
                    <p class="errMessege">{{$message}}</p>
                @enderror
            </div>
            </div>
    </td>
</tr>

▲ひたすらoptionで書くのは冗長的なので config('pref') の記述で別途pref.phpから読み込み、@foreachディレクティブで表示させています。
8行目の@ifディレクティブで値を保持させます。
以下がpref.phpになります。

<?php
return [
	'選択してください'=>'選択してください',
	'北海道' => '北海道',
	'青森県' => '青森県',
	'岩手県' => '岩手県',
	'秋田県' => '秋田県',
	'宮城県' => '宮城県',
	'山形県' => '山形県',
	'福島県' => '福島県',

〜〜〜〜〜〜 省略 〜〜〜〜〜〜

	'佐賀県' => '佐賀県',
	'長崎県' => '長崎県',
	'大分県' => '大分県',
	'熊本県' => '熊本県',
	'宮崎県' => '宮崎県',
	'鹿児島県' => '鹿児島県',
	'沖縄県' => '沖縄県',
];

▲ただ、このままだと「選択してください」のvalue値が「選択してください」になったり、関東地方などの区切りが入れらないので、以下のJavaScriptで調整します。
左辺の「選択してください」を空欄にしても上手く表示できませんでした。

$("#pref option:first-child").val("");
$("#pref option").slice(1, 8).wrapAll('<optgroup label="北海道・東北地方">');
$("#pref option").slice(8, 15).wrapAll('<optgroup label="関東地方">');
$("#pref option").slice(15, 24).wrapAll('<optgroup label="中部地方">');
$("#pref option").slice(24, 31).wrapAll('<optgroup label="近畿地方">');
$("#pref option").slice(31, 35).wrapAll('<optgroup label="四国地方">');
$("#pref option").slice(35, 40).wrapAll('<optgroup label="中国地方">');
$("#pref option").slice(40, 48).wrapAll('<optgroup label="九州・沖縄地方">');

jQueryの記述です。「選択してください」のvalue値を空欄にするのと、各地方の区切りが入れています。

確認ページ
confirm.blade.php

<tr>
    <th>都道府県</th>
    <td>
        <div class="inptBox">
            <div>{{ $contents['pref'] }}
                <input name="pref" type="hidden" value="{{ $contents['pref'] }}">
            </div>
        </div>
    </td>
</tr>

▲こちらも同じように、value="{{ $contents['pref'] }}" という記述でコントローラーから受け取った値を表示させてます。

 チェックボックス 

入力ページ
index.blade.php

<tr>
    <th>知ったきっかけを<br>教えてください。<span>必須</span></th>
    <td>
        <div class="inptBox">
            <div>
                <p class="supplement">※複数回答可</p>
                <div id="trigger">
                    @foreach (config('trigger') as $trigger)
                    <label>
                        <input type="checkbox" name="trigger[]" value="{{$trigger}}" {{ is_array(old("trigger")) &&
                            in_array($trigger, old("trigger"), true)? ' checked' : '' }}>{{$trigger}}</label>
                    @endforeach
                </div>
                @if(!is_array(old("trigger")))
                @error('trigger[]')
                <p class="errMessege">{{$message}}</p>
                @enderror
                @endif
            </div>
        </div>
    </td>
</tr>

▲チェックボックスの項目もconfig('trigger') trigger.phpから読み込み、@foreachディレクティブで表示させます。
チェックボックスは複数選択が可能なので、配列として値が取得されます。
{{ is_array(old("trigger")) && in_array($trigger, old("trigger"), true)? ' checked' : '' }}
is_array()関数で配列なのかを評価し、in_array()関数で配列の中身の有無を取得します。
両方合致したらチェックを入れる仕様になっています。

確認ページ
confirm.blade.php

<tr>
    <th>知ったきっかけ</th>
    <td>
        <div class="inptBox">{{implode('、', $contents['trigger'])}}</div>
        <input name="trigger[]" type="hidden" value="{{implode('、', $contents['trigger'])}}"></div>
    </td>
</tr>

▲配列で取得するのでimplode()関数を使い、読点「、」で区切ります。
カンマ区切りにするとCSV書き出しの際、一手間かかるので読点「、」にしました。

 テキストエリア 

入力ページ
index.blade.php

<tr>
    <th>備考</th>
    <td>
        <div class="inptBox">
            <div><textarea id="remarks" name="remarks" cols="70" rows="3">{{ old('remarks')}}</textarea></div>
        </div>
    </td>
</tr>

old()関数で表示してます。オーソドックスなLaravelの書き方になります。

確認ページ
confirm.blade.php

<tr>
    <th>備考</th>
    <td>
        <div class="inptBox">
            <div>{!! nl2br(e($contents['remarks'] )) !!}
                <input name="remarks" type="hidden" value="{!! e($contents['remarks'] ) !!}">
            </div>
        </div>
    </td>
</tr>

▲5行目、Blade記法 {{ xxxxx }} はPHPのhtmlspecialchars()が効きますが改行コードが無視されてしまいます。
そこで {!! xxxxx !!} という書き方をしてhtmlspecialchars()を無効化します。
しかし、コンテンツには必要なのでe()関数を使い、個別に $contents['remarks'] に適用する必要があります。
e()関数はPHPのhtmlspecialchars()Laravelでの書き方になります。
nl2br()関数は改行だけ有効にする関数になります。
つまり、下図のよう扱いになります。

6行目のvalue値にnl2br()関数がないのは、nl2br()関数を記述すると、なぜかCSVを書き出した際に改行が2つ入ってしまう現象が起きてしまいました。
それを回避するためです。

まとめ

Laravelとは、アプリ開発やシステム開発に特化したPHPフレームワークです。

ちなみにLaravelという名称は、ナルニア国物語 に登場するケア・パラヴェル(Cair Paravel)という王様と王女様の居城の名前が由来になっているそうです。


Model(モデル)、View(ビュー)、Controller(コントローラー)。
MVCと呼ばれる設計モデルに、プログラムの役割を分担させる特徴があります。
さらに、webを見ている人からのリクエスト、サーバーからのレスポンスといった、データ転送時の経路を管理するルーティングと呼ばれる設計も含んでいます。

View(ビュー)には、入力ページ(index.blade.php)、入力確認ページ(confirm.blade.php)、完了ページ(complete.blade.php)。
Controller(コントローラー)には、メール送信CSV書き出し(追記)バリデーションなどの記述。
それと、上記、View(ビュー)のそれぞれのプログラムを記述します。
ルーティング設定web.phpに記述します。

データを行ったり来たりしながらなので、慣れるまで相当な試行錯誤が必要です。
Laravelは初心者でも習得しやすいとうたっているサイトも多々ありますが、そんなに簡単に習得できるものではないと思います。

以降は、MiddlewareEloquentORMなども学び、データベースとの連携やアプリ制作に取り組みたいと思います。

最後までお読みいただき、ありがとうございます。

Laravel関連の記事
Pocket