前回の例はメールアドレス1つの入力でしたが、今度はちょっと複雑にして複数のメールアドレスを入力する配列入力の話です。

入力画面

画面はこんな感じです。

そして、その画面のブレードはこんなです。前回で定義したx-inputのコンポーネントを使用しています。

<x-layout>
  <div class="container">
    <div class="row justify-content-center">
      <div class="col-md-8">
        <div class="card">
          <div class="card-header">登録</div>

          <div class="card-body">
            <x-form action="{{ route('register') }}">

            @for($i=1;$i <=3;$i++)
              <div class="row mb-3">
                <x-label name="email{{ $i }}">メールアドレス {{ $i }}</x-label>

                <div class="col-md-6">
                  <x-input id="email{{ $i }}" type="email" name="emails[{{ $i }}]" />
                </div>
              </div>
            @endfor

              <div class="row mb-0">
                <div class="col-md-6 offset-md-4">
                  <x-button type="submit" class="m-2" level="primary">登録</x-button>
                </div>
              </div>
            </x-form>
          </div>
        </div>
      </div>
    </div>
  </div>
</x-layout>

前回と違って、name="emails[1]"のように配列の文字列となっていることに注意を。

なにかがおかしい!

上の画面で以下のようにEメールでない値を入れて「登録」ボタンを押すと、

もちろん、画面ではエラーが表示されることを期待しますが、何もでてきません。しかも、入力した値は空になってしまいます。まさに、最初の空の入力画面と同じ状態です。

ちなみに、バリデーションのルールは以下です。

'emails'   => ['required', 'array'],
'emails.*' => ['string', 'email', 'max:255'],

何がおかしいのでしょう?

ここで、前回のx-inputのコンポーネントをここで再度掲載します。

@props([
    'type'  => 'text',
    'name',
    'value' => null,
])
 
<input
  type="{{ $type }}"
  name="{{ $name }}"
  value="{{ old($name, $value) }}"
 
  @error($name)
    {{ $attributes->class('form-control is-invalid') }}
  @else
    {{ $attributes->class('form-control') }}
  @enderror
/>
 
@error($name)
  <span class="invalid-feedback" role="alert">
      <strong>{{ $message }}</strong>
  </span>
@enderror

調査すると、問題はコンポーネントにおける、old($name, $value)@error($name)に渡している$nameの値です。

配列なので、この$nameには、emails[1]、emails[2]、emails[3]の文字列が入ってきます。
しかし、old()はこれらの文字列を理解しません。@errorに関しては、debugbarでセッションを見ると、以下のように、emails[1]ではなく、emails.1という文字列になっています。

対応

ということは、old()や@error()に渡す指標が配列の文字列なら、ドットの文字列に変換すればよいですね。
以下は、改良したコンポーネントです。

@props([
    'type'  => 'text',
    'name',
    'value' => null,
])
@php
  $index = str_replace(['.', '[]', '[', ']'], ['_', '', '.', ''], $name); // 'emails[1]'が'emails.1'となる
@endphp
<input
  type="{{ $type }}"
  name="{{ $name }}"
  value="{{ old($index, $value) }}"

  @error($index)
    {{ $attributes->class('form-control is-invalid') }}
  @else
    {{ $attributes->class('form-control') }}
  @enderror
/>

@error($index)
  <span class="invalid-feedback" role="alert">
      <strong>{{ $message }}</strong>
  </span>
@enderror

これで再度「登録」ボタンを押すと、期待通りにエラーが表示されます。

By khino