Laravel 簡単なアプリケーション作成(1)

# Laravel 簡単なアプリケーション作成(1)
Laravelを利用して簡単なアプリケーションを作成する手順

## 環境
[前回作成した](https://qiita.com/kiyo-tomo/items/a812f96b3e7b9fa99652)sampleappを流用する。  

## 作成する画面、機能の概要

| ID | URL | 機能 |
|-----------|------------|------------|
| 1 | /home | トップ画面表示 |
| 2 | /auth/register | ユーザ登録およびメール送信 |
| 3 | /auth/login | Login |
| 4 | /auth/logout | Logout |

## トップ画面の作成

http://homestead.test/home  にアクセスしたらTop画面が表示されるようにする。

### ディレクトリ構成

```
(base) mbp:sampleapp username$ tree -d -L 1
.
├── app
├── bootstrap
├── config
├── database
├── public
├── resources
├── routes
├── storage
├── tests
└── vendor
```

ルーティング定義追加

```Php:routes/web.php
// add
Route::get('/home', function(){
	return view('home');
});
```

TOP画面のHTML作成(新規作成)

```Php:resources/home.blade.php
<html>
<head>
<meta charset='utf-8'>
</head>
<body>
Hello! World!
</body>
</html>
```

http://homestead.test/home  にアクセスしたらTop画面が表示される.


## テストフレームワーク PHPUnit を試してみる

Laravelには、PHPを代表するテストフレームワークである「PHPUnit」が同梱される。
以下の２つのテストを行う。

- トップ画面のHTTPステータスコードが200
- トップ画面のレスポンスに"Hell! World!"の文字列が含まれていること

### テストコードファイルの作成

```
(base) mbp:sampleapp username$ pwd
/Users/username/code/sampleapp
(base) mbp:sampleapp username$ php artisan make:test HomeTest
Test created successfully.
(base) mbp:sampleapp username$
```

生成されたテストファイル

```Php:tests/Feature/HomeTest.php
<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;

class HomeTest extends TestCase
{
    /**
     * A basic feature test example.
     *
     * @return void
     */
    public function testExample()
    {
        $response = $this->get('/');

        $response->assertStatus(200);
    }
}
```

以下に変更、追加

```Php:tests/Feature/HomeTest.php
<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;

class HomeTest extends TestCase
{
    /**
     * A basic feature test example.
     *
     * @return void
     */
    public function testExample()
    {
        $response = $this->get('/home');

        $response->assertStatus(200);
    }

    public function testBody(){
        $response = $this->get('/home');

        $response-> assertSeeText("Hell! World!");
    }
}

```

トップ画面のテストを実行

```
(base) mbp:sampleapp username$ pwd
/Users/username/code/sampleapp
(base) mbp:sampleapp username$ vendor/bin/phpunit tests/Feature/HomeTest.php
PHPUnit 7.5.9 by Sebastian Bergmann and contributors.

..                                                                  2 / 2 (100%)

Time: 100 ms, Memory: 14.00 MB

OK (2 tests, 2 assertions)
(base) mbp:sampleapp username$
```

## ユーザ登録の実装

ユーザ登録機能の実装を通じてリクエストの受信とバリデーション機能（検証、認可）に関して学ぶ。

### 手順概要

1. データベース準備
2. 認証/登録機能のコードを確認、ルーティングに追加
3. 登録画面を作成

### データベース準備

ユーザ情報を登録するテーブルを作成する。テーブル作成にはマイグレーション機能を利用する。  
マイグレーション機能とはデータベースのスキーマ作成やデータ投入などをプログラムコードを使って処理する機能。  
マイグレーションを行うためのファイルはdatabase/migrationsにある。

databaseディレクトリの内容

```
(base) mbp:sampleapp username$ tree database/
database/
├── factories
│   └── UserFactory.php
├── migrations
│   ├── 2014_10_12_000000_create_users_table.php
│   └── 2014_10_12_100000_create_password_resets_table.php
└── seeds
    └── DatabaseSeeder.php

3 directories, 4 files
```

マイグレーションファイル

```Php:2014_10_12_000000_create_users_table.php
<?php

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

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

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

```

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

vagrantで仮想環境にログイン

```
# cd ~/Homestead
# vagrant ssh

# cd ~/code/sampleapp/

vagrant@homestead:~/code/sampleapp$ php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table
vagrant@homestead:~/code/sampleapp$
```

MySQLに接続して作成したテーブルを確認する

```
vagrant@homestead:~/code/sampleapp$ mysql --host=localhost --user=homestead --password=secret homestead
mysql: [Warning] Using a password on the command line interface can be insecure.
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 5.7.25-0ubuntu0.18.04.2 (Ubuntu)

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show tables from homestead ;
+---------------------+
| Tables_in_homestead |
+---------------------+
| migrations          |
| password_resets     |
| users               |
+---------------------+
3 rows in set (0.00 sec)

mysql>
```

## 認証/登録機能をルーティングに追加

登録処理はコントローラーで処理する。コントローラーはMVCアーキテクチャを構成する要素の１つ。  
サービス利用者からの入力、受信結果を返却するためのビューの選択、生成などを担う。  


登録処理はRegisterControllerクラスの showRegistorationForm メソッドと registor メソッドで行う。  

ルーティング定義の追加

```php:routes/web.php
Route::get('auth/register', 'Auth\RegisterController@showRegistrationForm');
Route::post('auth/register', 'Auth\RegisterController@register');
```

### 登録画面の作成

resources/views/auth にregister.blade.php として保存

```php:resources/views/auth/register.blade.php
<html>
<head>
<meta charset='utf-8'>
</head>

<body>
<h1>ユーザ登録フォーム</h1>
<form name="registform" action="/auth/register" method="post">
    {{csrf_field()}}
    名前：<input type="text" name="name" size="30"><span>{{ $errors->first('name') }} </span><br />
    メールアドレス：<input type="text" name="email" size="30"><span>{{ $errors->first('email') }} </span><br />
    パスワード：<input type="password" name="password" size="30"><span>{{ $errors->first('password') }} </span><br />
    パスワード(確認)：<input type="password" name="password_confirmation" size="30"><span>{{ $errors->first('password_confirmation') }} </span><br />
    <button type='submit' name='action' value='send'>送信</button>
</form>
</body>

</html>
```

TOP画面を変更する

```php:resources/views/home.blade.php
<html>
<head>
<meta charset='utf-8'>
</head>
<body>
Hello!

@if (Auth::check())
    {{\Auth::user()->name}}さん
@else
    ゲストさん<br />
    <a href="/auth/register">会員登録</a>
@endif
</body>
</html>
```

TOP画面にアクセスし、ユーザ登録フォームが表示されることを確認する。
試しに適当な値を入力し、送信ボタンを押し、 /home のページにリダイレクトされ、ログイン後の画面が表示される事を確認する。

最後に、DBに登録されたデータを確認してみる。

```
vagrant@homestead:~$ mysql --host=localhost --user=homestead --password=secret homestead
mysql: [Warning] Using a password on the command line interface can be insecure.
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 16
Server version: 5.7.25-0ubuntu0.18.04.2 (Ubuntu)

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> select * from users;
+----+-----------------+----------------------+-------------------+--------------------------------------------------------------+----------------+---------------------+---------------------+
| id | name            | email                | email_verified_at | password                                                     | remember_token | created_at          | updated_at          |
+----+-----------------+----------------------+-------------------+--------------------------------------------------------------+----------------+---------------------+---------------------+
|  1 | xxx | xxxx.com | NULL              | xxxxx| NULL           | 2019-05-01 08:44:24 | 2019-05-01 08:44:24 |
+----+-----------------+----------------------+-------------------+--------------------------------------------------------------+----------------+---------------------+---------------------+
1 row in set (0.00 sec)

mysql>
```


## ユーザ認証

ログイン機能とログアウト機能を実装する

ルーティング追加

```php:routes/web.php
// Login Form
Route::get('/auth/login', 'Auth\LoginController@showLoginForm');
Route::post('/auth/login', 'Auth\LoginController@login');

// Logout
Route::get('/auth/login', 'Auth\LoginController@logout');
```

ログインフォーム実装

```php:resources/views/auth/login.blade.php
<html>
<head>
<meta charset='utf-8'>
</head>

<body>
<h1>ログインフォーム</h1>

@isset($mesage)
    <p style="color:red">{{$message}}</p>
@endisset

<form name="loginform" action="/auth/login" method="post">
    {{csrf_field()}}
    mailaddress: <input type="text" name="email" size="30" value="{{old('email')}}"><br />
    password: <input type="password" name="password" size="30"><br />
    <button type='submit' name='action' value='send'>Login</button>
</form>
</body>

</html>
```

TOP画面にログアウト機能を追加

```php:views/home.blade.php
<html>
<head>
<meta charset='utf-8'>
</head>
<body>
Hello!

@if (Auth::check())
    {{\Auth::user()->name}}さん<br />
    <a href="/auth/logout">Logout</a>
@else
    ゲストさん<br />
    <a href="/auth/login">Login</a><br />
    <a href="/auth/register">会員登録</a>
@endif
</body>
</html>
```

ログアウト後の遷移先を変更する

/app/Http/Controllers/Auth/LoginController.php に以下のメソッドをオーバライドする

```php:/app/Http/Controllers/Auth/LoginController.php
    // Override
    public function logout(\Illuminate\Http\Request $request)
    {
        $this->guard()->logout();

        $request->session()->invalidate();

        // return $this->loggedOut($request) ?: redirect('/');
        return $this->loggedOut($request) ?: redirect('/home');
    }
```

元は sampleapp/vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesUsers.php 
に定義されるメソッドだが、vendor/ 以下に直接変更を加えず、オーバライドしておこう