Laravel コントローラのstoreアクション使い方

# store（ストア）アクション

### store(ストア）とは何か？

`保存する`という意味になります

次のような新規投稿画面の場合
情報を入力した後は送信のボタンを押しますが
その送信先はsotreアクションにする必要があります



![スクリーンショット 2022-08-23 22.47.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/a87161a0-642a-b5ce-8482-cbf39b2fe422.png)

### storeアクションの役割とは？

フォームで送信された情報は最終的にデータベースへ登録され
結果、WEB画面に反映される仕組みですが、
どのテーブル、どの列（カラム）に登録されるかなどの割り当て指示は
storeアクションで行います。

## storeアクションに必要な工程

storeアクションで必要な工程は次になります

1. 保存するデータベースの`テーブル`と`列`を指定する 

1. saveメソッドでレコードを保存する
1. 新しいURLを検索しなおす
 


``` php
public function store(Request $request)
{
  // モデルからインスタンスを生成
  $sample = new Sample;
  //任意の変数名 = new 連携するデータベースのモデル名;
  //変数名はモデル名に関連させることが推奨されます
  // $requestに新規投稿ページのformタグからのデータが
  // 格納されているので、以下のようにそれぞれ代入する
  $sample->title = $request->title;
  $sample->body = $request->body;
  //　DBの中にあるテーブルに対し、フォームから受け取った値を代入するイメージ
  // 保存
  $article->save();
  // 保存後 一覧ページへリダイレクト
  return redirect('/sample');
  // 一覧ページのURLを入力する
}
```
新規投稿画面などで送信されたデータを
保存する処理がstoreの役割となります

## Laravelでの419エラーについて

### CSRF(クロスサイトリクエストフォージェリ) による被害

過去に`CSRF`というWEBシステムを悪用したサイバー攻撃が流行しました。

本物の会員制WEBサイト（アマゾン、楽天など）に`ログインした状態`で
インターネットサーフィンを行い`悪意のあるWEBサイトを閲覧`したとします
すると、悪意のあるWEBサイトが用意した`ボタンやリンクを押す`ことで
ログイン中の会員制WEBサイトに`退会、送金、購入`などの操作指示が
勝手に送信されてしまいます。

`悪意のあるWEBサイト`から送信された情報を
本物のWEBサイトは偽の情報と判断ができないため
`退会、送金、購入`などの操作を実行してしまいます。

### formタグを利用時にはCSRF対策を講じなければならない

Laravelでは、とあるバージョンから`CSRF対策`というものが付与されており
HTMLのformタグ内の情報をただ単に送信しようとしても
`formにCSRF対策の記述をしていなければ`
以下の画像のようなエラーを起こします

![スクリーンショット 2022-08-24 11.03.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/22bf0cc2-1a7f-4a2a-5721-f74ed1601ae9.png)

### 419エラーを回避するには

HTMLのformタグに以下のどちらかの記述をするだけです
- {{csrf_field()}}
- @csrf

どちらを利用しても問題はございません
違いとしては利用できるバージョンにあります
- {{csrf_field()}}　laravel5.4〜
- @csrf laravel 7.x〜

### CSRF対策すると何が起きるのか

多段階認証をすることができます。
まずはHTMLに記述した`{{csrf_field()}}`が
ワンタイムトークンを発行するため、
その後の操作でフォームの内容とワンタイムトークンを送信します

本物のWEBサイトでは、ユーザーのログイン操作時に保存しているトークンと
送信されたトークンが一致するか確認を行い、
一致しない場合は不正なリクエストとして扱います。



## &lt;form>タグの書き方

#### 記述する&lt;form>タグの属性

formタグは属性を付与することで、ボタンを押したときに
`特定のURL`を開く設定をすることができます

```php
<form action="/crud" method="post">
   //重要：次の1行を記述しないとstoreアクションにルーティングされずエラーになる
      {{ csrf_field() }}
    
  <div>
           <label for="inputName">価格</label>
           <input type="text" class="form-control" id="inputName" placeholder="価格">
  </div>

  <div>
    <input type="submit" value="送信">
  </div>

</form>
```

#### csrf_field() が必要な理由

上述の通り記述しなければ`エラーが発生する`ほど重要なコードになります。


#### action
- &lt;form>タグにおける`action属性は送信先（URL)を指定する`ためのものです。
- 送信先が未入力では、送信ボタンを押しても何も起こりません

#### method

- どのようにデータを送信するかを定義します（GET,POST)
- デフォルトではすでにGETが定義されています

#### GET
- ユーザーのブラウザから先方のサーバー（見たいサイト）に対して
「ブラウザに表示するhtmlをください」と要求をするという意味

- ボタンを押すことで`指定URLページを開くことを要求する`
    もしくは`特定のデータを削除`などの処理を実行する際に定義する

#### POST
- ブラウザの&lt;form>に入力された情報を特定のURLへ送ります
- 今回の目的として、storeアクションへ情報を送る必要があるので
    methodはPOSTにする必要があります

## &lt;label>タグと&lt;input>タグの書き方

```php
<form action="/crud" method="post">
   //重要：次の1行を記述しないとstoreアクションにルーティングされずエラーになる
      {{ csrf_field() }}
    
  <div>
           <label for="inputName">価格</label>
           <input type="text" name="price" placeholder="価格">
  </div>

  <div>
    <input type="submit" value="送信">
  </div>

</form>
```

#### &lt;label>
- &lt;label>はfor &lt;input> のname属性と同じ名前を付けることにより各々に関連付けがされます
- labelは関連付けを行うことにより、ブラウザでラベルをクリックした際に
  その構成部品（今回はinput)をクリックしたのと同じ動作が可能になります。

#### placeholder
- フォームなどの入力欄にあらかじめ記入されている薄い灰色のテキストのことです

#### name
- 	入力欄コントロールの名前。名前/値の組の部分としてフォームと一緒に送信されます
- 	送信先のstoreアクションにて挿入先の列の指定に名前を使います
- 	データベースとの連携に利用する重要な属性のため、名前は挿入先の列名にすることが推奨されます

※storeアクションの見本
``` php
public function store(Request $request)
  // $requestにformからのデータが格納されているので、以下のようにそれぞれ代入する
{
  // モデルからインスタンスを生成
  //　コントローラの記述始めにモデルへのパスが記述されているため
  // モデル名を拡張子なしで記述すれば参照できる 
  $sample = new Sample;
  //任意の変数名 = new 連携するデータベースのモデル名;
  //変数名はモデル名に似せることが推奨されます
  // $requestに新規投稿ページのformタグからのデータが
  // 格納されているので、以下のようにそれぞれ代入する
  $sample->price = $request->price;
    //$sample->price データベースのテーブル
    //$request->price; フォームから送信されたデータ
    //　DBの中にあるテーブルに対し、フォームから受け取った値を代入するイメージ
  // 保存
  $article->save();
  // 保存後 一覧ページへリダイレクト
  return redirect('/sample');
  // 一覧ページのURLを入力する
}
```

#### type="submit"

- `input`を送信するためのボタンに変更します
- &lt;form>で囲まれたブロックの値を送信することができます
- 今回の目的では、storeアクションに値を送ることができます