茶トラ猫エンジニア

フリーランスとして働く、先が見えないエンジニアのメモ帳

Laravelのold()で配列を扱う場合のインデックスの表現方法

検索フォームや登録画面など、form タグで値を POST する場面ってありますよね。

幸い、Laravel のバリデーションが柔軟にやってくれるので、フォームリクエストクラスを用意したり、ベタにコントローラにバリデーションを書いている人が多いと思います。

もちろん、下記のような複数を同じ名前で扱う項目のバリデーションにも対応はしてるのですが、エラー時に値を復元しようとしてミスったのでメモっておきます。

old()の項目名を配列で定義するには

例えば、こんなタグです。

<input type="text" name="hoge[]" value="A">
<input type="text" name="hoge[]" value="B">
<input type="text" name="hoge[]" value="C">

この value には old() を使って、入力時の値とデフォルト値を出し分けすることができます。

<input type="text" name="hoge[]" value="{{ old('hoge.0', $data[0]) }}">
<input type="text" name="hoge[]" value="{{ old('hoge.1', $data[1]) }}">
<input type="text" name="hoge[]" value="{{ old('hoge.2', $data[2]) }}">

画面の初期表示時には $data の値を表示し、その後は入力した値を保持しておきたい場合はこんな定義でいけると思います。

しかし、old() の項目には配列のように [] 内にインデックスを定義することもできます。

<input type="text" name="hoge[]" value="{{ old('hoge[0]', $data[0]) }}">
<input type="text" name="hoge[]" value="{{ old('hoge[1]', $data[1]) }}">
<input type="text" name="hoge[]" value="{{ old('hoge[2]', $data[2]) }}">

インデックスをループなどで動的に扱う場合は、こちらの配列っぽい書き方の方が都合がいい場合もあります。

ただ、ここに挙動の違いによるワナがありました。

罠というか単なる知識不足なだけですが・・・。

値がNULLの場合のデフォルト値の参照

以下の状態になるように値を設定して POST し、Laravel のバリデーションでエラーが発生したとします。

<input type="text" name="hoge[]" value="">
<input type="text" name="hoge[]" value="">
<input type="text" name="hoge[]" value="">

この時 POST された hoge の内容は配列で、中身は 3 つとも空文字です。

'hoge' => array(
  0 => '',
  1 => '',
  2 => '',
)

しかし old('hoge') を参照すると、それぞれの値は NULL になっています。

'hoge' => array(
  0 => NULL,
  1 => NULL,
  2 => NULL,
)

これ自体は問題ではないのですが、blade 側で old() の第一引数の形を以下のように書くと、第二引数のデフォルト値の方が使われてしまいます。

<input type="text" name="hoge[]" value="{{ old('hoge[0]', isset($data[0])) ? $data[0] : '' }}">
<input type="text" name="hoge[]" value="{{ old('hoge[1]', isset($data[1])) ? $data[1] : ''  }}">
<input type="text" name="hoge[]" value="{{ old('hoge[2]', isset($data[2])) ? $data[2] : ''  }}">

逆に、ドットでインデックスを繋いで定義している場合は、目的通り old('hoge.%d') の値が使われます。

<input type="text" name="hoge[]" value="{{ old('hoge.0', isset($data[0])) ? $data[0] : '' }}">
<input type="text" name="hoge[]" value="{{ old('hoge.1', isset($data[1])) ? $data[1] : ''  }}">
<input type="text" name="hoge[]" value="{{ old('hoge.2', isset($data[2])) ? $data[2] : ''  }}">

急ぎの対応があったので、実際にサンプルを使って細かく確認したわけではないのですが、挙動としては上記のように見受けられました。

次回、同じような場面に遭遇したらじっくり動作をみてみたいと思います。