Laravel collective セレクトボックスを実装する

# 目的

- Laravelでセレクトボックスを実装するときの方法をまとめる

# 実施環境

- ハードウェア環境

| 項目 | 情報 |
| --- | --- |
| OS | macOS Catalina(10.15.3) |
| ハードウェア | MacBook Pro (16-inch ,2019) |
| プロセッサ | 2.6 GHz 6コアIntel Core i7 |
| メモリ | 16 GB 2667 MHz DDR4 |
| グラフィックス | AMD Radeon Pro 5300M 4 GB Intel UHD Graphics 630 1536 MB |

- ソフトウェア環境

| 項目 | 情報 | 備考 |
| --- | --- | --- |
| PHP バージョン | 7.4.3 | Homebrewを用いて導入 |
| Laravel バージョン | 7.0.8 | Composerを用いて導入 |
| MySQLバージョン | 8.0.19 for osx10.13 on x86_64 | Homebrewを用いて導入 |

# 実施方法概要

1. laravelcollectiveのインストール
1. ビューファイルにコードの記載

# 実施方法詳細

1. laravelcollectiveのインストール
    1. アプリ名ディレクトリで下記コマンドを実行する。

        ```terminal
        $ composer require laravelcollective/html
        ```
1. ビューファイルにコードの記載
    1. セレクトボックスを表示したいビューファイルを開く。
    1. 下記のコードを記載する。

        ```php
        {{Form::select('age', ['Under 18', '19 to 64', 'Over 65'])}}
        ```
    1. ローカルサーバを起動し、下記のように表示される事を確認する。
        - 通常時

            <img width="145" alt="スクリーンショット 2020-04-13 17.42.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/e6003a90-70e8-1f1f-ae2b-868d16c373c6.png">
        - セレクトボックスクリック時

            <img width="212" alt="スクリーンショット 2020-04-13 17.42.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/79597145-b652-c615-2c7f-964f72b5ada9.png">

# 簡単な解説

1. 先に記載したセレクトボックスのコードをHTMLのselect要素で記載するとどうなるか比較してみる。
    - Form::select()メソッド
    
        ```php
        {{Form::select('age', ['Under 18', '19 to 64', 'Over 65'])}}
        ```
    - HTMLのselect要素

        ```html
        <select name="age">
          <option value="0">Under 18</option>
          <option value="1">19 to 64</option>
          <option value="2">Over 65</option>
        </select>
        ```
1. セレクトボックスでのデフォルト表示を変更したい時は下記のようにする。また、記載内容をHTMLのselect要素と比較する。
    - Form::select()メソッドで「Over 65」をデフォルト表示に設定
    
        ```php
        {{Form::select('age', ['Under 18', '19 to 64', 'Over 65'], 2)}}
        ```
    - HTMLのselect要素

        ```html
        <select name="age">
          <option value="0">Under 18</option>
          <option value="1">19 to 64</option>
          <option value="2" selected="selected">Over 65</option>
        </select>
        ```
1. セレクトボックスで選択した際の値を任意に決めたい時は下記のようにする。また、記載内容をHTMLのselect要素と比較する。
    - Form::select()メソッド

        ```php
        {{Form::select('age', ['first_ans' => 'Under 18', 'second_ans' => '19 to 64', 'third_ans' => 'Over 65'])}}
        ```
    - HTMLのselect要素

        ```html
        <select name="age">
          <option value="first_ans">Under 18</option>
          <option value="second_ans">19 to 64</option>
          <option value="third_ans">Over 65</option>
        </select>
        ```

# 実装の例

- `/add`にてセレクトボックスを表示する。当該ビューファイルに値を送信するボタンを設置し、押下をトリガーとして動作する。
- `/regist`にセレクトボックスでの入力値を飛ばし、リンクするコントローラのアクションで値を受け取る一連の処理を記載する。
- コントローラ名はPostControllerとする。
- セレクトボックスを表示するビューファイル名はaddとする。
- PostControllerのregistアクションで入力値を取得する。

- 当該処理に必要なルーティングファイルの内容のみ抜粋して記載する。

    ```アプリ名ディレクトリ/routes/web.php
    Route::get('/add', 'PostController@add');
    Route::post('/regist', 'PostController@regist');
    ```
- 当該処理に必要なコントローラファイルの内容のみ抜粋して記載する。

    ```アプリ名ディレクトリ/app/Http/Controller/PostController.php
    class PostController extends Controller
    {
        public function add_todo() {
            return view('post.');
        }

        public function regist(Request $request) {
            $age => $request->age,

        //DBへのデータ格納処理
        //リダイレクト処理
        }
    }
    ```

- 当該処理に必要なセレクトボックスを表示するビューファイルの内容のみ抜粋して記載する。

    ```アプリ名ディレクトリ/resources/view/post/add.blade.php
    <form action="/regist" method="post">
        @csrf
        {{Form::select('age', ['Under 18', '19 to 64', 'Over 65'])}}
        <input type="submit" value="send">
    </form>
    ```
- ビューファイルで「Under 18」を選択して、ブラウザの「send」ボタンをクリックした場合、PostController内のregistアクション内の`$age`には0が格納される。
- ビューファイルで「19 to 64」を選択して、ブラウザの「send」ボタンをクリックした場合、PostController内のregistアクション内の`$age`には1が格納される。
- ビューファイルで「Over 65」を選択して、ブラウザの「send」ボタンをクリックした場合、PostController内のregistアクション内の`$age`には2が格納される。

# 追記（2022/11/07）

- ライブラリlaravel collectiveの導入で使用できるようになるFormファサードのselectメソッドは下記のように定義されている。
    - `vendor/laravelcollective/html/src/FormBuilder.php`

        ```vendor/laravelcollective/html/src/FormBuilder.php
        /**
         * Create a select box field.
         *
         * @param  string $name
         * @param  array  $list
         * @param  string|bool $selected
         * @param  array  $selectAttributes
         * @param  array  $optionsAttributes
         * @param  array  $optgroupsAttributes
         *
         * @return \Illuminate\Support\HtmlString
         */
        public function select(
            $name,
            $list = [],
            $selected = null,
            array $selectAttributes = [],
            array $optionsAttributes = [],
            array $optgroupsAttributes = []
        ) {
            $this->type = 'select';
        
            // When building a select box the "value" attribute is really the selected one
            // so we will use that when checking the model or session for a value which
            // should provide a convenient method of re-populating the forms on post.
            $selected = $this->getValueAttribute($name, $selected);
        
            $selectAttributes['id'] = $this->getIdAttribute($name, $selectAttributes);
        
            if (! isset($selectAttributes['name'])) {
                $selectAttributes['name'] = $name;
            }
        
            // We will simply loop through the options and build an HTML value for each of
            // them until we have an array of HTML declarations. Then we will join them
            // all together into one single HTML element that can be put on the form.
            $html = [];
        
            if (isset($selectAttributes['placeholder'])) {
                $html[] = $this->placeholderOption($selectAttributes['placeholder'], $selected);
                unset($selectAttributes['placeholder']);
            }
        
            foreach ($list as $value => $display) {
                $optionAttributes = $optionsAttributes[$value] ?? [];
                $optgroupAttributes = $optgroupsAttributes[$value] ?? [];
                $html[] = $this->getSelectOption($display, $value, $selected, $optionAttributes, $optgroupAttributes);
            }
        
            // Once we have all of this HTML, we can join this into a single element after
            // formatting the attributes into an HTML "attributes" string, then we will
            // build out a final select statement, which will contain all the values.
            $selectAttributes = $this->html->attributes($selectAttributes);
        
            $list = implode('', $html);
        
            return $this->toHtmlString("<select{$selectAttributes}>{$list}</select>");
        }
        ```

- 引数は下記の様に指定されている模様（第五・第六引数まで設定はあるがよく使いそうな第四引数までをまとめる。）

    |  | 型 | 内容 | 備考 |
    | --- | --- | --- | --- |
    |第一引数| string | htmlのselect要素のnameの値 | 必須 |
    |第二引数| array | htmlのプルダウンを構成するoption要素の値<br>連想配列でoptionのvalueと表示名を指定 | デフォルト値は空配列 |
    |第三引数| string\|bool | デフォルト値の設定<br>第二引数の連想配列のキー名で指定 | デフォルトはnull |
    |第四引数| array | プレースホルダの設定<br>連想配列で`['placeholder' => '表示内容']`の様に指定 | デフォルトは空配列 |

# 参考文献

https://laravelcollective.com/docs/6.x/html