Laravelで簡単なメモアプリを作る（2）~データの取得と保存~

# はじめに
[Laravel](http://laravel.jp/)とは、Webに特化したPHPフレームワーク。セキュリティ対策(CSRF対策など)もこれでできます。MVCアーキテクチャを採用しています。今回は、データベースの接続とデータの取得と保存をしていきたいと思います。

[Laravelで簡単なメモアプリを作る（1）~Viewの作成と表示~](https://qiita.com/Alesion30/items/95222f62904ef46f6f45)
[Laravelで簡単なメモアプリを作る（3）~データの更新と削除~](https://qiita.com/Alesion30/items/11a9e17368b922e67a5c)

# 今回の目標物
<img width="723" alt="スクリーンショット 2019-12-31 11.25.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519787/677f6e21-1da3-ad96-4ac5-116fb6e8c391.png">

<img width="703" alt="スクリーンショット 2019-12-31 11.25.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519787/88b43946-ed4d-5ab1-56c6-d95b4d8f011b.png">

# データ取得の流れ
<img width="987" alt="スクリーンショット 2020-01-01 19.00.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519787/cd501133-f70c-44ef-f10d-e2c1059be62a.png">

<img width="1000" alt="スクリーンショット 2020-01-01 19.00.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519787/81f5dbab-9df9-e2c5-9abf-af6d2b4ce5dc.png">

<img width="948" alt="スクリーンショット 2020-01-01 19.00.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519787/b732fe23-516a-aa71-5412-5182da490cbe.png">

# データベースの作成

### データベースの作成
phpMyAdminを開く。Newを押して、新しくdatabaseを作成する。今回は、memoAppという名前のデータベースを作成する。

<img width="699" alt="スクリーンショット 2020-01-01 19.05.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519787/4250eb2f-748f-c69c-1b16-7adf0c14c60e.png">

### データベースの接続
.envに、データベースの情報を記述する。DB_DATABESEには、データベースの名前を入れる。MAMPを使っている人は、デフォルトでユーザー名、パスワード共に**root**なので特に設定していなければ、下の内容をそのままコピー＆ペーストして良い。

```
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=memoApp
DB_USERNAME=root
DB_PASSWORD=root
```

### モデルの作成
ターミナルまたは、PowerShellを開き、cdコマンドでmemoAppまで移動し、下のコマンドを打ち込む。

```
$ php artisan make:model Memo
```

先ほど作成したモデルにDBのテーブル情報を記述する。

```app/Memo.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Memo extends Model
{
    // table名を指定
    protected $table = 'memo';

    // カラムを指定
    protected $fillable = [
        'id', 'title', 'content'
    ];

    // created_atを使わない場合はfalseを指定する。
    public $timestamps = false;
}
```

### テーブルの作成
#### マイグレーションファイルの作成
ターミナルまたはpowerShellを開いて、cdコマンドでmemoAppまで移動し、下のコマンドを打つ。

```
$ php artisan make:migration create_memo_table
```

先ほど、生成したファイルにカラムの情報を記述する。

`id : bigInt型`
`title : string型 24桁`
`content: string型 60桁`

```database/migrations/2019_12_12_114638_create_memo_table.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateMemoTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('memo', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('title', 24);
            $table->string('content', 60);
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('memo');
    }
}
```

#### seederの作成
ターミナルまたはpowerShellを開いて、cdコマンドでmemoAppまで移動し、下のコマンドを打つ。

```
$ php artisan make:seeder MemoTableSeeder
```

```database/seeds/MemoTableSeeder.php
<?php

use Illuminate\Database\Seeder;

use App\Memo;

class MemoTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        DB::table('memo')->delete(); //最初に全件削除

        Memo::create([
            'title' => '12/13 laravel勉強会', 'content' => 'データの読み取りと追加をやりました。'
        ]);

        Memo::create([
            'title' => '12/6 laravel勉強会', 'content' => 'Viewの表示をしました。'
        ]);
    }
}
```

```database/seeds/DatabaseSeeder.php
<?php

use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        Model::unguard();

        $this->call('MemoTableSeeder');

        Model::reguard();
    }
}
```

#### マイグレーションとSeederの反映
phpMyAdminにマイグレーションとSeederを反映させる。ターミナルまたはpowerShellを開いて、cdコマンドでmemoAppまで移動し、下のコマンドを打つ。

```
$ php artisan migrate --seed
```

phpMyAdminを開いて、反映されているかどうか確認する。

ちなみに、エクセル形式で表すとこんな感じになる。

<img width="367" alt="スクリーンショット 2020-01-01 19.26.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519787/f390e7c1-6f1b-e82c-9e14-f9d547360cb4.png">

# データの取得

### データをViewに渡す
app/Http/Controllers/MemoController.phpに、データをViewに渡すメソッドを記述する。

```app/Http/Controllers/MemoController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Memo;

class MemoController extends Controller
{
    public function showHome()
    {
        $memos = Memo::get();
        return view("home", ['memos' => $memos]);
    }

    public function showSubmit()
    {
        return view("submit");
    }
}
```

とりあえずresources/views/home.blade.phpの適当なところに`<div>{{$memos}}</div>`を入れて、表示を確認してみよう。

$memosの中身が、id,title,contentの要素を持つオブジェクトの配列になっていることがわかる。

<img width="969" alt="スクリーンショット 2020-01-03 15.34.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519787/694801c9-bab8-d83b-d048-41fb4d93edd1.png">

resources/views/home.blade.phpの適当なところに以下のコードを追加してみる。

```html
<div>{{$memos[0]->id}}</div>
<div>{{$memos[0]->title}}</div>
<div>{{$memos[0]->content}}</div>
```

ループを使わずにこんな感じで表示してみよう。

<img width="545" alt="スクリーンショット 2020-01-03 15.41.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519787/6eb49094-cd20-b2a4-d943-ca48b8877e75.png">

```html:home.blade.php
<tbody>
  <tr>
    <td class="left">{{$memos[0]->title}}</td>
    <td><a href="{{ route('submit')}}">編集</a></td>
    <td><a>削除</a></td>
  </tr>
  <tr>
    <td class="left">{{$memos[1]->title}}</td>
    <td><a href="{{ route('submit')}}">編集</a></td>
    <td><a>削除</a></td>
  </tr>
</tbody>
```

これをループを用いて、記述するとこんな感じになる。

```html:resources/views/home.blade.php
<tbody>
   @foreach ($memos as $memo)
     <tr>
       <td class="left">{{$memo->title}}</td>
       <td><a href="{{ route('submit')}}">編集</a></td>
       <td><a>削除</a></td>
     </tr>
   @endforeach
</tbody>
```

bladeファイルはhtmlファイルと違って、@を使うことで直接、条件分岐やループ文を記述することができる。中括弧で囲む必要がないが`@endif`や`@endfor`などで閉じてやる必要がある。

### 詳細画面にもデータを渡す
URLからメモのidを受け取れるようにする。URLを`‘/submit/{id?}’`にすることで、idという変数をコントローラに渡すことができる。

```routes/web.php
<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('sample');
});

Route::get('/home', 'MemoController@showHome')->name('home');

Route::get('/submit/{id?}', 'MemoController@showSubmit')->name('submit');
```

リンクを押すと、URLにidを含んだページに飛べるようにする。`href="{{ route('submit', ['id' => $memo->id])}}"`とすることで、URLにidを渡すことができる。

```html:resources/views/home.blade.php
@extends('layouts.app')

@section('css')
<style>
    header {
        height: 50px;
        background-color: #000;
        color: white;
        padding-left: 20px;
        font-size: large;
        color: #ddd;
    }

    .title {
        position: absolute;
        top: 10px;
    }

    .card {
        margin-top: 40px;
    }

    .left {
        width: 70%;
    }

    .submit {
        position: absolute;
        top: 10px;
        right: 20px;
    }
</style>
@endsection

@section('content')
<div class="card" style="width: 100%;">
    <div class="card-header">
        メモ一覧
        <a href="{{ route('submit')}}" class="submit">メモを追加</a>
    </div>

    <table class="table">
        <tbody>
            @foreach ($memos as $memo)
            <tr>
                <td class="left">{{$memo->title}}</td>
                <td><a href="{{ route('submit', ['id' => $memo->id])}}">編集</a></td>
                <td><a>削除</a></td>
            </tr>
            @endforeach
        </tbody>
    </table>
</div>
@endsection
```

コントローラーの関数の引数に、URLの変数を渡せる。

```app/Http/Controllers/MemoController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Memo;

class MemoController extends Controller
{
    public function showHome()
    {
        $memos = Memo::get();
        return view("home", ['memos' => $memos]);
    }

    public function showSubmit($id = 0)
    {
        if ($id != 0) {
            $memo = Memo::where('id', $id)->get()->first();
        } else {
            $memo = (object) ["id" => 0, "title" => "", "content" => ""];
        }
        return view("submit", ['memo' => $memo]);
    }
}
```

コントローラから送られてきたデータを、Viewに埋め込む。

```html:resources/views/submit.blade.php
@extends('layouts.app')

@section('css')
<style>
    header {
        height: 50px;
        background-color: #000;
        padding-left: 20px;
        font-size: large;
        color: #ddd;
    }

    .title {
        position: absolute;
        top: 10px;
    }

    .container {
        margin-top: 40px;
    }
</style>
@endsection

@section('content')
<form>
    <div class="form-group">
        <label for="title">タイトル</label>
        <input type="text" class="form-control" id="title" name="title" value="{{$memo->title}}">
    </div>
    <div class="form-group">
        <label for="content">内容</label>
        <input type="text" class="form-control" id="content" name="content" value="{{$memo->content}}">
    </div>
    <a href="{{ route('home')}}" class="btn btn-primary">戻る</a>
    <button type="submit" class="btn btn-success">追加</button>
</form>
@endsection
```

# データの保存

postを使って、データをコントローラに送る。

```html:resources/views/submit.blade.php
@extends('layouts.app')

@section('css')
<style>
    header {
        height: 50px;
        background-color: #000;
        padding-left: 20px;
        font-size: large;
        color: #ddd;
    }

    .title {
        position: absolute;
        top: 10px;
    }

    .container {
        margin-top: 40px;
    }
</style>
@endsection

@section('content')
<form method="POST" action="{{ route('submit', ['id' => $memo->id])}}">
    @csrf
    <div class="form-group">
        <label for="title">タイトル</label>
        <input type="text" class="form-control" id="title" name="title" value="{{$memo->title}}">
    </div>
    <div class="form-group">
        <label for="content">内容</label>
        <input type="text" class="form-control" id="content" name="content" value="{{$memo->content}}">
    </div>
    <a href="{{ route('home')}}" class="btn btn-primary">戻る</a>
    <button type="submit" class="btn btn-success">追加</button>
</form>
@endsection
```

MemoControllerに、Viewから送られてきたデータをデータベースに保存するメソッドを記述する。

```app/Http/Controllers/MemoController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Memo;

class MemoController extends Controller
{
    public function showHome()
    {
        $memos = Memo::get();
        return view("home", ['memos' => $memos]);
    }

    public function showSubmit($id = 0)
    {
        if ($id != 0) {
            $memo = Memo::where('id', $id)->get()->first();
        } else {
            $memo = (object) ["id" => 0, "title" => "", "content" => ""];
        }
        return view("submit", ['memo' => $memo]);
    }

    public function postSubmit(Request $request, $id = 0)
    {
        $title = $request->input('title');
        $content = $request->input('content');
        if ($id == 0) {
            Memo::create([
                'title' => $title,
                'content' => $content
            ]);
        }
        return redirect()->route('home');
    }
}
```

web.phpに以下の内容を記述する。

```routes/web.php
<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('sample');
});

Route::get('/home', 'MemoController@showHome')->name('home');

Route::get('/submit/{id?}', 'MemoController@showSubmit')->name('submit');

Route::post('/submit/{id?}', 'MemoController@postSubmit')->name('submit');
```

今回はここまで。次回は、データの編集と削除をしたいと思います。