Laravel と checkbox と old() の話

例えば

<div class="form-group form-check">
  <input type="checkbox" class="form-check-input" name="is_admin" id="is_admin">
  <label class="form-check-label" for="is_admin">管理者</label>
</div>

このようなチェックボックスがあるユーザー情報の編集画面を想定したときに、「初めて編集画面を開いたときには DB から取得した $user->is_admin の値に基づいたチェック状態で表示し、更新ボタンを押してバリデーションエラーが発生したときには、最後の入力に応じたチェック状態で表示する」みたいな実装をすることが多いと思います。

このような場合に、単純に

<div class="form-group form-check">
    <input type="checkbox" class="form-check-input" name="is_admin" id="is_admin" @if (old('is_admin', $user->is_admin) == 1) checked @endif>
    <label class="form-check-label" for="is_admin">管理者</label>
</div>

としても、$user->is_admin が 1 で、直近の入力ではチェックボックスがオフの場合、チェックボックスをオフにすることができません。チェックボックスがオフの状態で送信すると、old('is_admin') は null となり、old('is_admin', $user->is_admin) は、デフォルト値である $user->is_admin の値になってしまうからです。

このような場合、コントローラー側で少し値を加工してやるとうまく扱うことができます。

public function update(Request $request, User $user)
{
    $request->merge([
        'is_admin' => $request->boolean('is_admin') ? 1 : 0,
    ]);

    $validated_data = $request->validate([
        'name'     => ['required'],
        'is_admin' => ['boolean'],
    ]);

    $user->fill($validated_data)->save();
}

以前に紹介したフォームリクエストprepareForValidation を使っても同様のことができますが、今回くらいの処理であれば、merge メソッドを使ったほうが手っ取り早いかと。値を加工して merge メソッドでリクエストに戻してやることで、バリデートもしやすくなりますし、old ヘルパでも扱いやすくなります。

この記事を書いた人
グッドネイバー

“ Webに悩むお客さまの「よき隣人」でありたい ” をモットーに、Web システム開発(主に Laravel)、Web マーケティング支援の仕事をしています。お仕事のご依頼・ご相談はこちらからお気軽にどうぞ。

PHPLaravel