laravel5.7 掲示板作成 チュートリアル

アドベントカレンダーLaraveｌを初めて書かせていただきました。
こちらは、昔書いたものを復刻したものです。

windowsの方はこちら
[windows Laravel環境構築 \- Qiita](https://qiita.com/yoshinyan/items/3161ed3eb8ea0e6ba14e)


macの方はこちら
[mac Laravel環境構築 \- Qiita](https://qiita.com/yoshinyan/items/38bc4e4a02a66acead91)

---

### 最低限の設定



```php:\config\app.php
'timezone' => 'Asia/Tokyo',
'locale' => 'ja',
```



---

### Controllerを作る

```bash
php artisan make:controller HelloController
```

ここを見てみましょう




できたファイルを編集してみましょう

```php:\app\Http\Controllers\HelloController.php
    public function index()
    {
        $msg = 'hello';
            return view('hello.index', ['msg' => $msg]);
    }
```

---

### ルーティングを設定する



```php:\routes\web.php
Route::get('/hello', 'HelloController@index');
```

### bladeを作成する



```html:\resources\views\hello\index.blade.php
{{$msg}}
```
次のURLを確認してみましょう
http://localhost:8000/hello

---

### @foreachを使う



```php:\app\Http\Controllers\HelloController.php
    public function index()
    {
        $msgs = [
            'hello',
            'こんにちは',
            '尓好'
        ];
            return view('hello.index', ['msgs' => $msgs]);
    }
```

---

### bladeの中でforeachを使う



```php:\resources\views\hello\index.blade.php
@foreach($msgs as $msg)
{{$msg}}<br>
@endforeach

```
Bladeを使わないとこんな書き方です

参考サイト
flatFlag
endforeachの書き方でHTML埋め込みもスッキリ！
https://www.flatflag.nir87.com/foreach-294#endforeachHTML


---

#### ほかはこういうのもあります

```php
@if(bool)
    // code
@endif

次とイコール

<?php if(boo) : ?>
    // code 
<?php endif; ?>
```

```php
@php
// code
@endphp

次とイコール

<?php
// code
?>

```

他にはこんなものもあります

参考サイト
Laravel 5.7 Bladeテンプレート
https://readouble.com/laravel/5.7/ja/blade.html#introduction

---

#### DB作成

マイグレーションファイルを作成
DBの移行を簡単にするファイル。
ここでは、DBを作成するために使う。


```bash
php artisan make:migration create_article_table
```

---

#### マイグレーションファイルを編集



```php:\database\migrations\2018_08_10_183909_create_article_table.php

<?php

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

class CreateArticleTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id');
            $table->string('title');
            $table->string('body');
            $table->timestamps();
        });
    }

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

---

#### マイグレーション実行

```bash
php artisan migrate
```

DBが作られているかDB Browser for SQLiteで確認する

macは

```bash
mysql> show column from article;
```

---

#### サンプルデータを作る

seederファイルを作成。
サンプルデータを作れる。

```php
php artisan make:seeder ArticleSeeder
```



---



```php:\database\seeds\ArticleSeeder.php

<?php

use Illuminate\Database\Seeder;

class ArticleSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        // テーブル内のデータを一旦全削除
        \Illuminate\Support\Facades\DB::table('article')->truncate();

        // データのインサート
        DB::table('articles')->insert([
            [
                'user_id' => 2,
                'title' => 'title1',
                'body' => 'body1',
                'created_at' => '2018-06-10 21:07:31',
                'updated_at' => '2018-06-10 21:07:31'
            ],
            [
                'user_id' => 2,
                'title' => 'title2',
                'body' => 'body2',
                'created_at' => '2018-06-10 21:07:31',
                'updated_at' => '2018-06-10 21:07:31'
            ],
            [
                'user_id' => 2,
                'title' => 'title3',
                'body' => 'body3',
                'created_at' => '2018-06-10 21:07:31',
                'updated_at' => '2018-06-10 21:07:31'
            ]
        ]);
    }
}
```

---

#### seederを登録する



```php:\database\seeds\DatabaseSeeder.php
<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call([
            ArticleSeeder::class,
        ]);
    }
}
```


seederを実行

```bash
php artisan db:seed
```

データができているか見てみましょう。

mac

```bash
select * from article;
```

---

モデルを作成

```bash
$ php artisan make:model Article
```

---

### Controllerを作る

```bash
php artisan make:controller ArticleController
```



```php:\app\Http\Controllers\ArticleController.php

// モデルを追加
use App\Article;


    public function index()
    {
            // データベースから全データを取得
            $article = Article::all();
            // viewにデータを渡す
            return view('article.index', ['articles' => $article]);
    }
```

---

### ルーティングを設定する



```php:\routes\web.php
Route::get('/article', 'ArticleController@index');
```

---

### bladeを作成する

次の場所にファイルを作成
\resources\views\article\index.blade.php


---

一旦ここでDBからデータが取れるか確認



```php:\resources\views\article\index.blade.php
@foreach($articles as $article)
    {{$article->title}}
    {{$article->body}}
@endforeach
```

http://localhost:8000/article

---

errorになる場合

ヒント
DB設定を見直す

serverを一旦ストップ、再起動

キャッシュをクリアしてみる

```bash
$ php artisan config:clear
$ php artisan cache:clear
```

#### データを作成するメソッドを追加



```php:\app\Http\Controllers\ArticleController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Article;
use Validator;

class ArticleController extends Controller
{
    public function index()
    {
        $articles = Article::orderBy('id', 'desc')->get();
        return view('article.index', ['articles' => $articles]);
    }
    
    public function add (Request $request)
    {
        // 保存の処理
        $article = new Article;
        $article->user_id = 1; // 今回は1固定       
        $article->title = $request->input('title');
        $article->body = $request->input('body');
        $article->save();
   
        return redirect()->to('/article');
    }
```



```php:\routes\web.php
Route::post('/article/add', 'ArticleController@add');
```
---

#### bladeを作成

多いのでコピペしましょう。



```html:\resources\views\layouts\common.blade.php
<html>
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/css/bootstrap.min.css" integrity="sha384-Smlep5jCw/wG7hdkwQ/Z5nLIefveQRIY9nfy6xoR1uRYBtpZgI6339F5dgvm/e9B" crossorigin="anonymous">
        <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/js/bootstrap.min.js" integrity="sha384-o+RDsa0aLu++PJvFqy8fFScvbHFLtbvScb8AjopnFD+iEQ7wo/CG0xlczd+2O/em" crossorigin="anonymous"></script>
        <title>@yield('title')</title>
    </head>
    <body>
        <div class="mx-auto" style="width: 600px; background-color: #2ff1d4; margin: 10px 10px">
            <div class="container-fluid">
                @yield('content')
            </div>
        </div>
    </body>
</html>
```

---

少しだけ解説

#### タイトルをはめ込みます
```php
<title>@yield('title')</title>        
```

#### 設定したコンテンツをはめ込みます
```php
@yield('content')
```



---


```html:\resources\views\article\index.blade.php
@extends('layouts.common')
@section('title', '掲示板')
@section('content')
    <div class="row">
        <div class="col-sm-12">
            <form method="POST" action="/article/add">
                <div class="form-group">
                    {{ csrf_field() }}
                    <p class="ext-monospace">タイトル</p><input type="text" name="title" class="form-control">
                    <p class="ext-monospace">本文</p><input type="text" name="body" class="form-control">
                    <br><input type="submit" value="投稿" class="btn btn-default">
                </div>
            </form>
            
        </div>
    </div>
    <div class="mx-auto" style="width: 450px;">
        <div class="row">
            <div class="col-sm-12">
                @foreach($articles as $article)
                    <div class="card border-primary mb-4" style="max-width: 30rem;">
                    <div class="card-body text-primary">
                        <h5 class="card-title">{{$article->title}}</h5>
                        <p class="card-text">{{$article->body}} </p>
                    </div>
                    </div>
                @endforeach
            </div>
        </div>
    </div>
@endsection
```

---

#### 親bladeとの関係性を設定します。

```php
@extends('layouts.common')
```

#### タイトルを設定できます

```php
@section('title', '掲示板')
```

#### はめ込む部品を書きます。

```php
@section('content')
    //code
@endsection
```

コメントを追加してみよう
http://localhost:8000/article

---

#### 削除機能をつける



```html:\resources\views\article\index.blade.php

<p class="card-text">{{$article->body}}</p>
// この下に入れる
<form method="post" action="/article/delete/{{$article->id}}">
{{ csrf_field() }}
<input type="submit" value="削除" class="btn btn-danger btn-sm" onclick='return confirm("君は本当に削除するつもりかい？");'>
</form>
```

---

Controllerに削除メソッドを追加



```php:\app\Http\Controllers\ArticleController.php
public function delete (Request $request)
{
    Article::find($request->id)->delete();
    return redirect('/article');
}
```

---

ルートを設定し、deleteメソッドを起動させる。



```php:\routes\web.php
Route::post('/article/delete/{id}', 'ArticleController@delete');
```
削除できるか確認してみよう

http://localhost:8000/article

---

#### Validate機能を設定する

保存処理の前にValidateの設定を書きます。



```php:\app\Http\Controllers\ArticleController.php

// Validateをインポート
use Validator;

// 省略

    public function add (Request $request)
    {
        // Validation
        // 入力情報の取得
        $inputs = $request->all();

        // ルールを設定
        $rules = [
            'title' => 'required|max:15',
            'body' => 'required|max:256'
        ];
        
        // エラーメッセージを設定
        $messages = [
            'title.required' => 'タイトルは必須だよ',
            'title.max' => 'タイトルは15文字以内だよ',
            'body.required' => '本文は必須だよ',
            'body.max' => '本文は256文字以内だよ'
        ];

        $validation = Validator::make($inputs, $rules, $messages);

        if ($validation->fails()){
            return redirect()->back()->withErrors($validation->errors())->withInput();
        }

        // 保存の処理
        $article = new Article;
        $article->user_id = 1; // 今回は1固定
        $article->title = $request->input('title');
        $article->body = $request->input('body');
        $article->save();

        return redirect()->to('/article');
    }

```

---

#### bladeを修正する
ここもコピペしよう



```html:\resources\views\article\index.blade.php
<div class="row">
    <div class="col-sm-12">
        <form method="POST" action="/article/add">
            <div class="form-group">
                {{ csrf_field() }}
                <p class="ext-monospace">タイトル</p>
                <input type="text" name="title" class="form-control @if ($errors->has('title')) is-invalid @endif" value="{{old('title')}}">
                @if ($errors->has('title'))
                    <span class="invalid-feedback">{{ $errors->first('title') }}</span>
                @endif
                
                <p class="ext-monospace">本文</p>
                <input type="text" name="body" class=form-control value="{{old('body')}}">
                @if ($errors->has('body'))
                    <span class="invalid-feedback">{{ $errors->first('body') }}</span>
                @endif
                
                <br><input type="submit" value="投稿" class="btn btn-default">
            </div>
        </form>
        
    </div>
</div>
```

Validationが効いているかためしてみよう

---
### 参考サイト
Laravel 5.7 TOC
https://readouble.com/laravel/5.7/ja/