【Laravel初心者】投稿編集機能の実装

Laravel初学者です。
オリジナルアプリを作成しているのでその過程を記事にしています。

理解が曖昧なところも多いため、ご指摘等ありましたらご連絡いただければ幸いです。

今回は投稿の編集機能の実装について備忘録のため記録として残します。
関連記事：
[【Laravel初心者】一覧表示の実装](https://qiita.com/mumucochimu/items/b0221657a3981f4a4f49)
[【Laravel初心者】投稿保存の実装]
(https://qiita.com/mumucochimu/items/12bd2d46b73891e737e2)


## 環境

|                | Version     |
|:---------------|------------:|
| PHP            | 7.4.14      |
| Laravel        | 8.24.0      |
| mysql          | 8.0.23      |
| docker         | 20.10.2     |
| docker-compose | 1.27.4      |


## ルーティング

```PHP:routes/web.php
Route::resource('/game', App\Http\Controllers\GameController::class)->only(['create','store','edit','update']);
```

`resource`で`edit`と`update`を追加します。

`edit`と`update`の役割としては

- edit→編集画面の生成とupdateへデータを送信する役割
- update→データを受け取り上書きする役割

です。

## コントローラー

```PHP:app/Http/Controllers/GameController.php
/**
* Show the form for editing the specified resource.
*
* @param  int  $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
  $game = Game::find($id);
  return view('game.edit', compact('game'));
}
```

まずは`edit`です。
idからどの編集をするかを判断するために`$game = Game::find($id);`として代入しています。
そして`return view('game.edit', compact('game'));`でビューを返しています。
この時`compact`で指定してあげないと変数をビューに渡すことができません。


```PHP:app/Http/Controllers/GameController.php
/**
* Update the specified resource in storage.
*
* @param  \Illuminate\Http\Request  $request
* @param  int  $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
$game = Game::find($id);
$game->user_id = Auth::id();
$game->name = $request->input('name');
$game->describe = $request->input('describe');
$game->play_time = $request->input('play_time');
$game->players_minimum = $request->input('players_minimum');
$game->players_max = $request->input('players_max');

$image = $request->file('image');
$path = Storage::disk('s3')->putFile('bgama32070', $image, 'public');
$game->image_path = Storage::disk('s3')->url($path);
        
$game->save();

return redirect('/')->with('success', '更新しました');
}
```

次に`update`です。
`store`の記述とほぼ同じですが一つ違うのが`$game = Game::find($id);`です。

- store→`$game = new Game();`
- update→`$game = Game::find($id);`

上記のように、storeは`new`で生成して`$game`に代入していますが
updateはidから取ってきたものを代入しています。


## ビュー

```PHP:resources/views/game/edit.blade.php
<div class="container mt-4">
  <div class="border p-4">
    <h1 class="h4 mb-4 font-weight-bold">編集</h1>

    <form action="{{ route('game.update', $game->id) }}" enctype="multipart/form-data" method="POST" id="new">
      @csrf
      @method('PUT')

      <fieldset class="mb-4">

        <div class="form-group">
          <label for="subject">
            ボードゲーム名
          </label>
          <input
            id="name"
            type="text"
            name="name"
            value="{{old('name')?: $game->name}}"
            class="form-control"
          >
        </div>

        <div class="form-group">
          <label for="subject">
            商品説明
          </label>
          <textarea
            id="new"
            name="describe"
            class="form-control"
            rows="8"
          >{{old('describe')?: $game->describe}}
          </textarea>
        </div>

        <div class="form-group">
          <label for="subject">
            プレイ時間
          </label>
          <input
            type="number"
            name="play_time"
            value="{{old('play_time')?: $game->play_time}}"
            class="form-control"
          >
        </div>

        <div class="form-group">
          <label for="subject">
            最小プレイ人数
          </label>
          <input
            type="number"
            name="players_minimum"
            value="{{old('players_minimum')?: $game->players_minimum}}"
            class="form-control"
          >
        </div>

        <div class="form-group">
          <label for="subject">
            最大プレイ人数
          </label>
          <input
            type="text"
            name="players_max"
            value="{{old('players_max')?: $game->players_max}}"
            class="form-control"
          >
        </div>

        <div class="form-group">
          <label for="exampleInputFile">
            商品画像
          </label>
          <input
            id="image"
            type='file'
            name="image"
            accept="image/png, image/jpeg"
            class="form-control-file"
          >
        </div>

        <button type="submit" class="btn btn-primary">
          編集する
        </button>
  
      </fieldset>
    </form>
  </div>
</div>
```

こちらも`create`の画面とほぼ変わらないです。
違うのは

```PHP:
<form action="{{ route('game.update', $game->id) }}" enctype="multipart/form-data" method="POST" id="new">
```

上記のように`action`で`{{ route('game.update', $game->id) }}`としてupdateに送信するようにしているところと

```PHP:
@method('PUT')
```

上記のように擬似フォームメソッドを指定しているところです。

参考記事：[【Laravel】掲示板を作成する（5）投稿編集機能、投稿の物理削除](https://nodoame.net/archives/11628)

>擬似フォームメソッドは『HTTPメソッドに意味をもたせて機能性を分ける』というのがRESTという概念で、Laravelの場合、ルーティングはURLとHTTPメソッドの組に対して定義されますので、使い分けないとリクエストが正しく処理されません

とのことです。
`PUT`で`更新データです`という感じで渡すために必要みたいですね。
ありがとうございます。


編集機能は以上です。