投稿日:2025年1月25日

申し込みフォームを作る案件が多いです。
Laravelチェックボックスの扱いでハマったので書き残しておきたいと思います。
チェックボックス複数選択可能な項目です。
必須項目だったり、任意項目だったり、「同意する」などの択一のチェックボックスも存在します。

▲3種類のチェックボックスを作りました。
「野菜」は複数選択可能で必須項目です。
「配達状況」は項目が1つで必須ではありません。
チェックするとvalueが返り、チェックしないと空が返ります。
「配達間隔」は項目が2つ。複数選択可能で必須ではありません。
チェックするとvalueが返り、チェックしないと空が返ります。

「野菜」は必須なので必ず1つ以上の返りがあります。
ありがちなのが、必須ではなく、返りが1つもない状態でsubmitをクリックすると、確認画面で500のエラーになる現象です。

▲見たくもないですよね。

これの回避方法を順番に紹介します。

❶ チェックボックス(必須) 複数選択

▼index.blade.php(入力画面)

<tr>
    <th>野菜<span>必須</span></th>
    <td>
        <div class="inptBox">
            <div>
                <p class="supplement">※複数回答可</p>
                <div id="vegetables">
                    <label>
                        <input type="checkbox" name="vegetables[]" value="にんじん" {{ is_array(old("vegetables")) && in_array("にんじん", old("vegetables"), true)? ' checked' : '' }}>にんじん
                    </label>
                    <label>
                        <input type="checkbox" name="vegetables[]" value="たまねぎ" {{ is_array(old("vegetables")) && in_array("たまねぎ", old("vegetables"), true)? ' checked' : '' }}>たまねぎ
                    </label>
                    <label>
                        <input type="checkbox" name="vegetables[]" value="ピーマン" {{ is_array(old("vegetables")) && in_array("ピーマン", old("vegetables"), true)? ' checked' : '' }}>ピーマン
                    </label>
                    <label>
                        <input type="checkbox" name="vegetables[]" value="キャベツ" {{ is_array(old("vegetables")) && in_array("キャベツ", old("vegetables"), true)? ' checked' : '' }}>キャベツ
                    </label>
                    <label>
                        <input type="checkbox" name="vegetables[]" value="白菜" {{ is_array(old("vegetables")) && in_array("白菜", old("vegetables"), true)? ' checked' : '' }}>白菜
                    </label>
                </div>
                {{-- バリデーション処理 --}}
                @if(!is_array(old("vegetables")))
                @error('vegetables[]')
                <p class="errMessege">{{$message}}</p>
                @enderror
                @endif
            </div>
        </div>
    </td>
</tr>

{{ is_array(old("vegetables")) && in_array("にんじん", old("vegetables"), true)? ' checked' : '' }}
のような書き方が「確認画面」から戻ったときやバリデーションエラーが表示されたときでもチェック(入力)した内容を保持する記述になります。
ないと再度チェックしたり、再入力しないといけなくなります。
チェック項目は複数の返りがあるので配列の扱いになります。
is_array(old("vegetables"))はold("vegetables")が配列か判定する関数です。
in_array("にんじん", old("vegetables"),true)は、old("vegetables")内に「にんじん」が存在するかを判定します。
この1行で三項演算子になっており、
配列内に「にんじん」が存在すればチェックを入れ、なければチェックを入れない。
という意味になります。

▼confirm.blade.php(確認画面)

<tr>
    <th>野菜</th>
    <td>
        <div class="inptBox">{{implode('、', $contents['vegetables'])}}</div>
        <input name="vegetables[]" type="hidden" value="{{implode('、', $contents['vegetables'])}}"></div>
    </td>
</t

Laravelのセオリーな書き方になります。
implode関数は返ってきた配列$contents['vegetables']を第一引数の‘、’で区切ることができます。

▲確認画面。返りが複数あれば「、」区切りで。

▲確認画面。1つの場合「、」は出力されません。

❷ チェックボックス(任意) 1つの選択

▼index.blade.php(入力画面)

<tr>
    <th>配達状況</th>
    <td>
        <label>
            <input type='hidden' value='' name='delivery_notice'>
            <input type="checkbox" name="delivery_notice" value="受け取る" {{ old('delivery_notice')=='受け取る' ? 'checked' : '' }}>受け取る
        </label>
    </td>
</tr>

▲項目が1つの場合、submitで500エラーが出ないようにするには5行目のように書きます。type="hidden"で非表示にし、value=''で空の扱いにします。
つまりチェックしたらチェックした項目を、してなければ空を返すということです。
6行目のname="delivery_notice"は、項目が1つなので配列扱いにはしません。[ ]は不要です。
テキストのように{{ old('delivery_notice')=='受け取る' ? 'checked' : '' }}と書き、複数 必須のときのようにis_arrayin_arrayなどの配列の扱いにはしません。

▼confirm.blade.php(確認画面)

<tr>
    <th>配達状況</th>
    <td>
        <div class="inptBox">{{$contents['delivery_notice']}}</div>
        <input name="delivery_notice" type="hidden" value="{{$contents['delivery_notice']}}"></div>
    </td>
</tr>

▲このように普通の書き方になります。

▲結果、チェックが入っていれば値を返し、

▲チェックが入ってなければ空を返します。

❸ チェックボックス(任意) 複数選択

▼index.blade.php(入力画面)

<tr>
    <th>配達間隔</th>
    <td>
        <div id="delivery_interval" class="deliveryInterval">
            <p class="supplement">※複数回答可</p>
            <label>
                <input type='hidden' value='' name='delivery_interval[]'>
            </label>
            <label>
                <input type="checkbox" name="delivery_interval[]" value="1ヶ月" {{ is_array(old("delivery_interval")) && in_array("1ヶ月", old("delivery_interval"), true)? ' checked' : '' }}>1ヶ月
            </label>
            <label>
                <input type="checkbox" name="delivery_interval[]" value="3ヶ月" {{ is_array(old("delivery_interval")) && in_array("3ヶ月", old("delivery_interval"), true)? ' checked' : '' }}>3ヶ月
            </label>
        </div>
    </td>
</tr>

▲7行目、上の項目1つのときと同様ですが、今回は複数項目なのでname='delivery_interval[]'ように配列扱いにします。配列なので[ ]が必要になります。
10行目、13行目。必須の複数選択と同じように書きます。

▼confirm.blade.php(確認画面)

<tr>
    <th>配達間隔</th>
    <td>
        <div class="inptBox">{{implode('、', array_filter($contents['delivery_interval']))}}</div>
        <input name="delivery_interval[]" type="hidden" value="{{implode('、', array_filter($contents['delivery_interval']))}}"></div>
    </div>
    </td>
</tr>

▲ここでのポイントは4行目のarray_filter関数になります。
入力画面の7行目<input type=’hidden’ value=” name=’delivery_interval[]’>の記述で空の項目が返ります。
ここでは「1ヶ月」と「3ヶ月」の2つの項目ですが、実は空の項目も含めて計3つの値が変えることになるのです。
つまり、「1ヶ月」と「3ヶ月」にチェックを入れると、下図のように「空、1ヶ月、3ヶ月」という値が返ってきます。

array_filter関数は配列の空白以外の要素を返すので上のソースコードのように書きます。

▲結果、正しく出力されるようになります。

▲チェックなしで空白になります。
もちろん1ヶ月なら1ヶ月のみ出力され、3ヶ月なら3ヶ月のみ出力されます。

まとめ

項目が1つのチェックボックスは、PHPでのフォーム作成のときに何回か経験したことがあります。
が、必須ではない任意の複数選択のチェックボックスは扱ったことがありませんでした。
正直、どうしてエラーが出るのか分からず、原因が何なのか調べるのにも苦労した次第です。

今回はチェックボックスを取り上げました。
ラジオボタンではどうでしょう?
ラジオボタンは択一なので、また違った扱いが必要だと思います。
さらに検証したいと思います。

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

Laravel関連の記事
Pocket