Laravel + SQLiteでシンプルなブログアプリを作っていく

#はじめに
以前の投稿、[Laravel + SQLite 準備編](https://qiita.com/drafts/04936cff78af500b4d53)からの続きで、開発を進めます。

[ドットインストール Laravel 5.5入門](https://dotinstall.com/lessons/basic_laravel_v2)の内容に沿ってシンプルなブログアプリ開発を行います。

#環境
[VisualStudioCode]
(https://code.visualstudio.com)

Laravel Framework 7.12.0

#マイグレーションの設定

まず記事に関するモデルから作ります。

```:Terminal
$ php artisan make:model Post --migration
```
モデルは`artisan`コマンドを使えば良いので`php artisan`とします。
`make:model`としてモデル名は記事のModelなので`Post`とします。

その後にバージョン管理するためのマイグレーションファイルも作るので、
```--migration```というオプションを付けます。

こうすると`Model`が作られて`migration`ファイルも作られます。

---
`migration`ファイルを開いてデータベース構造の設定をします。
`migration`ファイルは`database`の中の`migrations`にあります。
`migration`ファイルには`up()`とdown`()`というメソッドがあります。

```php
<?php

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

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

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

`up()`→このマイグレーションで行いたい処理
`down()`→それを巻き戻すための処理

これらがあることでデータベース構成を変更したり、その変更を取り消したりすることが出来るので、結果としてデータベース構成のバージョン管理ができるという仕組みです。

upメソッドは自動的にmodelを複数形にしたテーブル名にしてくれてidとtimestampsを設定してくれています。
idは連番で付けられる主キーです。

timestampsは`created_at updated_at`というcolumnを作ってくれて作成日時と更新日時を自動で管理してくれる仕組みになっています。

columnを追加したいので、titleとbodyというcolumnにします。

```php
$table->id();
$table->string('title');
$table->text('body');
$table->timestamps();
```
**columnの種類**
SQLでいうところのvarcharはstringで設定していくので```string('title')```
bodyはテキストで設定したいので```text('body')```

参考：[varchar](https://sql-oracle.com/sqlserver/?p=721)
> 可変長の文字列です。可変長とは「長さが決まっていない」という意味で、varchar(10)に2バイトを格納すると、10バイトではなく２バイト使用します。
最大8,000バイト。文字データ型として最もよく使われるデータ型です。

このマイグレーションファイルの中身を実行します。

```:Terminal
$ php artisan migrate
```

SQLite でテーブルが作られたか確認。

```:Terminal
$ sqlite3 database/database.sqlite
```

```:Terminal
sqlite> .schema posts
```
```:Terminal
sqlite> .quit
```
確認できたらこれでOKです。

#Modelのインタラクティブな操作
LaravelはEloquentモデルと呼ばれていてSQLを意識しなくても直感的にデータが操作できるようになっています。

[Eloquent：利用の開始 5.7 Laravel - ReaDouble](https://readouble.com/laravel/5.7/ja/eloquent.html)
> Eloquent ORMはLaravelに含まれている、美しくシンプルなアクティブレコードによるデーター操作の実装です。それぞれのデータベーステーブルは関連する「モデル」と結びついています。モデルによりテーブル中のデータをクエリできますし、さらに新しいレコードを追加することもできます。

Postモデルを作ったので`php artisan tinker`というコマンドを使いインタラクティブに操作してみます。

```:Terminal
$ php artisan tinker
```
まずはレコードを挿入します。
インスタンスを作りsaveメソッドを使います。

インスタンスの作り方はデフォルトで名前空間がAppになっているので`new App\Post()`とします。

*[名前空間の概要 - Manual - PHP](https://www.php.net/manual/ja/language.namespaces.rationale.php)*

```:Terminal
>>> $post = new App\Post()
=> App\Post {#3054}
```

他にも設定していきます。

```:Terminal
>>> $post->title = 'title 1'; $post->body = 'body 1';
=> "body 1"
```

```:Terminal
>>> $post->save();
=> true
>>> 
```

このようにtrueと出れば正常に処理が終了したという意味になります。

**格納したデータを確認する**
```APP\Post::all(); ```
こちらのコマンドを使います。

```:Terminal
>>> APP\Post::all();
=> Illuminate\Database\Eloquent\Collection {#3781
     all: [
       App\Post {#3780
         id: "1",
         title: "title 1",
         body: "body 1",
         created_at: "2020-05-24 07:40:04",
         updated_at: "2020-05-24 07:40:04",
       },
     ],
   }
```

もっとシンプルな表示でみたい場合
```App\Post::all()->toArray();```

```:Terminal
>>> App\Post::all()->toArray();
=> [
     [
       "id" => 1,
       "title" => "title 1",
       "body" => "body 1",
       "created_at" => "2020-05-24T07:40:04.000000Z",
       "updated_at" => "2020-05-24T07:40:04.000000Z",
     ],
   ]
```
tinker終了
```exit```

```:Terminal
>>> exit
Exit:  Goodbye
```

SQLiteでも確認する

```:Terminal
$ sqlite3 database/database.sqlite
```

```:Terminal
sqlite> select * from posts;
```

先ほどのtitle1が入っているか確認

```:Terminal
1|title 1|body 1|2020-05-24 07:40:04|2020-05-24 07:40:04
```

Eloquentモデルを使えばSQLを特に意識しなくてもこのようにデータが扱えます。

```:Terminal
sqlite> .exit
```

終了
#Mass Assignmentの設定
Eloquentモデルをいじっていきたいのでまずtinkerを使います。

```:Terminal
$ php artisan tinker
```

データを格納する際にインスタンスを作ってsaveとしていましたが、

```:Terminal
App\Post::create(['title'=>'title 2', 'body'=>'body 2']);
```
これでそれぞれにデータを与えて一気に追加することも可能です。
しかしそのまま実行しても以下のようなエラーになります。

```:Terminal
Illuminate/Database/Eloquent/MassAssignmentException with message 'Add [title] to fillable property to allow mass assignment on [App/Post].'
```

**MassAssignment エラー**: 意図しないリクエストによって悪意のあるデータが挿入されてしまう脆弱性

これを実行するにはLaravelでデフォルト設定を変える必要があります。

モデルで設定をします。
Modelはappの中にあるのでapp>Post.phpを編集します。

```class Post extends Model {}```の中に

```:Terminal
protected $fillable = ['title', 'body'];
```

このcolumnの、titleとbodyにデータを挿入していい という設定になります。

設定を変えたのでtinkerをexitしてもう一度tinkerで入ります。

```:Terminal
>>> exit
```
```:Terminal
$ php artisan tinker
```

これで先ほどと同じコマンドを実行できます。

```:Terminal
>>> App\Post::create(['title'=>'title 2', 'body'=>'body 2']);
=> App\Post {#3935
     title: "title 2",
     body: "body 2",
     updated_at: "2020-05-24 08:37:32",
     created_at: "2020-05-24 08:37:32",
     id: 2,
   }
```

さらに```App\Post::create(['title'=>'title 3', 'body'=>'body 3']);```と追加すれば3も挿入できます。

```:Terminal
>>> App\Post::all()->toArray();
=> [
     [
       "id" => 1,
       "title" => "title 1",
       "body" => "body 1",
       "created_at" => "2020-05-24T07:40:04.000000Z",
       "updated_at" => "2020-05-24T07:40:04.000000Z",
     ],
     [
       "id" => 2,
       "title" => "title 2",
       "body" => "body 2",
       "created_at" => "2020-05-24T08:37:32.000000Z",
       "updated_at" => "2020-05-24T08:37:32.000000Z",
     ],
     [
       "id" => 3,
       "title" => "title 3",
       "body" => "body 3",
       "created_at" => "2020-05-24T08:39:36.000000Z",
       "updated_at" => "2020-05-24T08:39:36.000000Z",
     ],
   ]
```
#データの抽出
特定のidのデータを引っ張ってくる場合はfindにidを渡します。
idが3のデータを引っ張ってくるには、

```:Terminal
>>> App\Post::find(3)->toArray();
=> [
     "id" => 3,
     "title" => "title 3",
     "body" => "body 3",
     "created_at" => "2020-05-24T08:39:36.000000Z",
     "updated_at" => "2020-05-24T08:39:36.000000Z",
   ]
```
条件付きで抽出するにはwhereとgetを使います。
例えばidが1より大きいものをgetせよという命令はこのようにします。

```:Terminal
>>> App\Post::where('id', '>', 1)->get()->toArray();
=> [
     [
       "id" => 2,
       "title" => "title 2",
       "body" => "body 2",
       "created_at" => "2020-05-24T08:37:32.000000Z",
       "updated_at" => "2020-05-24T08:37:32.000000Z",
     ],
     [
       "id" => 3,
       "title" => "title 3",
       "body" => "body 3",
       "created_at" => "2020-05-24T08:39:36.000000Z",
       "updated_at" => "2020-05-24T08:39:36.000000Z",
     ],
   ]
```

このように2と3が抽出されています。

#データの並び替え
```orderBy('created_at', 'desc') ```で新しい順に表示します。

```:Terminal
>>> App\Post::where('id', '>', 1)->orderBy('created_at', 'desc')->get()->toArray();
=> [
     [
       "id" => 3,
       "title" => "title 3",
       "body" => "body 3",
       "created_at" => "2020-05-24T08:39:36.000000Z",
       "updated_at" => "2020-05-24T08:39:36.000000Z",
     ],
     [
       "id" => 2,
       "title" => "title 2",
       "body" => "body 2",
       "created_at" => "2020-05-24T08:37:32.000000Z",
       "updated_at" => "2020-05-24T08:37:32.000000Z",
     ],
   ]
```

SQLでいうところのlimitで、変数を制限するにはtakeを使います。

[SQLデータ分析入門#4『LIMIT句を理解する』](https://qiita.com/piyoSakai/items/131553cbc40ac357477f)
> 指定したレコードを上限に、結果を引っ張ってくる

```:Terminal
>>> App\Post::where('id', '>', 1)->take(1)->get()->toArray(); 
=> [
     [
       "id" => 2,
       "title" => "title 2",
       "body" => "body 2",
       "created_at" => "2020-05-24T08:37:32.000000Z",
       "updated_at" => "2020-05-24T08:37:32.000000Z",
     ],
   ]
```

#データの更新
一旦Postの3を$postに入れます。

```:Terminal
>>> $post = App\Post::find(3);
=> App\Post {#4008
     id: "3",
     title: "title 3",
     body: "body 3",
     created_at: "2020-05-24 08:39:36",
     updated_at: "2020-05-24 08:39:36",
   }
```

```$post->title``` を更新します。

```:Terminal
>>> $post->title = 'title 3 updated';
=> "title 3 updated"
```

```:Terminal
>>> $post->save();
=> true
```

これでデータベースに反映したので確認します。

```:Terminal
>>> App\Post::all()->toArray();
=> [
     [
       "id" => 1,
       "title" => "title 1",
       "body" => "body 1",
       "created_at" => "2020-05-24T07:40:04.000000Z",
       "updated_at" => "2020-05-24T07:40:04.000000Z",
     ],
     [
       "id" => 2,
       "title" => "title 2",
       "body" => "body 2",
       "created_at" => "2020-05-24T08:37:32.000000Z",
       "updated_at" => "2020-05-24T08:37:32.000000Z",
     ],
     [
       "id" => 3,
       "title" => "title 3 updated",
       "body" => "body 3",
       "created_at" => "2020-05-24T08:39:36.000000Z",
       "updated_at" => "2020-05-24T09:20:06.000000Z",
     ],
   ]
```

title 3 updatedに変わっているのでOKです。

#データの削除
deleteを使います。

以下のように今$postがidが3のデータになっています。

```:Terminal
>>> $post
=> App\Post {#4008
     id: "3",
     title: "title 3 updated",
     body: "body 3",
     created_at: "2020-05-24 08:39:36",
     updated_at: "2020-05-24 09:20:06",
   }
```
これを削除します。

```:Terminal
>>> $post->delete();
=> true
```
全件表示で確認します。

```:Terminal
>>> App\Post::all()->toArray();
=> [
     [
       "id" => 1,
       "title" => "title 1",
       "body" => "body 1",
       "created_at" => "2020-05-24T07:40:04.000000Z",
       "updated_at" => "2020-05-24T07:40:04.000000Z",
     ],
     [
       "id" => 2,
       "title" => "title 2",
       "body" => "body 2",
       "created_at" => "2020-05-24T08:37:32.000000Z",
       "updated_at" => "2020-05-24T08:37:32.000000Z",
     ],
   ]
```

idが1と2だけになっています。

#Controller
Postモデルにいくつかデータを格納できたので、そのデータをブラウザで表示します。
それにはどのURLでどのような処理をするかの設定をする必要があります。

その設定を**ルーティング**と呼び、routesフォルダの中のweb.phpで設定できます。

デフォルトの以下の部分は今回は使わないので削ります。

```php:routes>web.php
Route::get('/', function () {
    return view('welcome');
});
```

URLに/をつけてgetでアクセスした時のroutingを作る場合はまず、
```Route::get('/', '')```のように書いて、その後に行いたい処理を書いていきます。
PostsController@indexアクションを実行せよとしていきます。

```php:routes>web.php
Route::get('/', 'PostsController@index');
```
Controllerが必要になるので作っていきます。
artisanコマンドを使うので`php artisan make:controller`として`PostsController`という名前にします。

```:Terminal
$ php artisan make:controller PostsController
Controller created successfully.
```
Controllerが作られました。

Controllerはapp>Http>ControllersにPostsController.phpができているので編集していきます。

helloと表示してみます。
表示する内容を返せばいいので```return "hello";```のようにします。

```php:app>Http>Controllers>PostsController.php
extends Controller
{
  public function index() {
    return "hello";
  }
}
```

確認していきたいのでサーバーを立ち上げます。
サーバーを立ち上げるにあたってIPアドレスが必要になるので、
```$ ifconfig``` で調べられます。
inetの隣に4つ並んでいるものがローカルIPです。

ホストを指定する必要があるので、先程のIPアドレスを入れて--host 192.XXX.X.XX -- portを8000番で立ち上げてます。

```:Terminal
 $ php artisan serve --host 192.168.X.XXX --port 8000
```
実行

```:Terminal
Laravel development server started: http://192.168.X.XXX:8000
```
アクセス先のURLが出てきますので確認します。

helloと出てくればOKです。

**以上がroutingを設定してその処理をController辺りに作成するという流れでした。**

#View
viewを用意してそこにデータを入れていきます。
resourcesの中のViewsの中に作ります。

フォルダ名：Postに関するviewをまとめるのでpostsフォルダを用意します。
その中にAction名に対応したviewの名前を付けます。

ファイル名：indexアクションなのでindex。LaravelではBladeというテンプレートエンジンが使えるので、index.blade.phpとなります。

[Laravel 5.5 Bladeテンプレート](https://readouble.com/laravel/5.5/ja/blade.html)
> BladeはシンプルながらパワフルなLaravelのテンプレートエンジンです。他の人気のあるPHPテンプレートエンジンとは異なり、ビューの中にPHPを直接記述することを許しています。全BladeビューはPHPへコンパイルされ、変更があるまでキャッシュされます。つまりアプリケーションのオーバーヘッドは基本的に０です。Bladeビューには.blade.phpファイル拡張子を付け、通常はresources/viewsディレクトリの中に設置します。

内容の編集：emmetの機能でhtml5のテンプレートを貼り付けたら、titleと文字コードを編集。

bodyの方では、中身を後で中央揃えにします。
```<div class="container">```で囲っておき、見出し(h1)と記事の一覧(li)を作っていきます。

```html:resources>views>posts>index.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Blog Posts</title>
</head>
<body>
  <div class="container">
    <h1>Blog Posts</h1>
    <ul>
      <li><a href="">title</a></li>
      <li><a href="">title</a></li>
      <li><a href="">title</a></li>
    </ul>
  </div>
</body>
</html>
```
これでviewができたのでControllerの方でこのviewを指定します。

```php:app>Http>Controllers>PostsController.php
extends Controller
{
  public function index() {
    // return "hello"; 編集
    return view('posts.index');
  }
}
```

viewを使うにはreturn viewの後にviewの名前を指定します。
Action名と同じにしたので```posts.index```とします。
フォルダの区切りは .(ドット) になっている点に注意します。

ブラウザをリロードして確認

<img width="611" alt="スクリーンショット 2020-05-25 10.22.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555520/5d7026e5-e060-9d88-6efc-31ad27956c04.png">
このようにviewが反映されてればOKです。

#データの抽出
データを入れるため、まずはデータの取得からしていきます。

データを取得するにはEloquentの命令を使います。
```$posts = \App\Post::all();```
とすると全件を取得することが出来ます。
しかし名前空間が長くなるので、上の方で```use App\Post;```を使います。

```php:app>Http>Controllers>PostsController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Post;

class PostsController extends Controller
{
  public function index() {
    $posts = Post::all();
    dd($posts->toArray()); // dump die
    return view('posts.index');
  }
}
```
データが取得できたかどうかは、Laravelで用意されているdd()という命令を使って確かめます。
ddはdump dieの略で結果を出力して処理をその場で終了する命令です。
配列で見やすく表示させたいので`dd($posts->toArray());`としています。
<img width="378" alt="スクリーンショット 2020-05-25 10.45.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555520/825db210-2ddc-aaa3-b861-5e789a17d2ab.png">
こうしてブラウザで確認するとtitle1とtitle2のデータが取れています。

あとは記事を新しい順に並べたいのでorderByで並べ替えます。
```Post::orderBy('created_at', 'desc')->get();```

これでいいのですが、このcreated_atで新しい順に取ってくるという処理はよく行うので、
Laravelではlatest()という書き方も用意されていて
```Post::latest()->get();```で同じ意味になります。

```php:app>Http>Controllers>PostsController.php
class PostsController extends Controller
{
  public function index() {
    // $posts = Post::orderBy('created_at', 'dest')->get;
    $posts = Post::latest()->get();
    dd($posts->toArray()); // dump die
    return view('posts.index');
  }
}
```
ブラウザで確認します。
<img width="378" alt="スクリーンショット 2020-05-25 11.01.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555520/f278b4d2-20f0-9ecb-f30b-1b0e7e4d4d0f.png">
title2のほうが上に来ているのがわかります。
これでデータの抽出ができました。

#データをViewに埋め込む

`$posts`でデータの取得ができたのでこれをviewの方に渡していきます。
`return view()`の第2引数に渡します。

`'posts' => $posts`とすると`$posts`の内容をviewの中で`posts`という名前で使うことが出来ます。

もしくは`with('post', '$posts');`でも全く同じ意味になります。

```php
class PostsController extends Controller
{
  public function index() {
    $posts = Post::latest()->get();
    // return view('posts.index', ['posts' => $posts]);
    return view('posts.index')->with('posts', $posts);
  }
}
```

viewの方でこのpostsを使っていきます。

Bladeでは`@foreach`という制御構造を使えるので`@foreach(\$posts as \$post)`として、この`$post`を使ってループを展開していきます。

```html:resources>views>posts>index.blade.php
<div class="container">
    <h1>Blog Posts</h1>
    <ul>
      @foreach ($posts as $post)
      <li><a href="">{{ $post->title }}</a></li>
      @endforeach
    </ul>
  </div>
```
これで`$posts`が無くなるまで`$post`でひとつひとつの記事を表すことが出来るので値を埋め込みます。

値の埋め込みには二重波括弧を使うとエスケープもします。
```{{ $post->title }}```で$postのtitleを表示をします。

ブラウザを確認します。

<img width="378" alt="スクリーンショット 2020-05-25 11.25.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555520/ed76712c-f2d1-7961-007b-dc59e67c0888.png">


title2, title1 となっています。

**もしこちらの`$posts`の中身が空だったら、と書きたい場合**

`@forelse`という構文を使います。
そうすると、`@empty`という命令が使えるので`@empty`の後に、このデータが空だった時のテンプレートを入れ込むことが出来ます。

No posts yetと表示させることにします。

```html
  <div class="container">
    <h1>Blog Posts</h1>
    <ul>
      @forelse ($posts as $post)
      <li><a href="">{{ $post->title }}</a></li>
      @empty
      <li>No posts yet</li>
      @endforelse
    </ul>
  </div>
```
一旦`$posts`を空にします。

```php
class PostsController extends Controller
{
  public function index() {
    // $posts = Post::latest()->get();
    $posts = [];
    // return view('posts.index', ['posts' => $posts]);
    return view('posts.index')->with('posts', $posts);
  }
}
```
<img width="244" alt="スクリーンショット 2020-05-25 11.43.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555520/d58a13da-bdcf-76c0-949a-0a827c822285.png">
空のときの表示ができました。
確認できたら`$posts = [];`は戻しておきます。

BladeではHTMLに出力したくないコメントは`{{-- --}}`で囲みます。

```html
  <div class="container">
    <h1>Blog Posts</h1>
    <ul>
      {{--
      @foreach ($posts as $post)
      <li><a href="">{{ $post->title }}</a></li>
      @endforeach
      --}}
      @forelse ($posts as $post)
      <li><a href="">{{ $post->title }}</a></li>
      @empty
      <li>No posts yet</li>
      @endforelse
    </ul>
  </div>
```

**スタイルを整える**
CSSを読み込むリンクタグを入れます。
`<link rel="stylesheet" href="/css/styles.css">`

CSSやJavaScriptや画像はpublicフォルダの中に作っていきます。

```css:public>css>styles.css
body {
  font-family: Verdana, sans-serif;
  font-size: 14px;
}

.container {
  width: 400px;
  margin: 20px auto;
}

h1 {
  font-size: 16px;
  padding-bottom: 10px;
  margin-bottom: 15px;
  border-bottom: 1px solid #ddd;
}

ul >li {
  margin-bottom: 5px;
}
```
以下のような見た目になればOKです。
<img width="709" alt="スクリーンショット 2020-05-25 13.00.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555520/6b3e83eb-c20e-2d58-5aa1-722ff3ac0c79.png">

#記事の詳細画面の作成
記事の一覧ができたので、次は記事の詳細画面を作ります。
まずはroutingです。

URLとしてはgetでアクセスされたpostsの1や2を処理したいのですが、
ここにきた値をControllerに渡したい場合は波括弧を付けて変数名を書きます。

Controllerはshowアクションに渡します。
`Route::get('/posts{id}', 'PostsController@show');`

```php:routes>web.php
<?php

use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| 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('/', 'PostsController@index');
Route::get('/posts{id}', 'PostsController@show');
```
次にshowアクションを作ります。

Controllerの中に続きから書いていきます。

```php:app>Http>Controllers>PostsController.php
public function index($id) {
    // $post = Post::find($id);
    $post = Post::findOrFail($id);
    return view('posts.show')->with('post', $post);
  }
```

`web.php`のURLのパラメーターから渡ってきた値は引数で受け取ることが出来るので`$id`とします。

データを引っ張ってくるので`Post::find($id)`でいいのですが`$id`でデータが見つからなかった場合に、例外を返したいのでその場合は`findOrFail()`という命令を使います。

そしてデータをviewに渡してあげれば良いので今回は`posts.show`というテンプレートに対してpostという名前で`$post`のデータを渡します。

```php:app>Http>Controllers>PostsController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Post;

class PostsController extends Controller
{
  public function index() {
    $posts = Post::latest()->get();
    return view('posts.index')->with('posts', $posts);
  }
  public function show($id) {
    $post = Post::findOrFail($id);
    return view('posts.show')->with('post', $post);
  }
}
```

viewを作りたいのでresourcesフォルダに行きます。

`index.blade.php`を複製して`show.blade.php`を作り編集していきます。

head内タイトル変更

```<title>{{ $post->title }}</title>```

body内

```php:resources>views>posts>show.blade.php
<body>
  <div class="container">
    <h1>{{ $post->title }}</h1>
    <p>{!! nl2br(e($post->body)) !!}</p>
  </div>
</body>
```
この部分について
```<p>{!! nl2br(e($post->body)) !!}</p>```

本文の方は改行が入ってくる可能性もあるので、改行をbrタグに変換したいです。
まずは二重波括弧ではなく、中身をエスケープしないで値を出力するための`{{!! !!}}`という命令を使います。

`$post->body`を入れたいので、一旦Laravelの`e()`ヘルパーでエスケープして、それを`nl2br()`で挟み改行をbrタグにします。

---


`e()`
https://readouble.com/laravel/5.5/ja/helpers.html#method-e
> e関数は、PHPのhtmlspecialchars関数をdouble_encodeオプションにfalseを指定し、実行します。

```php
echo e('<html>foo</html>');

// &lt;html&gt;foo&lt;/html&gt;
```

`e()`について
https://laraweb.net/knowledge/835/
> HTMLエンティティ―（※ブラウザがHTMLとして処理せずにそのまま出力させるための代替コード）の実行

```php
echo e('<strong>laravel</strong>');
//出力結果　⇒ &lt;strong&gt;laravel&lt;/strong&gt;
```

`nl2br()`
https://www.php.net/manual/ja/function.nl2br.php
> nl2br — 改行文字の前に HTML の改行タグを挿入する
説明
nl2br ( string \$string [, bool $is_xhtml = TRUE ] ) : string
string に含まれるすべての改行文字 (\r\n、 \n\r、\n および \r) の前に <br /> あるいは <br> を挿入して返します。

#Implicit Binding
記事の一覧から記事の詳細画面にリンクを張ります。

routingの設計通り```/posts/{{ $post->id }}```でもいいですが、

```php
@forelse ($posts as $post)
li><a href="/posts/{{ $post->id }}">{{ $post->title }}</a></li>
```

URLを生成するための命令が他にもいくつかあります。

**url()という命令を使う方法**
```php
<li><a href="{{ url('/$posts', $post->id }}">{{ $post->title }}</a></li>
```

これでも同じ意味になります。

もしくはControllerとActionからURLを生成することができる`action()`という命令もあります。
その場合はPostsControllerのshowに対応するURLを生成する、という書き方ができます。

routingのパラメーターに渡す値は、第2引数以降に入れていけばいいので以下のようにします。

```php
<li><a href="{{ action('PostsController@show', $post->id }}">{{ $post->title }}</a></li>
 ```

これで各titleをクリックすると以下のように詳細リンクに飛べるようになりました。
<img width="709" alt="スクリーンショット 2020-05-25 14.49.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555520/5d75bddf-8a39-b1b8-5e4b-365ce10e8aae.png">

URLから`$id`を受け取って、Controllerでその`$id`を元にモデルを引っ張ってくるという流れはよく行うので、暗黙的にモデルをデータに結びつけられる**Implicit Binding**という仕組みも用意されています。

まずroutingを`'/posts/{post}'`にします。

```php:routes>web.php
// Route::get('/posts{id}', 'PostsController@show');
Route::get('/posts{post}', 'PostsController@show');
```

```php:app>Http>Controllers>PostsController.php
// public function show(Post $id) {
public function show(Post $post) {
```

これで自動的にこの`$post`にはURLから受け取ったidに対応するデータが格納されます。

なのでこの場合はidで引っ張ってくる必要がないのでこれでOKです。

```php
  public function show(Post $post) {
    // $post = Post::findOrFail($id); // 削除
    return view('posts.show')->with('post', $post);
  }
```
さらにリンクの生成についても`$post->id`を`$post`にするだけで、`@post`のidをパラメーターに渡してくれます。 

```html:resources>views>posts>index.blade.php
      <!-- <li><a href="{{ action('PostsController@show', $post->id) }}">{{ $post->title }}</a></li> -->
      <li><a href="{{ action('PostsController@show', $post) }}">{{ $post->title }}</a></li>
```
同じようにtitleから詳細リンクへの動作を確認することができます。
以上がImplicit Bindingです。

長くなるので続きは分けます。

後半は共通部分の部品化、編集やコメント機能などから進めていきます。

#Links
ドットインストール Laravel 5.5入門
https://dotinstall.com/lessons/basic_laravel_v2