# Laravel授業最終回
## 環境構築(先週の復習)
### 【環境構築(bashコマンド)】
#### 1. PHPセットアップ
`sudo amazon-linux-extras install php7.2=stable`
`sudo yum install php-mbstring php-pecl-memcached php-gd php-apcu php-xml`
#### 2. データベースの準備
#### MaryaDB 構築
`sudo amazon-linux-extras install -y lamp-mariadb10.2-php7.2`
#### MariaDBのインストール
`sudo yum install -y mariadb-server`
#### 3. MariaDBの起動&初期設定
`sudo systemctl start mariadb`
`sudo mysql_secure_installation`
```
初回設定の入力項目
Set root password? [Y/n] y
New password: root
Re-enter new password: root
Remove anonymous users? [Y/n] y
Disallow root login remotely? [Y/n] y
Remove test database and access to it? [Y/n] y
Reload privilege tables now? [Y/n] y
```
#### MaridaDBの自動起動を有効化
`sudo systemctl enable mariadb`
`sudo systemctl is-enabled mariadb`
#### 4. Composerインストール
`curl -sS https://getcomposer.org/installer | php -- --version=2.1.6`
`sudo mv composer.phar /usr/bin/composer`
`composer`
#### 5. Laravelインストール
`composer create-project laravel/laravel cms 6.* --prefer-dist`
#### 6. サーバーの起動とLaravelプロジェクトの起動チェック
#ディレクトリ移動
`cd cms`
#### #BuiltInサーバーを起動:動作確認
`php artisan serve --port=8080`
```
*Cloud9の画面上部の緑の起動ボタンの左側Previewボタン>Preview Running Applicationをクリック
右下に画面が起動してLaravelの文字が確認できたらOK
```
### 【データベースの作成】
`mysql -u root -p`
`root [Enterキー]`
`create database c9;`
`show databases; `
`exit;`
### 【Laravelプロジェクト初期設定】
#### 1. env(ファイル内の同じ箇所を上書き)
```
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=c9
DB_USERNAME=root
DB_PASSWORD=root
```
#### 2. サーバー再起動(cms階層で)
Ctrl + C
php artisan serve --port=8080
#### 3. /app/Providers/ AppServiceProvider.php ファイルを修正
```
use Illuminate\Support\Facades\Schema; //この行を追加
use Illuminate\Support\Facades\URL; //この行を追加
public function boot() {
Schema::defaultStringLength(191); //この行を追加
URL::forceScheme('https'); //この行を追加
}
```
#### 4. 表示の仕組みをチェックしてみる!
#4-1 /resouces/views/welcome.blade.php を編集して見よう!
#4-2 ブラウザ・更新で確認 → 変更確認できればOK
### 【phpMyAdmin設定】
#### 1. cms階層からpublicフォルダに移動
`cd public`
#### 2. phpMyAdminのzipをダウンロード
`wget https://files.phpmyadmin.net/phpMyAdmin/4.8.3/phpMyAdmin-4.8.3-all-languages.zip`
#### 3. zipファイルを解凍
`unzip phpMyAdmin-4.8.3-all-languages.zip`
#### 4. cms階層に戻る
`cd ..`
```
<手順解説>
1 publicフォルダ内に「phpMyAdmin-4.8.3-all-languages」フォルダが作成される
2 フォルダ名が長いので「phpMyAdmin」に変更
3「Preview」でサイトを開き、URLの最後に「phpMyAdmin/index.php」をつけてEnterキーを押す
4 URL例: https://******.cloud9.us-east-1.amazonaws.com/phpMyAdmin/index.php
5 phpMyAdmin画面が表示されたら: ユーザー名・パスワードともに「root」を入力してログイン
6 ログインできればOK
```
## ログイン認証
### 【ログイン認証実装】
#### 1. マイグレーションを実行
`php artisan migrate`
#### 2. laravel/ui パッケージをインストール
`composer require laravel/ui:^1.0 --dev`
#### 3. artisan コマンドを実行
`php artisan ui vue --auth`
#### 4. npmパッケージをインストール
`npm install`
#### 5. パッケージをビルド
`npm run dev`
## APIを使ったCRUDの作成
### テーブルの作成(Bookモデルとbooks_tableを作成します)
#### 1. モデル作成とセットでマイグレーションファイルも作成する
`php artisan make:model Book -m`
#### 2. booksのマイグレーションファイルの中に以下を追記
```
public function up()
{
Schema::create('books', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('title');//追記
$table->text('body');//追記
$table->timestamps();
});
}
```
#### 3. マイグレーション実行
`php artisan migrate`
### モデル、コントローラー、ルーティングを作っていく
#### 1. API階層とBooksコントローラーを作成する(API用のメソッドとモデルを自動で設定)
`php artisan make:controller Api/BooksController --resource --model=Book`
#### 2. routes/api.phpにルーティングを記述
```
// books用のAPIルーティング
Route::group(['middleware' => ['api']], function(){
Route::resource('books', 'Api\BooksController');
});
```
#### 3. ルーティング一覧を見てみる
`php artisan route:list`
こんな感じになってるはず
```
+--------+-----------+-----------------------+---------------+--------------------------------------------------+--------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+-----------+-----------------------+---------------+--------------------------------------------------+--------------+
| | GET|HEAD | / | | Closure | web |
| | GET|HEAD | api/books | books.index | App\Http\Controllers\Api\BooksController@index | api |
| | POST | api/books | books.store | App\Http\Controllers\Api\BooksController@store | api |
| | GET|HEAD | api/books/create | books.create | App\Http\Controllers\Api\BooksController@create | api |
| | GET|HEAD | api/books/{book} | books.show | App\Http\Controllers\Api\BooksController@show | api |
| | PUT|PATCH | api/books/{book} | books.update | App\Http\Controllers\Api\BooksController@update | api |
| | DELETE | api/books/{book} | books.destroy | App\Http\Controllers\Api\BooksController@destroy | api |
| | GET|HEAD | api/books/{book}/edit | books.edit | App\Http\Controllers\Api\BooksController@edit | api |
| | GET|HEAD | api/user | | Closure | api,auth:api |
+--------+-----------+-----------------------+---------------+--------------------------------------------------+--------------+
```
各メソッド大まかな役割分担
```
index -> 一覧表示(対象のテーブルのデータを全件取得とか)
store -> テーブルに対してデータを登録する
create -> データ登録画面を表示する
show -> 特定IDの1件のデータを取得し表示する
update -> データの更新処理
destroy -> データの削除処理
edit -> データの更新画面を表示する
```
#### 4. APIは画面表示ルーティングは不要なので【create】と【edit】はroutes/api.phpから削除
```
Route::group(['middleware' => ['api']], function(){
Route::resource('books', 'Api\BooksController', ['except' => ['create', 'edit'] ]);
});
```
#### 5. 再度ルーティング一覧を確認
`php artisan route:list`
削除したメソッドのルーティングが消えているはず
```
+--------+-----------+------------------+---------------+--------------------------------------------------+--------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+-----------+------------------+---------------+--------------------------------------------------+--------------+
| | GET|HEAD | / | | Closure | web |
| | GET|HEAD | api/books | books.index | App\Http\Controllers\Api\BooksController@index | api |
| | POST | api/books | books.store | App\Http\Controllers\Api\BooksController@store | api |
| | GET|HEAD | api/books/{book} | books.show | App\Http\Controllers\Api\BooksController@show | api |
| | PUT|PATCH | api/books/{book} | books.update | App\Http\Controllers\Api\BooksController@update | api |
| | DELETE | api/books/{book} | books.destroy | App\Http\Controllers\Api\BooksController@destroy | api |
| | GET|HEAD | api/user | | Closure | api,auth:api |
+--------+-----------+------------------+---------------+--------------------------------------------------+--------------+
```
### CRUD処理を作っていく
#### 1. indexメソッド(一覧表示)
```
public function index()
{
$books = Book::all();
return $books;
}
```
#### 2. storeメソッド(登録処理)
```
public function store(Request $request)
{
$book = new Book;
$book->title = $request->title;
$book->body = $request->body;
$book->save();
}
```
#### 3. showメソッド(特定IDのみ取得)
```
public function show(Book $book)
{
return $book;
}
```
#### 4. updateメソッド(更新処理)
```
public function update(Request $request, Book $book)
{
$book->title = $request->title;
$book->body = $request->body;
$book->save();
return $book;
}
```
#### 5. destroyメソッド(削除処理)
```
public function destroy(Book $book)
{
$book->delete();
}
```
### AWS Cloud9で外部アクセスができるように設定変更
#### 1. 自分のパブリック IP アドレスを取得
`curl http://169.254.169.254/latest/meta-data/public-ipv4`
表示されたIDをメモなどにコピペしておく
#### 2. エディターの右上アイコンからManage EC2 Instanceをクリック
表示されている自分のインスタンスIDのリンクをクリック
#### 3. セキュリティのタブをクリックしセキュリティグループのリンクをクリック
#### 4. 下部の右側インバウンドルールを編集をクリックしてルールを追加をクリック
```
タイプ:カスタム TCP
プロトコル:TCP
ポート範囲:8080
ソース:任意の場所
```
に設定してルールを保存をクリック
#### 5. 左側のリストの中のインスタンスをクリックし実行中のインスタンスを選択
#### 6. サブネットIDをコピー
#### 7. 上の検索タブからVPCを検索してクリック
#### 8. 左側のリストからサブネットをクリック
#### 9. さっきコピーしたサブネットを検索(⌘+F)してリンクをクリック
#### 10. 下部ネットワークACLタブを開きネットワークACL:横のリンクをクリック
#### 11. さらにリンクをクリック
#### 12. インバウンドルールを編集をクリックして新しいルールを追加
```
ルール番号:200
タイプ:カスタムTCP
プロトコル:TCP
ポート範囲:8080
送信元:0.0.0.0/0
許可/拒否:許可
```
#### 13. サーバーを再起動
`Ctrl + C`
`php artisan serve --port=8080 --host 0.0.0.0`
*ホストを0.0.0.0にするのがポイント!!
## PostmanでAPIのテスト
#### 1. postmanにアクセスしてログイン
https://identity.getpostman.com/login
#### 2. Workspaces>MyWorkspaceに入る
#### 3. リクエストを作ってみる(Overviewの横のプラスボタンから新規タブ)
GETメソッドで以下のURLを作成して貼り付け
`http://{自分のcloud9 の IP アドレス}:8080/api/books`
例:`http://52.6.254.192:8080/api/books`
SendをクリックしてみてエラーがなければOK
#### 4. メソッドをPOSTに変更してデータを登録してみる
POSTメソッド
`http://{自分のcloud9 の IP アドレス}:8080/api/books`
例:`http://52.6.254.192:8080/api/books`
真ん中あたりのBodyからform-dataをクリックして以下を入力
```
KEY | VALUE
--------------
title | テスト
body | サンプル
```
Sendを押して登録→別タブでGETで全件取得してみる
#### 5. UpdateメソッドをPOSTでデータ更新してみる
POSTメソッド
`http://{自分のcloud9 の IP アドレス}:8080/api/books/{本のid}`
例:`http://52.6.254.192:8080/api/books/1`
```
KEY | VALUE
--------------
title | テスト
body | サンプル
_method | PUT
```
Sendしてリターンをチェック
## PassPortを使ったAPI認証
### Passportをインストール
#### 1. laravel passportのパッケージをインストール
`composer require laravel/passport`
#### 2. マイグレーションを実行
`php artisan migrate`
#### 3. install実行
`php artisan passport:install`
### 諸々の設定
#### 1. app/User.phpにHasApiTokensを追加
```
<?php
namespace App;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens; //追記
class User extends Authenticatable
{
use HasApiTokens , Notifiable; //変更
省略
}
```
#### 2. app/Providers/AuthServiceProvider.phpにPassportを呼び出す
```
<?php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
use Laravel\Passport\Passport; //追記
class AuthServiceProvider extends ServiceProvider
{
省略
public function boot()
{
$this->registerPolicies();
Passport::routes(); //追記
}
}
```
#### 3.config/auth.phpのapiをpassportに変更 app/Providers/AuthServiceProvider.phpにPassportを呼び出す
```
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',<-ここを変更
'provider' => 'users'
],
],
```
### トークン発行処理を作成
#### 1. コントローラー作成
`php artisan make:controller Api/AuthController
`
#### 2. login処理を作成
```
public function login(Request $request) {
$credentials = $request->only('email', 'password');
if(auth()->attempt($credentials)) {
$user = auth()->user();
$token = $user->createToken('Laravel Password Grant Client')->accessToken;
return ['token' => $token];
}
return response([
'message' => 'Unauthenticated.'
], 401);
}
```
### ルーティングとPostmanでテスト
#### 1. routes/api.phpに以下を追記
`Route::post('/login', 'Api\AuthController@login');`
#### 2. POSTメソッドで以下のURLにテストデータを送ってみる
*事前にユーザーを1名登録しておく
POSTメソッドでapi/loginにリクエスト
`http://{自分のcloud9 の IP アドレス}:8080/api/login`
例:`http://3.85.177.52:8080/api/login`
bodyのform-dataに以下のデータをセットしてSend
```
KEY | VALUE
--------------
email | test@test.jp
password | testtest
```
戻り値でtokenが戻ってくれば成功
#### 3. 認証済みのユーザーのみデータが取得できるAPIを叩く
GETメソッドでapi/userにリクエスト
`http://{自分のcloud9 の IP アドレス}:8080/api/user`
例:`http://3.85.177.52:8080/api/user`
Headersに以下のデータをセットしてSend
```
KEY | VALUE
--------------
Accept | application/json
Authorization | Bearer さっきのトークン
```
ポイントは半角スペース
`「Bearer 123456789」`
これでログインユーザー情報が返ってきたら成功
## APIでのリレーション
### テーブルとモデルをリレーション用に修正
#### 1. booksテーブルにカラム追加
`php artisan make:migration add_user_id_to_books_table --table=books`
#### 2. マイグレーションファイルに以下を追加
```
public function up()
{
Schema::table('books', function (Blueprint $table) {
$table->integer('user_id'); //カラム追加
});
}
```
#### 3. マイグレーション実行
`php artisan migrate`
#### 4. リレーションをモデルに記述
##### 1 App/User.phpの中の39行目を改行して以下の内容をコピー
```
// booksテーブルとのリレーション (主テーブル側)
public function books() {
return $this->hasMany('App\Book');
}
```
##### 2 App/Book.phpの中の9行目を改行して以下の内容をコピー
```
// Userテーブルとのリレーション (従テーブル側)
public function user() {
return $this->belongsTo('App\User');
}
```
#### 5. routes/api.phpの/userのルーティングを以下に変更
```
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user()->with('books')->get(); //変更した部分
});
```
#### 6 Postmanでテストしてみる
GETメソッドでapi/userにリクエスト
`http://{自分のcloud9 の IP アドレス}:8080/api/user`
`例:http://3.85.177.52:8080/api/user`
Headersに以下のデータをセットしてSend
```
KEY | VALUE
--------------
Accept | application/json
Authorization | Bearer さっきのトークン
```
ポイントは半角スペース
「Bearer 123456789」
これでログインユーザーの保持しているbooksの情報が返ってくれば成功
#### 7. BooksControllerのstoreをいかに変更
```
public function store(Request $request)
{
$book = new Book;
$book->title = $request->title;
$book->body = $request->body;
$book->user_id = Auth::id(); //追記
$book->save();
}
```
#### 8. routes/api.phpのbooksのルーティングを以下に変更
```
// books用のAPIルーティング
Route::group(['middleware' => ['auth:api']], function(){
Route::resource('books', 'Api\BooksController',[ 'except' => ['create', 'edit'] ]);
});
```
これで本のCRUDはログイン済みユーザーのみ使える機能になりました。