[Laravel6] 簡易的な機能を作ってCRUDの全容を掴む

## 作るもの
- お問い合わせフォーム
- REST（CRUD機能の作成）

## 作成の流れ
- Model → Controller → Route → View

## Read & Create
- Model
    1. まずDBのテーブル及びカラム作成から行っていく
        
        　 -  `php artisan make:model Models/〇〇 (-mc)` -mcとつけることで、マイグレーションとコントローラーファイルも用意してくれる
        
        - 実際のマイグレーションファイルの記述は以下のようになる
        
        ```php
        public function up()
            {
                Schema::create('contact_forms', function (Blueprint $table) {
                    $table->bigIncrements('id');
                    //氏名、メールアドレス、url、性別、年齢、お問い合わせ内容
                    //unsigned -> 符号(+,-)がない
                    $table->string('your_name', 20);
                    $table->string('email', 255);
                    $table->longText('url')->nullable($value = true);
                    $table->boolean('gender')->unsigned();
                    $table->tinyInteger('age');
                    $table->string('contact', 200);
                    $table->timestamps();
                });
            }
        ```
        
    - `php artisan migrate` これを行うことで、マイグレーションファイルが起動し、実際にDBにテーブルが作成される。
    - Schema::create関数は、引数1に作成するテーブル名、引数2にカラムの作成手順を指定している
    - unsignedは、+,-の符号のうち、-を認めない機能。RDBで繋げるときに、この設定が違い違いになっていたらエラーが出るので、明示しておく。
    
- Controller
    - RESTfulなコントローラーを作成する
    - `php artisan make:controller 〇〇 —resource` と入力することで、CRUD機能の土台を既に持っている、〇〇というControllerを作成することができる
- View
    - リンク先にはRouteと同じ書き方が使える
    - laravelのformには@csrfが必須
    
    ```php
    <form method="GET" action="{{ route('contact.create') }}">
    @csrf
                <button type="submit" class="btn btn-primary">
                  新規登録
                </button>
              </form>
    ```
    
- Route
    - prefixは共通のフォルダ名、middlewareはAuth::routes();の認証機能を読み込んでる。
    
    ```php
    Auth::routes();
    
    Route::group(['prefix' => 'contact', 'middleware' => 'auth'], function () {
        Route::get('index', 'ContactFormController@index')->name('contact.index');
        Route::get('create', 'ContactFormController@create')->name('contact.create');
    });
    ```
    

> DBに投稿内容を保存
> 
- storeで書いていく

> DBの投稿内容を表示
> 

> 投稿の詳細
> 

### Route

```php
Route::get('show/{id}', 'ContactFormController@show')
->name('contact.show');
```

- `'show/{id}'` と書くことで、各投稿に紐づけられたIDを参照し、その詳細な投稿内容を引っ張り出してくることが可能

### Controller

```php
public function show($id)
    {
        $contact = ContactForm::find($id);

if($contact->gender === 0){
            $gender = '男性';
        }

if ($contact->age === 1) {
            $age = '10代';
        }

        return view('contact.show', compact('contact','gender','age'));
    }
```

- findは一つのデータを持ってくるイメージ
    - だから変数名も単数系
- returnで渡しているデータ（compact）は、書き方の特徴として[$]が不要
    - それに複数の値を渡すことができる
- DBでint他で管理しているものは、そのcontroller内で加工処理をしてあげる
    - 今回はintで管理しているものに、新しい変数を設定して、それをcompactでまとめてViewに送っている

### View

```php
{{ $contact->your_name}}
          {{ $gender}}
          {{ $age}}
```

- Viewで表示するときは[$]が必要

### 別のViewから飛んでくる

```php
<td><a href=
"{{route('contact.show', ['id' => $contact->id])}}">
詳細を見る</a>
```

- ルートでパラメータを定義している場合は、route関数の第2引数としてパラメータを渡す。指定されたパラメータは自動的にURLの正しい場所へ埋め込まれる
    - 今回であれば、contact.showというrouteで定義した名前だけではなく、パラメータのidも定義してあげている
        - $contact→idはもちろんこのビューにもcontrollerからデータを飛ばしていることが前提にある

## Edit画面

### Route

```php
Route::get('edit/{id}', 'ContactFormController@edit')->
name('contact.edit');
```

- showで投稿の詳細画面を作成したが、イメージとしてはそれと同じ。
- 各投稿の詳細を持ってくるためにパラメーターにidを指定して、その投稿を表示させる

### Controller

```php
public function edit($id)
    {
        //
        $contact = ContactForm::find($id);

        return view('contact.edit', compact('contact'));
    }
```

- DBから投稿データを(idを基に)引っ張ってきて、Viewに投稿データを渡している

### View

```php
//createとほぼ同じ
//変更点は、各入力欄に初期値として投稿データを渡している
<input type="text" name="title" value="{{$contact->title}}">

//gender,ageのように数値で管理しているものの記述は少し違う

<input type="radio" name="gender" value="0"
 @if($contact->gender === 0 ) checked @endif >
男性
</input>

<input type="radio" name="gender" value="1" 
@if($contact->gender === 1 ) checked @endif>
女性
</input>
```

- もちろんformで囲っているので、こっからDBに登録されているデータを更新する処理を書いていく必要がある
- intで管理しているチェックボックス系は、引っ張ってきたデータがその数値と一致していたら、checked(selected)にする、というif文で対応する

## Update 

### Route

```php
Route::post('update/{id}', 'ContactFormController@update')
->name('contact.update');
```

### Controller

```php
public function update(Request $request, $id)
    {
        //
        $contact = ContactForm::find($id);

        $contact->your_name = $request->input('your_name');
        $contact->title = $request->input('title');
        $contact->email = $request->input('email');
        $contact->url = $request->input('url');
        $contact->gender = $request->input('gender');
        $contact->age = $request->input('age');
        $contact->contact = $request->input('contact');

        $contact->save();

        return redirect('contact/index');
    }
```

- データの登録という面ではstoreと同じなので、型はstoreを流用
- storeと違う部分
    - 現在のデータを持ってくる（新しくインスタンスを作成することはしない）

### View

```php
Editです！
<form method="POST" 
action="{{route('contact.update', ['id' => $contact->id])}}">
```

- action先にcontrollerのupdateメソッドを指定している
- 各投稿の情報を基にデータの更新作業をしているので、idの指定は忘れない

## Destroy

### Route

```php
Route::post('destroy/{id}', 'ContactFormController@destroy')
->name('contact.destroy');
```

- その投稿を削除するので、show,editと同じ

### Controller

```php
public function destroy($id)
    {
        $contact = ContactForm::find($id);
        $contact->delete();

        return redirect('contact/index');
    }
```

- データを一つ引っ張ってきて、deleteするだけ

### View

```php
<form method="POST" action="{{route('contact.destroy', ['id' => $contact->id])}}" id="delete_{{$contact->id}}">
          @csrf
          <a href="#" class="btn btn-danger" data-id="{{$contact->id}}" onclick="deletePost(this);" type="submit">削除する</a>
          </form>
        </div>
      </div>
    </div>
  </div>
</div>
<script>
function deletePost(e){
  'use strict';
  if (confirm('本当に削除していいですか？')){
    document.getElementById('delete_' + e.dataset.id).submit();
  }
}
</script>
@endsection
```

- show.bladeのなかにformを二つ作っている
- ごちゃごちゃしているのは、削除ボタンを押したときに「本当に削除しますか？」という表示を挟んでいるから