Laravelでログイン機能付きサイト作成 with XAMPP(1/4)　基礎学習編

**この記事の解説は独自の解釈が多いため間違っている可能性もあります。そのような箇所があれば指摘して頂けると幸いです。**

## 目標

**ログイン機能付きのサイトを作るために必要な`Laravel`の基礎を習得する**

## 環境
- Windows 10 home
- XAMPP
- Laravel

## Laravelの勉強
まずは[初心者のためのLaravel入門 - libro](http://libro.tuyano.com/index2?id=3766003)を軸に勉強を進めていく。
学習の手順としては入れ替えた方が良い箇所もあるかもしれないが、自分にとって親しみやすい順で進めていく。

### Laravelのインストール

#### Composerのインストール 
`Laravel`のインストールには`Composer`というパッケージ管理ツールを使う。
`PHP`で使用するソフトウェアやアプリケーションをインストールしたい時に、そのソフトウェアなどが動くのに必要な依存関係のある他のソフトウェアなども一緒にインストールしてくれる便利なツール。
[Composer 公式](https://getcomposer.org/)からダウンロードして、`PATH`を通して、ターミナルなどで次のような表示がされればOK。
![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/8a014076-073e-0b27-5211-472c6d459622.jpeg)


#### Laravelインストーラーの導入
`Laravel`では設定ファイルやコードなどを1つの**プロジェクト**としてまとめて作業を行う。
ディレクトリやフォルダと同じ認識。

では、`Laravel`のプロジェクトを作成していく。
今後も`Laravel`プロジェクトを作成することを考えて、`Composer`でLaravelインストーラーを導入してから`Laravel`のプロジェクトを作成する。
Laravelインストーラーは下記のコマンドをターミナル実行して、インストールする。

```
$ composer global require "laravel/installer"
```

Laravelインストーラーのダウンロードが終わったら、赤下線部分をエクスプローラーで開く。
![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/9e41ad33-b608-5f59-b0af-24954d3887e5.jpeg)
そこから`~\vendor\bin`まで移動し、そこまでのパスをコピーする。

```
C:\(各自のパス)\AppData\Roaming\Composer\vendor\bin
```

その後、`Windows10`の左下にある検索窓から「環境変数」を入力して`システム環境変数の編集`を開く
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/90d61f21-493f-9257-8db0-5b1b6007689f.jpeg" height="500px">

`システムのプロパティ`が開けたら下の`環境変数`(赤枠部)をクリック。
![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/aeff2222-2175-939c-e512-2099920da9d5.jpeg)

その後、下にある`システム環境変数(S)`から`Path`を探してダブルクリック。
すると、`環境変数名の編集`が開けるので、右上の`新規`をクリックし、先程のパスを貼り付けて、`OK`を押す。


#### Laravelプロジェクトの作成
ターミナルに戻り、下記コマンドを実行。

```
$ laravel new blog(プロジェクト名)
```

これで`Laravel`のプロジェクトが作成される。
今後、`Laravel`のプロジェクトを作成したいときは、`$ laravel new (プロジェクト名)`をターミナルで実行するだけで作成できるようになった。

作成できたプロジェクトを実際に実行してみる。
ターミナルから以下のコマンドを実行。

```
$ cd (プロジェクト名)
$ php artisan serve
```

![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/3672b987-5b57-42b7-695d-413145a37fef.jpeg)

**`$ php artisan serve`で`Laravel`の内蔵サーバーを起動できる。**
つまり、このコマンドを利用することでローカルのアプリケーションとしてプロジェクトの状態確認が可能に。
ターミナルに表示された http://127.0.0.1:8000 にアクセスしてみると、`Laravel`と中央に大きく書かれたサンプルページが開かれる。
ターミナルで`Ctrl + C`を押すとサーバーを閉じる。


### プロジェクト(フォルダ)構成について
プロジェクトを作成した際、一緒にインストールされたファイルなどは[Laravelをスタートしよう(4/5):初心者のためのLaravel入門 - libro](https://www.tuyano.com/index3?id=11526003&page=4)に解説が載っている。
ただ、この記事の情報は古いため、必要があれば下記コマンドで`Laravel`のバージョンなどを確認し、公式ドキュメントなどで各自フォルダ構成について調査を。

```
$ php artisan --version
```

### ルーティング処理
**ルーティング処理: どのアドレスでアクセスされたら、どの処理を返すかを定義するもの**

`Laravel`では`(プロジェクト名)\routes\web.php`でルーティング処理が指定されており、実際にファイルを確認してみると、以下のような宣言がある。

```(プロジェクト名)\routes\web.php
Route::get('/', function () {
    return view('welcome');
});
```

上記のコードを`Route::メソッド(第一引数, 第二引数)`として解説を行う。

- `Route`: クラス名。`::`の後に続くメソッドを呼び出して処理を実行する。
- `メソッド`: `Route`クラスで定義されている処理から、どの処理を実行するかを指定する。ここによって次の`第一引数`の値が変わる。
- `第一引数`: `メソッド`によって値が変わる。(例: `get`メソッドではアドレスを表すテキスト。`group`メソッドではアドレス情報をまとめた配列になる)
- `第二引数`: `第一引数`にアクセスされた際に返す処理。`web.php`ではファイル名が指定されているがテキストなども返すことができる。

以上の解説を踏まえて、現在の`web.php`を見てみると、**`/(ルート)`にアクセスされたら`view(welcome)`を返す**ルーティング処理であることがわかる。
このルーティング処理で呼び出される`view(welcome)`がどこにあるか、どのファイルかという質問に対する答えは、`(プロジェクト名)\resources\views\welcome.blade.php`。

`view()`関数については次章で説明する。
`welcome.blade.php`に`blade`という見慣れない拡張子があるが、これは`Laravel`で利用できるテンプレートの仕組み。
この仕組みを利用することで、`blade`拡張子がついたファイル同士でコードを共有しあったり、`Laravel`に搭載されている機能を簡単に呼び出したりすることができるようになる。

ルーティング処理についてわかったところで、`Hello,World!!`を表示するように`web.php`を変更してみる。
この後の作業で使用するため、変更前のコードをコメントアウトなどして残しておく。

```(プロジェクト名)\routes\web.php
Route::get('/', function () {
    return 'Hello,World!!';
});
```

![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/86047c8e-14c7-5a5e-ef8a-bb16ad696450.jpeg)

### 表示用のファイル(テンプレート)について
`web.php`で特定のURLにアクセスされた際の処理を定義できることが分かった所で、その結果を表示するページを作成していく。
今回は簡単な`PHP`ファイルを作成するが、`welcome.blade.php`のようなファイルを作成することもある。むしろ、そちらが主流。そのような`.blade.php`拡張子ファイルは**テンプレート**と呼ばれ、この先で作成するため覚えておいてほしい。

では、表示用のページとなるファイルから作成していく。
`(プロジェクト名)\resources\views\`に`template.php`を作成し、下記の内容にする。

```(プロジェクト名)\resources\views\template.php
<!DOCTYPE HTML>
<html>
	<head>
		<title>template</title>
    	<style>
    		body{color:gray;}
    		h1{font-size:18pt; font-weight:bold;}
    	</style>
    </head>
    <body>
    	<h1>Template</h1>
    	<p><?php echo $message; ?></p>
    </body>
</html>
```

次に、`web.php`でこのファイルをを表示するルーティング処理を定義する。

```(プロジェクト名)\routes\web.php
Route::get('/template', function () {
    return view('template',['message' => 'Study Template']);
});
```

ルーティング処理の内容は**`/template`にアクセスされたら`template.php`を返す**というものだが、`view()`の中に連想配列が指定されている。

ここで`ルーティング処理`の所で飛ばした`view()`関数の説明をする。
`view()`関数は**`view(第一引数, 第二引数)`**という形をとり、次のように宣言する。

- `第一引数`: ファイル名、テンプレート名を指定する。**拡張子を除いた名前を宣言する**。
- `第二引数`: `第一引数`に渡す値などを指定する。今回では連想配列を用いて、`template.php`の変数`$message`に`Study Template`という文字列を渡している。

以上のファイル、ルーティング処理の作成によって表示されるページは次のようなものとなる。
http://127.0.0.1:8000/template

![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/28b079c0-602e-05d4-ac60-f94afe76021a.jpeg)

### コントローラー
`(プロジェクト名)\routes\web.php`にルーティング処理を定義することで、`(プロジェクト名)\resources\views\`にある表示用のファイルやテンプレートを呼び出せるようになったがある問題が潜んでいる。
それは`view()`の第二引数を利用する処理が増えると、`web.php`のコードが複雑になることだ。
テンプレートの作成では第二引数に指定する連想配列のキーと値は1つだけだったが、`web.php`で宣言するルーティング処理が増え、連想配列の数も増えれば見づらく、読みにくいコードとなってしまう。

そのような問題を防ぐために使用されるのが**コントローラー**だ。
実際に作成しながら解説をしていく。

コントローラーは`(プロジェクト名)\app\Http\Controllers`に作成する。
今回はその階層に`TemplateController.php`というファイルを作成し、次の内容にする。

```(プロジェクト名)\app\Http\Controllers\TemplateController.php
<?php
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
 
use App\Http\Requests;
use App\Http\Controllers\Controller;
 
class TemplateController extends Controller
{
    public function getIndex()
    {
        return view('template', ['message' => 'Study Template']);
    }
}
?>
```

そして、`web.php`の`Route::get('/template', ~`を下記のように変更する。

```(プロジェクト名)\routes\web.php
Route::get('/template','TemplateController@getindex');
```

`Route`クラスの第二引数に指定されている**`TemplateController@getindex`で`TemplateController`の`getIndex()`メソッドを呼び出す**ことを宣言している。

`TemplateController.php`のようなコントローラーの仕組みを説明をしていく。
新規作成したコントローラーのファイルでは**`use App\Http\Controllers\Controller;`**で`App\Http\Controllers\Controller`というクラスを継承することを**忘れずに**宣言する。
`public function getIndex()`で宣言されている`getIndex()`は、`Route::get()`などの`GET`アクセスで`index`というアドレスにアクセスした際に呼び出されるメソッドであることを定義している。
この`TemplateController.php`自体が`web.php`のルーティング処理において、`Route::get()`で`/template`に割り当てられているため、`/template/index(トップページ)`にアクセスすると、`getIndex()`が呼び出され、`view()`で定義した処理が実行される仕組みとなっている。

コントローラーで指定するメソッド(`getIndex()`など)は**HTTPメソッドの種類 + アクセスするアドレス**によって名前が自動的に決まるため、このルールを覚えておく必要がある。

http://127.0.0.1:8000/template にアクセスして、エラーが表示されていないか確認。

### Requestクラス
ここでは`Request`クラスを利用して、フォームを使用したページ間でのデータの送受信ができるようにする。
この記事の軸にしていたサイトの情報が古かったので、ここでは[Laravel5 チュートリアル ブログもどきを作る(2) ブログ記事投稿フォームの作成 - Qiita](https://qiita.com/yumgoo17/items/55152da02372dd203bcb)をメインに進めていく。


まずはテンプレートの作成から。
`GET`メソッド以外でフォームを利用する場合、`Laravel`の仕様で`CSRF(ログイン状態で悪意あるURLにアクセスするとログイン情報が盗まれ悪用される事)`の対策をしないとエラーが発生する。
その対策として活用できるのが`Laravel`の機能である`blade`テンプレートだ。
`(プロジェクト名)\resources\views\`に`form.blade.php`を作成し、次の内容にする。


```(プロジェクト名)\resources\views\form.blade.php
<!DOCTYPE HTML>
<html>
	<head>
		<title>Form</title>
    	<style>
    		body{color:gray;}
    		h1{font-size:18pt; font-weight:bold;}
    	</style>
    </head>
    <body>
    	<h1>フォームを利用したデータの送受信</h1>
        <p>{{ $message }}</p>
    	<form method="POST" action="/form">
            {{ csrf_field() }}
            <input type="text" name="str">
            <input type="submit">
        </form>
    </body>
</html>
```


**`{{ }}`が`blade`テンプレートの記法。**
`{{}}`自体は`<?php echo ~ ?>`の代わりで、`{{ csrf_field() }}`はこれだけで`Laravel`における`CSRF`対策の機能を呼び起こし、利用できる。

続いて、コントローラーを作成する。
`(プロジェクト名)\app\Http\Controllers`に`FormController.php`を作成し、次の内容にする。

```(プロジェクト名)\app\Http\Controllers\FormController.php
<?php
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
 
use App\Http\Requests;
use App\Http\Controllers\Controller;
 
class FormController extends Controller
{
    public function getIndex(Request $request)
    {
        return view('form', ['message' => 'データを入力してください。']);
    }
    public function postIndex(Request $request)
    {
    	$res = "入力内容: ".$request -> input('str');
        return view('form', ['message' => $res ]);
    }
}
?>
```

`postIndex()`はテンプレートの章でも説明したように、`POST`アクセスで`index`に接続した際に実行される処理がそれ以降に記載されている。
そのため、`POST`アクセスが行われていない何もデータが入力されていない時に表示する用のページとして、`getIndex()`のメソッドも作成しておくことも必要。

そして、今回の主題となるのが**`Request`クラス**を利用した**`(Request $request)`**だ。
`Request`クラスではユーザーからのアクセスを始めとする各種情報を管理している。
その内容を`$request`に入れ、今回は`input('str')`という形でデータを取り出している。
`input`に関するデータは`input(name属性)`で取り出せるため、このような記述となる。

`(プロジェクト名)\routes\web.php`に次のルーティング処理を追記する。

```web.php
Route::get('/form','FormController@getindex');
Route::post('/form','FormController@postindex');
```

ここで意図した設計で稼働しているか確認してみる。
http://127.0.0.1:8000/form にアクセス。

![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/736b8253-df8c-5d65-7e55-b6f82e9f63ce.jpeg)

この状態で`送信`を押すと、

![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/b6b7563d-6aa0-164f-fc2a-ebcad5a82ccd.jpeg)

このように変化する。

[Requestクラスの基本(3/5):初心者のためのLaravel入門 - libro](https://www.tuyano.com/index3?id=3786004&page=3) 以降ではクエリやURLの取得、リダイレクトについて記載されているため、確認してみては。

### データベースとの連携
ここでは`XAMPP`の`MySQL`を利用して、`Laravel`とデータベースを連携させる。

まずはデータベースの準備から。
`XAMPP`を起動したら、`XAMPP`のコントロールパネルにおける`MySQL`の`Admin`をクリックして、`phpMyAdmin`に接続する。

![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/4110e75f-885a-ec78-0335-31eb7a0b0238.jpeg)

`phpMyAdmin`にログインできたら、`データベース`タブから下記画像のように新規データベースを作成する。(画像ではデータベース名が頭文字が大文字だったが作成したら小文字になった。)
![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/3113e7f2-b38f-83f8-1d23-4af2bb6ce7db.jpeg)

そして、新規テーブルを作成する。
好きな名前とカラム数を設定してテーブルを作成し、
![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/4c741d87-5298-21cd-1489-cb1297b4b180.jpeg)

各カラムの設定を行い、
![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/5a7ac5e9-23cf-4b06-2df9-dd08c0c5fdd9.jpeg)

サンプルデータを何個か入れる。
![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/43050e9a-93ef-6ce5-985d-6dcb633e931a.jpeg)

ここまで(↓)設定できたら、次は`Laravel`側の設定に移る。
![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/7dee1c62-de0c-b5d5-3382-3f3287559a88.jpeg)

今回は`MySQL`を使用するが、他のデータベースを利用したい場合は、`(プロジェクト名)\config\database.php`を開いて、下記の部分を使用したいデータベースに変える。

```(プロジェクト名)\config\database.php
'default' => env('DB_CONNECTION', 'mysql'),
```

どのデータベースを使用するか設定できたら、`(プロジェクト名)\.env`を開いて、下記にデータベース情報を入力していく。
デフォルトで値が入っているが、必要があれば変更する。

```(プロジェクト名)\.env
DB_CONNECTION=
DB_HOST=
DB_PORT=
DB_DATABASE=
DB_USERNAME=
DB_PASSWORD=
```


ここからはデータベースに接続し、値を取得、ページに表示するまでを説明していく。

コントローラーの作成から行っていく。
`(プロジェクト名)\app\Http\Controllers`に`DatabaseController.php`を作成し、下記の内容にする。

```(プロジェクト名)\app\Http\Controllers\DatabaseController.php
<?php
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
 
use DB; 
use App\Http\Requests;
use App\Http\Controllers\Controller;
 
class DatabaseController extends Controller
{
    public function getIndex(Request $request)
    {
        $data = DB::select('select * from sample');
        return view('database', ['message' => 'データベース名: sample','data' => $data]);
    }
}
?>
```

**`use DB;`** を忘れないように注意。
**`DB::select`** はデータベースに対して`SELECT`のクエリ文を実行するための関数。

`select`以外にも`DB`クラスにはデータベースを操作するためのメソッドがあり、それらを **`CRUD処理`** と呼ぶ。
**`CRUD処理`** とは、**`Create(生成)`** , **`Read(読み取り)`** , **`Update(更新)`** , **`Delete(削除)`** の処理における頭文字を並べたもの。
それぞれの`DB`クラスにおけるメソッドは**`Create(生成) = DB:insert()`** , **`Read(読み取り) = DB:select()`** , **`Update(更新) = DB:update()`** , **`Delete(削除) = DB:delete()`** となるので覚えておく。

余談となるが、複数人がページやサイトにアクセスしていて、同時にデータベースに`CRUD処理`を実行した場合、`Update`と`Delete`が同時に実行する命令が起きるようなデータの不整合が起きる可能性がある。
そのような事態に陥るのを防ぐために行われるのが **`トランザクション`** で、**`DB::beginTransaction();`** から **`DB::commit();`** の間に書かれた処理が実行されている間は他の命令が実行されることを防ぐことができるようになる。
本番環境でデータの書き換えを行うような処理を定義する場合は忘れずに記述するようにしておく。

本題に戻って、コントローラーが取得したデータベースのデータを表示するページを作成していく。
`(プロジェクト名)\resources\views\`に`database.blade.php`を作成し、下記のような内容に。

```(プロジェクト名)\resources\views\database.blade.php
<!DOCTYPE HTML>
<html>
	<head>
		<title>Form</title>
    	<style>
    		body{color:gray;}
    		h1{font-size:18pt; font-weight:bold;}
            　　th{color:white; background:#999;}
            　　td{color:black; background:#eee; padding:5px 10px;}
    	</style>
    </head>
    <body>
    	<h1>Laravelとデータベースの連携</h1>
        <p>{{ $message; }}</p>
        <table>
            <tr>
                <th>ID</th>
                <th>NAME</th>
                <th>PASS</th>
                <th>CREATE_DAY</th>
            </tr>
            @foreach($data as $value)
            <tr>
                <td>{{ $value -> id; }}</td>
                <td>{{ $value -> name }}</td>
                <td>{{ $value -> pass }}</td>
                <td>{{ $value -> create_day }}</td>
            </tr>
            @endforeach
    </table>
    </body>
</html>
```

`@foreach($data as $value)`でコントローラーが取得したデータベースの各値が入っている`$data`を`$value`に移す。
`{{ $value -> (カラム名) }}`で各カラムに入っているデータを取得して表示している。

`(プロジェクト名)\routes\web.php`に今回のルーティング処理を実装して、実際にページを確認してみる。

```(プロジェクト名)\routes\web.php
Route::get('/database','DatabaseController@getindex');
```

自分の今までに掲載した画像の設定と同じ設定にすれば次のように表示されるはず。
http://127.0.0.1:8000/database

![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/8ae3b5dc-af5f-c851-bd3b-2f647d4aeaa3.jpeg)

### ORM(Object/Relational Mapping)について
さっきは自分でデータベースを作成して値を取得、表示まで行ったが、仕事でも同じような状況で作業ができるとは限らない。
違う人がデータベースを作成する事なんて普通だし、そもそもデータベースを見れずに手探りでデータを取得しなければならないことだってあり得る。
そのような状況で、今までのようなやり方では不都合が多い。

そこで`PHP`のようなオブジェクト指向言語で用いられる技術が **`ORM(Object/Relational Mapping)`** だ。
この技術を用いることで、データベースのテーブルに存在しているデータ、値を`PHP`のオブジェクトに変換したり、その逆の変換も行えるようになる。
その上、`PHP`側で用意したクラスを操作するだけで、それに対応するデータベースのテーブルを自動的に操作できるようになるという。

`Laravel`では **`Eloquent`** という`ORM`が利用できるため早速使用してみる。

最初にテーブルに対応する**モデル**と呼ばれるクラスの作成を行う。
ターミナルでプロジェクトのトップディレクトリに移動し、下記コマンドを実行。
自分はどのテーブルを扱うのかわかりやすいよう、`テーブル: sample`に対し、`モデル: Sample`を作成した。

```
 $ php artisan make:model Sample(モデル名)
```

上記のコマンドが成功すると、`(プロジェクト名)\app`に`Sample(モデル名).php`が作成されているので、開いて確認してみると次のような内容になっている。

```(プロジェクト名)\app\Sample(モデル名).php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Sample extends Model
{
    //
}
```

`//`とコメントアウトにされている箇所があるが、そこを **`protected $table = 'sample';`** に変更して、使用するテーブル名を定義する。
`protected`を付けることで、そのクラス自身と継承したクラス限定でアクセスが可能となるため、テーブルを保護するためにも欠かさずに付与する。
モデルの作成はこれで完了。コントローラーの作成に移る。

`(プロジェクト名)\app\Http\Controllers`に`ORMController.php`を作成し、下記の内容を入力する。
データベースとの連携で使用した表示用のファイル`(プロジェクト名)\resources\views\database.php`を使用するため、`view()`関数の第一引数は`database`にする。

```(プロジェクト名)\app\Http\Controllers\ORMController.php
<?php
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;

use App\Sample; 
use App\Http\Requests;
use App\Http\Controllers\Controller;
 
class ORMController extends Controller
{
    public function getIndex(Request $request)
    {
        $data = Sample::all();
        return view('database', ['message' => 'データベース名: sample','data' => $data]);
    }
}
?>
```

**`use App\Sample;`** で今回作成したモデルを使用することを宣言。
**`Sample::all()`** では、`Sample`クラスで`モデル: Sample`に対応している`テーブル: sample`の全データを`all`メソッドを使用して取得している。

一回ここで、モデルなどが問題なく使えているか確かめる。
`(プロジェクト名)\routes\web.php`にルーティング処理を実装し、実際にページを確認してみる。

```web.php
Route::get('/orm','ORMController@getindex');
```

http://127.0.0.1:8000/orm にアクセスしてみて、http://127.0.0.1:8000/database と同じ内容が表示されているか確かめる。
![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/37a63fea-0bfe-853c-994c-f74818533a4f.jpeg)


`all` の他にもデータベースにおける処理に関するメソッドがモデルクラスには用意されている。
その中の一つが検索機能の **`where`** だ。
`where`は **`モデル名::where(カラム名, 取得したい値)`** でテーブルに検索をかけて、 **`get()`** でその結果を取得する。
コントローラーに実装して、試してみるとそれぞれ次のようになる。

```ORMController.php
class ORMController extends Controller
{
    public function getIndex(Request $request)
    {
        $data = Sample::where('id', 2)->get();
        return view('database', ['message' => 'データベース名: sample','data' => $data]);
    }
}
?>
```

![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/982095d8-876f-9b19-d876-5ad71db7b64a.jpeg)

検索を実行できる`where`には様々な使い方がある。
`>`や`like`といった演算子を使いたい場合は **`where(カラム名, 演算子, 取得したい値)`** 、`and`条件なら **`where(条件1) -> where(条件2)`**、`or`条件なら **`where(条件1) -> orWhere(条件2)`** という風になる。
データベースから値を取得する機会は多いので、少なくともこれらだけでも覚えておきたい。

### Laravelからデータベースのデータを操作する
**`CRUD処理`** において、`Read`に関しては`ORM`の`where`で触れたが、`Create`と`Update`,`Delete`がまだなので、今回はそれらに触れていく。

#### 前準備
`ORM`の際に作成したモデルに2つのコードを追加する。

```(プロジェクト名)\app\Sample(モデル名).php
class Sample extends Model
{
    protected $table = 'sample';

    protected $guarded = array('id');
 
    public $timestamps = false;
}
```

`protected`はテーブルだけでなく、データも保護できる。
**`protected $guarded = array('id');`**で**主キーを保護する。**
更新や削除の際に`protected`で保護されていないと、連携しているテーブルにも影響を与えてしまう。
それらを防ぐためにもテーブルや主キーには **`protected`で忘れず**に保護をかける。

`Laravel`でデータベースにデータを作成、追加する際、`create_at`,`update_at`という、それぞれ作成日時と更新日時を示す項目が自動的に作成される。
今回利用するテーブルではこれらの項目を設けていないため、何もしない状態でデータベースにデータを作成、追加してしまうと、エラーの原因となる。
それを防ぐのが **`public $timestamps = false;`** の部分。
このコードを追加することで、データベースにデータを作成、追加する際に`create_at`,`update_at`が生成されなくなる。
データベースにデータを作成、追加する処理を`Laravel`に実装する際は、このコードを追加するかテーブルに`create_at`,`update_at`カラムの作成を忘れないように。

#### Create
表示用のページとして`(プロジェクト名)\resources\views\`に`create.blade.php`を作成し、次のような内容に。

```(プロジェクト名)\resources\views\create.blade.php
<!DOCTYPE HTML>
<html>
<head>
    <title>CRUD</title>
    <style>
    body{color:gray; }
    h1{font-size:18pt; font-weight:bold;}
    th{color:white; background:#999;}
    td{color:black; background:#eee; padding:5px 10px;}
    </style>
</head>
<body>
    <h1>LaravelからのCRUD処理</h1>
    <p>{{ $message }}</p>
    <table>
            <tr>
                <th>ID</th>
                <th>NAME</th>
                <th>PASS</th>
                <th>CREATE_DAY</th>
            </tr>
            @foreach($data as $value)
            <tr>
                <td>{{ $value -> id }}</td>
                <td>{{ $value -> name }}</td>
                <td>{{ $value -> pass }}</td>
                <td>{{ $value -> create_day }}</td>
            </tr>
            @endforeach
    </table>
    <table>
    <form method="post" action="/create">
        {{ csrf_field() }}
        <tr><td>NAME:</td><td><input type="text" name="name"></td></tr>
        <tr><td>PASS:</td><td><input type="text" name="pass"></td></tr>
        <tr><td>CREATE_DAY:</td><td><input type="text" name="day"></td></tr>
        <tr><td></td><td><input type="submit"></td></tr>
    </form>
    </table>
</body>
</html>
```

大まかな内容としては、テーブルのデータを表示して、`post`で作成するデータを送信するというもの。

`ID`に値する内容を入力するフォームを作成していないが、これはデータベースの`AUTO_INCREMENT`を利用しているため。
`AUTO_INCREMENT`とは他のデータが挿入された際に、適用しているカラムに自動でデータを入力してくれるデータベースの機能。
この機能を適用させるには、`phpMyAdmin`を開いて、`AUTO_INCREMENT`を適用したいカラムを選択して、`変更`をクリック。
![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/9bceacd7-beaa-fb1c-772b-a331066daeaf.jpeg)

その後、`A_I`の下のチェックボックスにチェックを入れ、保存。
![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/d6414927-d833-5b64-67ac-70928874c612.jpeg)

もし、使用しない場合は`ID`の値を入力するフォームを作成を忘れないように。

`post`から投げられたデータはコントローラーでデータベースのテーブルに挿入する。
その処理は以下のような内容。

```(プロジェクト名)\app\Http\Controllers\CreateController.php
<?php
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;

use DB; 
use App\Sample; 
use App\Http\Requests;
use App\Http\Controllers\Controller;
 
class CreateController extends Controller
{
    public function getIndex(Request $request)
	{
    	$data = DB::select('select * from sample');
    	return view('create', ['message' => 'Create処理を実行する','data' => $data]);
	}

	public function postIndex(Request $request)
	{
    	$name = $request -> input('name');
    	$pass = $request -> input('pass');
    	$day = $request -> input('day');
    	$data = array(
        	'name' => $name,
        	'pass' => $pass,
        	'create_day' => $day
    	);
    	Sample::create($data);
    	return redirect()->action('CreateController@getindex');
	}
}
?>
```

データベースのテーブルにデータを作成する処理、`Create`では`モデル名::create()`メソッドを使用する。

**`getIndex()`** はデータベースの連携の際の内容と同じなので説明を省略。

**`postIndex()`** は`post`が実行されたときに行われる処理を示している。
`input`に入力された`name`,`pass`,`day`を`$data`という連想配列に格納して、`モデル名::create($data)`で`$data`の内容をデータベースのテーブルに格納。
その後、`getIndex()`にリダイレクトするという流れになっている。

最後に`(プロジェクト名)\routes\web.php`に下記のルーティング処理を実装し、実際にページを確認してみる。

```(プロジェクト名)\routes\web.php
Route::get('/create','CreateController@getindex');
Route::post('/create','CreateController@postindex');
```

`post`前
![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/1e726a72-cf97-89f0-a57b-c5138edb6d7d.jpeg)

`post`後(`ID`の5,6が抜けてるのは作成中にエラーの対応をしていたため)
![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/e1789073-0592-7987-e78d-79b30876e597.jpeg)

#### Update
表示用のページとして`(プロジェクト名)\resources\views\`に`update.blade.php`を作成し、`form`以下を次の内容に。
それ以外は`Create`で作成した`create.blade.php`と同じ。

```(プロジェクト名)\resources\views\update.blade.php
    <form method="post" action="update">
        {{ csrf_field() }}
        <tr>
            <td>ID:</td>
            <td>
                {{ optional($data)->id }}
                <input type="hidden" name="id" value="{{ optional($data)->id }}">
            </td>
        </tr>
        <tr>
            <td>NAME:</td>
            <td><input type="text" name="name" value="{{ optional($data)->name }}"></td>
        </tr>
        <tr>
            <td>PASS:</td>
            <td><input type="text" name="pass" value="{{ optional($data)->pass }}"></td>
        </tr>
        <tr>
            <td>CREATE_DAY:</td>
            <td><input type="text" name="day" value="{{ optional($data)->create_day }}"></td>
        </tr>
        <tr>
            <td></td>
            <td><input type="submit"></td>
        </tr>
    </form>
```

`id`以外の各カラムの更新内容を入力するフォームを作成。

**`optional()`** は**引数に指定したオブジェクトにアクセスしたり、そのプロパティを取得する** 関数。
オブジェクトが`null`の時は`null`を返す。

`post`から投げられたデータをデータベースに更新する処理を記述するコントローラーの`class`以下は次のような内容。
`class`より上は`Create`で作成した`create.blade.php`と同じ。

```(プロジェクト名)\app\Http\Controllers\UpdateController.php
class UpdateController extends Controller
{
    public function getIndex(Request $request)
    {
        $id = $request -> id;
        $table = DB::select('select * from sample');
        $data = Sample::find($id);
        $msg = 'Update  Sample Table [id = ' . $id . ']';
        return view('update', ['message' => $msg,'Table' => $table,'data' => $data]);
    }

    public function postIndex(Request $request)
    {
        $id = $request -> input('id');
        $data = Sample::find($id);
        $data -> name = $request -> input('name');
        $data -> pass = $request -> input('pass');
        $data -> create_day = $request -> input('day');
        $data->save();
        return redirect()->action('UpdateController@getindex');
    }
}
```

**`$id = $request -> id;`** で`URL`におけるクエリパラメータ(`~/~?id=123`などの`?`以降の部分)を取得している。
そこで取得した`$id`を **`モデル名::find()`** の引数に使用することで、**引数に一致するレコードをデータベースから取得**し、`$data`などのインスタンスに格納できるようにしている。
データベースのテーブルにおけるデータを更新する際は **`save()`** メソッドを使用する。

`(プロジェクト名)\routes\web.php`に下記のルーティング処理を実装し、実際にページを確認してみる。

```(プロジェクト名)\routes\web.php
Route::get('/update','UpdateController@getindex');
Route::post('/update','UpdateController@postindex');
```

`post`前: http://127.0.0.1:8000/update?id=7
フォームの内容を変更したい内容に変えてある。
![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/fa3a6722-0d26-92cf-7d75-1b3d1981df2d.jpeg)

`post`後
![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/9b326e25-e0a3-8894-0b2d-872a33df8003.jpeg)

#### Delete 
表示用のページとして`(プロジェクト名)\resources\views\`に`delete.blade.php`を作成し、`form`を次の内容に。
それ以外は`Create`で作成した`create.blade.php`と同じ。

```(プロジェクト名)\resources\views\delete.blade.php
    <form method="post" action="update">
        {{ csrf_field() }}
        <tr>
            <td>削除したいレコードのID:</td>
            <td>
                <input type="text" name="id" value="{{ optional($data)->id }}">
            </td>
        </tr>
        <tr>
            <td></td>
            <td><input type="submit"></td>
        </tr>
    </form>
```

削除したいレコードのIDを入力するフォームと送信ボタンだけでOK。

指定されたレコードをデータベースから削除する処理を記述する`DeleteController.php`は次のような内容。
`class`より上は`Create`で作成した`create.blade.php`と同じ。

```(プロジェクト名)\app\Http\Controllers\DeleteController.php
class DeleteController extends Controller
{
    public function getIndex(Request $request)
    {
        $data = DB::select('select * from sample');
        return view('update', ['message' => 'レコードの削除','data' => $data]);
    }

    public function postIndex(Request $request)
    {
        $id = $request -> input('id');
        $data = Sample::find($id);
        $data -> delete();
        return redirect()->action('DeleteController@getindex');
    }
}
```

`Create`,`Update`で使用したコントローラーの内容がわかっていれば **` $data -> delete();`** 以外説明することもない。
**` $data -> delete();`** も `Update`で使用した`save()`メソッドと同じような使い方をして、そのデータを削除する使い方をするものだという覚え方で問題はない。

いつも通り、`(プロジェクト名)\routes\web.php`に下記のルーティング処理を実装し、実際にページを確認してみる。

```(プロジェクト名)\routes\web.php
Route::get('/delete','DeleteController@getindex');
Route::post('/delete','DeleteController@postindex');
```

`post`前: http://127.0.0.1:8000/delete
![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/32733f56-dcb1-dfe8-5c26-35860ef9cc43.jpeg)

`post`後
![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/a4796ed8-83c3-d5d3-a8bc-aa277a3a719d.jpeg)


#### 番外編: バリデーション
`CRUD処理`の番外編としてバリデーションにも触れていく。
この機能は入力内容をチェックし、設定した条件を満たしているかどうかを判断するもので実装する方法は複数あるが、今回はフォームのバリデーションを実装する。
フォームのバリデーションは`Laravel`において、フォームリクエストと呼ばれる。
今回は`Update`で使用したファイル達に、このフォームリクエストを適用していく。

フォームリクエストは以下のコマンドをターミナルで実行して作成する。

```
$ php artisan make:request UpdateRequest(作成したいファイル名)
```

処理が完了すると`(プロジェクト名)\app\Http\Requests`に`UpdateRequest(作成したいファイル名).php`が作成される。
`UpdateRequest(作成したいファイル名).php`の各メソッドを次のように変更する。

```(プロジェクト名)\app\Http\Requests\UpdateRequest(作成したいファイル名).php
public function authorize()
    {
        return true;
    }

public function rules()
    {
        return [
            'name' => 'required|string|max:10',
            'pass' => 'required',
            'day' => 'required|string|max:10',
        ];
    }
```

バリデーションする条件の指定は、このように連想配列の形をとる。
どのような条件が指定できるかは[公式ドキュメント](https://readouble.com/laravel/5.7/ja/validation.html)に記載されているため、必要があれば確認を。

そしたら、`(プロジェクト名)\app\Http\Controllers\UpdateControllers.php`に作成したバリデーションを適用させていく。

```(プロジェクト名)\app\Http\Controllers\UpdateControllers.php

use App\Http\Requests;
use App\Http\Requests\UpdateRequest;

// 中略 

    public function postIndex(UpdateRequest $request)
    {

```

変更といっても、`use`の箇所に **`use App\Http\Requests\UpdateRequest;`** を追加、`public function postIndex(Request $request)`を **`public function postIndex(UpdateRequest $request)`** に変えるだけ。

これで http://127.0.0.1:8000/update?id=4 にアクセスして、フォームの中を全て空にして`送信`を押すと、最初の状態に戻り、バリデーションが効いていることがわかる。

ただ、エラーメッセージもなしに画面が遷移するのはわかりにくいので、表示用のページである`(プロジェクト名)\resources\views\update.blade.php`も変更する。


```(プロジェクト名)\resources\views\update.blade.php
// 略

    .alert{color:red;}
    </style>
</head>

// 中略


 </table>
    @if ($errors->any())
        <div class="alert">
          <ul>
              @foreach ($errors->all() as $error)
                  <li>{{ $error }}</li>
              @endforeach
          </ul>
        </div>
    @endif
</body>
```


これでバリデーションが適用された際、どのフォームが条件を満たしていないかが赤字で表示されるようになった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/5c0f4de1-ea7c-bd94-571d-9c5b5ec95e89.png)


### `Laravel`からテーブルを操作する
ここまでで`Laravel`側からデータベースのテーブルに対する操作ができることを学んだが、`Laravel`ではテーブルそのものを作成することもできる。

ここからは[Laravel入門 - 使い方チュートリアル - - Qiita](https://qiita.com/sano1202/items/6021856b70e4f8d3dc3d)と[Laravel5 チュートリアル ブログもどきを作る(1) DB設定・マイグレーション - Qiita](https://qiita.com/yumgoo17/items/e40e02b3fc3275bd7f23)シリーズを軸に進めていく。

#### マイグレーション
`Laravel`のテーブルそのものを作成する仕組み、それが **`マイグレーション`** だ。

まずはデータベースにテーブルを作成するためのマイグレーションファイルを作成するところから始まる。
今回は`laravels`というテーブル名で、それを作成するためのマイグレーションファイルを以下のコマンドをターミナルに入力して作成する。
**テーブル名の最後に`s`を忘れないように**。

```
$ php artisan make:migration laravels(作成したいマイグレーションファイル名) --create=laravels(作成したいテーブル名)
```

そうすると、`(プロジェクト名)\database\migrations`に`2020_08_06_095118_laravels(作成したいマイグレーションファイル名).php`が作成される。

```(プロジェクト名)\database\migrations\2020_08_06_095118_laravels(作成したいマイグレーションファイル名).php
<?php

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

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

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

**`public function up()`** にはテーブルを作成するときの処理が、**`public function down()`** にはテーブルを削除する処理が記載されている。
このまま、このファイルを実行してもテーブルを作成してもよいが、次のように少しカラムの設定を宣言してみる。

```(プロジェクト名)\database\migrations\2020_08_06_095118_laravels(作成したいマイグレーションファイル名).php
    public function up()
    {
        Schema::create('laravels', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name', 10);
            $table->timestamps();
        });
    }
```

この状態で`migration`が実行されると、次の設定が反映されたカラムになる。

| カラム名 |設定　         |
|:--------:|:-------------:|
|id        |AUTO_INCREMENT |
|name      |VARCHAR(10)    |
|create_at |timestamp      |
|update_at |timestamp      |

上でも説明したように、`create_at`と`update_at`のカラムは自動で作成され、`AUTO_INCREMENT`は自動挿入、`timestamp`は日時が自動で挿入される機能。

では、このファイルを実行して、テーブルを作成してみる。

ターミナルに次のコマンドを入力することで、マイグレーションファイルが実行される。

```
$ php artisan migrate
```

`phpMyAdmin`で確認してみる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/bee804e7-adb7-4be8-a11b-24d3dc7dc6bd.png)

**`migrate`**で**テーブルを作成する**`public function up()`の処理が行われた。
`public function down()`の処理は`migrate:rollback`や`migrate:reset`で実行する。

**`migrate:rollback`** は **最後に行ったマイグレーション操作を取り消す**。
**`migrate:reset`** は **全てのマイグレーションを削除する**。

#### シーディング
**`シーディング`** はテーブルの初期化やテストデータとなるレコードを挿入する`Laravel`の仕組み。
今回はこの仕組みを利用して、`マイグレーション`で作成した`migration`テーブルを初期化(最初のデータを挿入)する。

`シーディング`も`マイグレーション`同様、ファイルの作成から始めるが、その前にマイグレーションで作成したテーブルに対応するモデルの作成を行う。

```
$ php artisan make:model laravel(テーブル名の最後のs抜き)
```

マイグレーションの時のテーブル名における最後の文字に`s`を付けてもらった理由がここにある。
**モデル名はテーブル名の単数形にすることで自動的にテーブルを判断する機能がある。**
**`テーブル名: 複数形`**、**`モデル名: 単数形`**の命名規則を忘れないように。

ファイルを編集する必要はないので`(プロジェクト名)\app\`に`laravel(テーブル名の最後のs抜き).php`があるのを確認すればOK。

その後、ターミナルで下記のコマンドを実行。

```
$ php artisan make:seeder StudySeeder(作成したいシーディングファイル名)
```

そうすると、`(プロジェクト名)\database\seeds`に`StudySeeder(作成したいシーディングファイル名).php`が作成される。

```(プロジェクト名)\database\seeds\StudySeeder(作成したいシーディングファイル名).php
<?php

use Illuminate\Database\Seeder;

class StudySeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        //
    }
}
```

`migration`テーブルに挿入するデータは下の表。

| id |name       |create_at  |update_at  |
|:--:|:---------:|:---------:|:---------:|
|1   |Laravel    |作成日時   |作成日時   |
|2   |Migration  |作成日時   |作成日時   |
|3   |Seeding    |作成日時   |作成日時   |

`StudySeeder(作成したいシーディングファイル名).php`で、この表の内容を入力できるようにするには次の内容にする。

```(プロジェクト名)\database\seeds\StudySeeder(作成したいシーディングファイル名).php
public function run()
    {
        DB::table('laravels')->truncate();

        $table_data = [
        	['name' => 'Laravel'],
        	['name' => 'Migration'],
                ['name' => 'Seeding']
        ];

        foreach($table_data as $data) {
        	\App\laravel::create($data);
        }
    }
```

**`DB::table('laravels')->truncate();`** でシーディングの対象となるテーブルの指定と初期化。
**`$migrationdata~`** には連想配列の形式で入力したいレコードのデータを挿入。`id`,`create_at`,`update_at`は自動挿入されるようにテーブル側で設定されているため、`name`カラムだけ指定。
**`foreach($table_data as $data)~`** で挿入するデータを一つずつテーブルに挿入していく。
`\App\laravel::create();`の`laravel`部分は各自のモデル名に。

シーディングではコマンド実行時に同じディレクトリにある`DatabaseSeeder.php`を実行するため、このファイルも編集する。

```(プロジェクト名)\database\seeds\DatabaseSeeder.php
public function run()
    {
        $this->call(StudySeeder::class);
    }
```

`StudySeeder`の部分を各自のシーディングファイル名に変更。

以上で設定は終わりなのでシーディングを実行してみる。
シーディングの実行はターミナルで次のコマンドを叩く。

```
$ php artisan db:seed
```

`phpMyAdmin`を確認してみる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/4714dd33-f9da-c3b1-0001-5f3465df2964.png)


## Laravelシステム作成手順
今回の学習を踏まえて`Laravel`の作成手順をまとめる。


**0. `(プロジェクト名)\.env`にデータベース設定を記述**
**1. マイグレーションでテーブルを作成**
**2. シーディングでテーブルにデータ挿入**
**3. `(プロジェクト名)\resources\views\`に表示用のファイル、`blade`テンプレートを使用したファイルを作成**
**4. `(プロジェクト名)\app\Http\Controllers\`に3で作成したファイルへデータなどを渡すコントローラーを作成**
**5. バリデーション作成**
**6. `(プロジェクト名)\routes\web.php`でルーティング処理** 


## 次回の記事
今回は`Laravel`で簡易的なサイトが作れるようになるまでの基礎を学んだ。
次回の記事から、実際に作業をしながら`Laravel`の機能を学んでいく。
[Laravelでログイン機能付きサイト作成 with XAMPP(2/4)　認証機能の有効化編](https://qiita.com/kaitaku/items/13db4b60b7a4db6050af)


## 参考資料
- [初心者のためのLaravel入門 - libro](http://libro.tuyano.com/index2?id=3766003)
- [Laravel - Laravelで「"Attribute [controller] does not exist."」というエラーに困ってます。｜teratail](https://teratail.com/questions/107696)
- [Laravel5 チュートリアル ブログもどきを作る(2) ブログ記事投稿フォームの作成 - Qiita](https://qiita.com/yumgoo17/items/55152da02372dd203bcb)
- [PHPのアクセス修飾子public, protected, privateの違い | UX MILK](https://uxmilk.jp/26435)
- [【Laravel】Trying to get property フィールド名 of non-objectについて – ネコと征く戦場](https://neco.sakuratan.com/laravel-20190909/)
- [【Laravel5.8】FormRequestを使うとThis action is unauthorized.が吐き出される - Laravelとねころっけくん5.8](https://nekorokkekun.hatenablog.com/entry/2019/07/13/223834)
- [Laravel入門 - 使い方チュートリアル - - Qiita](https://qiita.com/sano1202/items/6021856b70e4f8d3dc3d)
- [Laravel5 チュートリアル ブログもどきを作る(1) DB設定・マイグレーション - Qiita](https://qiita.com/yumgoo17/items/e40e02b3fc3275bd7f23)シリーズ