# Laravel授業2回目(PaizaCloud版)
## 環境構築(先週の復習)
### 【サーバーの立ち上げ】
#### 1. ログインが完了したら新規サーバ作成をクリックするボタンが表示されます。以下の設定でサーバー作成
```
サーバ名:デフォルトでOK
web開発:PHP,Laravel
データベース:MySQL,phpMyAdmin
その他は設定不要
```
新規作成ボタンをクリック
### 【Laravelプロジェクトの立ち上げ】
#### 1. ターミナルを立ち上げてLaravelプロジェクト作成コマンドを入力
`composer create-project laravel/laravel cms 6.* --prefer-dist`
#### 2. cms(プロジェクトディレクトリ)にターミナル上で移動
`cd cms`
#### 3. ターミナル上CMS階層でComposerコマンド実行
`sudo composer update`
#### 4. ターミナル上CMS階層でBuiltInサーバーを起動:動作確認
`php artisan serve`
server startedと表示されてURLが生成されればOKです。
左側に地球で8000番ポートでプロジェクトが立ち上がっているはずです。
ブラウザで確認までいきましょう。
## VSCodeからSSH接続で開発できる環境を作る
### 【PaizaCloud上での設定】
#### 1. PaizaCloud上でターミナルを新規で開いて公開鍵・秘密鍵を生成するコマンドを実行
`ssh-keygen -f ~/id_rsa`
#### 2. 生成された「id_rsa」と「id_rsa.pub」の二つのファイルをダウンロード
#### 3. 公開鍵を表示してコピー
`$cat id_rsa.pub `
実行結果
```
$cat id_rsa.pub
↓ここから
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC7Th1CAeSpQVsE9UheYi0Vpw+bcKxEqjooIHhaXLow2whnRRDnsSejaMVxH6OyTx81J5wlqTq/UXaViPMAeB5・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
↑ここまでコピー
.ssh ユーザー名$
```
#### 4. PaizaCloudの左側メニューからSSH設定を開いてSSHkeyの部分に先程コピーした公開鍵を貼り付けてSAVE
この作業でPaziaCloud上の作業は終了です。
### 【ローカルPC(自分のパソコン)での設定】
#### 1. ローカル(自分のPC)で自分のOSにあった以下のフォルダの階層から「.ssh」フォルダを開く
表示されない場合は隠しファイル表示のショートカットキーは「command」+「shift」+「.」 です。
winはタスクバーからエクスプローラーを開いて[表示]>[表示]>[隠しファイル]を選択します。
ない場合は自分で作成してOKです。
```
Windows C:\Users\ユーザ名\.ssh
Mac /Users/ユーザ名/.ssh
```
#### 2. 「.ssh」フォルダの中にpaizaというフォルダを作成
```
Windows C:\Users\ユーザ名\.ssh\paiza
Mac /Users/ユーザ名/.ssh/paiza
```
#### 3. さっきダウンロードしてきた「id_rsa」と「id_rsa.pub」をpaizaの中に移動
```
【Windows】
C:\Users\ユーザ名\.ssh\paiza\id_rsa
\id_rsa.pub
【Mac】
/Users/ユーザ名/.ssh/paiza/id_rsa
/id_rsa.pub
```
#### 4. ターミナルで以下のコマンドを実行(権限を付与)
`chmod 600 .ssh/paiza/id_rsa`
#### 5. VSCodeで拡張機能の「Remote Development」を探して有効化
#### 6. VSCodeのSSH設定用のファイルを開く
VSCodeの画面左下の歯車アイコンからコマンドパレットを起動
コマンドパレットから「>Remote-SSH: Open configuration File」を実行
下記のファイルを開く
```
Windows C:\Users\ユーザ名\.ssh\config
Mac /Users/ユーザ名/.ssh/config
```
#### 7. SSH設定に書き変える
paizacloudのSSH設定のSSH CommandのURLが個々人の接続コマンドです。
ここから情報をコピペで作業してください。
```
# Read more about SSH config files: https://linux.die.net/man/5/ssh_config
Host paiza-cloud
HostName 自分で決めたサーバー名.paiza-user-lite.cloud
User ubuntu
Port -pの次の数字 59123など、環境によって変わります
IdentityFile ~/.ssh/paiza/id_rsa
```
変更できたら保存
#### 8. リモートアクセス
画面左下の歯車アイコンからコマンドパレットを起動
コマンドパレットから「>Remote-SSH: >Remote-SSH: Connect to Host」を選択するとさっき作ったpaiza-cloudが選択できるのでクリック
新しいタブが開けばOK。
#### 9. フォルダを開いてみる
左側のファイルツリーから「Open Folder」をクリックし、デフォルトでホームディレクトリ /home/ubuntu が選択されているので先ほど作ったcmsを選択してOKを押してみましょう。
## 共通初期設定
### 【Laravelプロジェクト初期設定】
#### 1. データベースを作成
エディタ左側の一番上に🔽ボタンをクリックすると下の方にMySQLがあるのでStart MySQLをクリックしてMySQlを起動
phpMyAdminのタブ内のOpen phpMyAdminをクリックして起動
phpMyAdminの管理画面からc9というデータベースを作成。
```
DB名:c9
照合順:utf8mb4_general_ci
```
#### 2. env(ファイル内の同じ箇所を上書き)
*隠しファイル表示はエディタ左側ファイル階層で右クリック
```
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=c9
DB_USERNAME=root
DB_PASSWORD=
```
#### 3. /app/Providers/AppServiceProvider.php ファイルを修正
```
use Illuminate\Support\Facades\URL; //この行を追加
public function boot() {
URL::forceScheme('https'); //この行を追加
}
```
#### 4. サーバーの再起動
envファイルなどの設定を書き換えたときは必ず再起動!!
サーバー起動後のターミナル上で
`Ctrl + C`
#### 5. 表示の仕組みをチェックしてみる!
#4-1 /resouces/views/welcome.blade.php を編集して見よう!
#4-2 ブラウザ・更新で確認 → 変更確認できれば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`
## リレーション(1対多)
1人のユーザーは複数の投稿ができる機能
### 【データベースに新しいテーブルを作成する為にマイグレーション を作成】
#### 1. artisanコマンドでマイグレーション 作成
`php artisan make:migration create_posts_table --create=posts`
#### 2. database/migrationsの直下のposts_table.phpに以下追記
```
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('post_title');
$table->string('post_desc');
$table->integer('user_id');
$table->timestamps();
});
}
```
#### 3. マイグレーション実行(テーブルの作成)
`php artisan migrate`
### 【モデルの作成】
#### 1. artisanコマンドでモデル作成
`php artisan make:model Post`
### 【モデルにリレーションの設定を記述】
#### 1. App/User.phpの中の39行目を改行して以下の内容をコピー
```
// Postsテーブルとのリレーション (主テーブル側)
public function posts() {
return $this->hasMany('App\Post');
}
```
#### 2. App/Post.phpの中の9行目を改行して以下の内容をコピー
```
// Userテーブルとのリレーション (従テーブル側)
public function user() {
return $this->belongsTo('App\User');
}
```
### 【投稿画面の作成】
#### 1. viewsの直下にposts.blade.phpを作成して以下の内容をコピペ
```
<!-- resources/views/posts.blade.php -->
@extends('layouts.app')
@section('content')
<!-- Bootstrapの定形コード… -->
<div class="card-body">
<div class="card-title">
投稿フォーム
</div>
<!-- バリデーションエラーの表示に使用-->
@include('common.errors')
<!-- バリデーションエラーの表示に使用-->
<!-- 投稿フォーム -->
<form action="{{ url('posts') }}" method="POST" class="form-horizontal">
{{ csrf_field() }}
<!-- 投稿のタイトル -->
<div class="form-group">
投稿のタイトル
<div class="col-sm-6">
<input type="text" name="post_title" class="form-control">
</div>
</div>
<!-- 投稿の本文 -->
<div class="form-group">
投稿の本文
<div class="col-sm-6">
<input type="text" name="post_desc" class="form-control">
</div>
</div>
<!-- 登録ボタン -->
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6">
<button type="submit" class="btn btn-primary">
Save
</button>
</div>
</div>
</form>
</div>
<!-- 全ての投稿リスト -->
@endsection
```
#### 2. /resources/views/common/errors.blade.php を作成 し以下を追記
```
<!-- resources/views/common/errors.blade.php -->
@if (count($errors) > 0)
<!-- Form Error List -->
<div class="alert alert-danger">
<div><strong>入力した文字を修正してください。</strong></div>
<div>
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
</div>
@endif
```
### 【投稿画面表示処理の実装】
#### 1. postsコントローラーを作成
```
php artisan make:controller PostsController --resource
```
#### 2. postsコントローラー内にモデルの呼び出しをした上でindexメソッドに投稿表示処理を記述
```
use App\Post; //この行を上に追加
use App\User;//この行を上に追加
use Auth;//この行を上に追加
use Validator;//この行を上に追加
public function index()
{
//
return view('posts');
}
```
#### 3. web.phpにルーティングを追記
```
Route::get('/', 'PostsController@index');
```
#### 4. posts.blade.phpのフォームを以下のタグで囲んでログインユーザーしか投稿できないようにする
```
@if( Auth::check() )
<form action="{{ url('posts') }}" method="POST" class="form-horizontal">
=== ここは省略してます。===
</form>
@endif
```
### 【投稿処理の実装】
#### 1. web.phpにルーティングを追記
`Route::post('posts', 'PostsController@store');`
#### 2. postsコントローラー内のstoreメソッドに登録処理を記述
```
public function store(Request $request)
{
//バリデーション
$validator = Validator::make($request->all(), [
'post_title' => 'required|max:255',
'post_desc' => 'required|max:255',
]);
//バリデーション:エラー
if ($validator->fails()) {
return redirect('/')
->withInput()
->withErrors($validator);
}
//以下に登録処理を記述(Eloquentモデル)
$posts = new Post;
$posts->post_title = $request->post_title;
$posts->post_desc = $request->post_desc;
$posts->user_id = Auth::id();//ここでログインしているユーザidを登録しています
$posts->save();
return redirect('/');
}
```
### 【投稿の一覧表示処理を実装】
#### 1. posts.blade.php内42行目に以下を記述して表示エリア作成
```
@if (count($posts) > 0)
<div class="card-body">
<div class="card-body">
<table class="table table-striped task-table">
<!-- テーブルヘッダ -->
<thead>
<th>投稿一覧</th>
<th> </th>
</thead>
<!-- テーブル本体 -->
<tbody>
@foreach ($posts as $post)
<tr>
<!-- 投稿タイトル -->
<td class="table-text">
<div>{{ $post->post_title }}</div>
</td>
<!-- 投稿詳細 -->
<td class="table-text">
<div>{{ $post->post_desc }}</div>
</td>
<!-- 投稿者名の表示 -->
<td class="table-text">
<div></div>
</td>
<!-- お気に入りボタン -->
<td class="table-text">
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
@endif
```
#### 2. postコントローラー内のindexメソッドを以下のように変更してログインユーザーと紐付く投稿を取得する
```
public function index()
{
// 全ての投稿を取得
$posts = Post::get();
return view('posts',[
'posts'=> $posts
]);
}
```
#### 3. posts.blade.php内63行目を以下のように変更して投稿したユーザー名を表示
```
<!-- 投稿者名の表示 -->
<td class="table-text">
<div>{{ $post->user->name }}</div>
</td>
```
## リレーション(多対多) 投稿をお気に入り機能
### 【データベースに中間テーブルを作成する為にマイグレーションを作成】
#### 1. artisanコマンドでマイグレーション 作成
`php artisan make:migration create_post_user_table --create=post_user`
#### 2. database/migrationsの直下のpost_user_table.phpに以下追記
```
public function up()
{
Schema::create('post_user', function (Blueprint $table) {
$table->increments('id');
$table->unsignedBigInteger('user_id');
$table->unsignedBigInteger('post_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); //外部キー参照
$table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade'); //外部キー参照
$table->unique(['user_id', 'post_id'],'uq_roles'); //Laravelは複合主キーが扱いにくいのでユニークで代用
});
}
```
#### 3. マイグレーション実行(テーブルの作成)
`php artisan migrate`
### 【モデルにリレーション設定】
#### 1. App/User.phpに以下の内容を追記
```
// Postsテーブルとの多対多リレーション
public function favo_posts() {
return $this->belongsToMany('App\Post');
}
```
#### 2. App/Post.phpに以下の内容を追記
```
// Userテーブルとの多対多リレーション
public function favo_user() {
return $this->belongsToMany('App\User');
}
```
### 【お気に入りボタン&お気に入り処理実装】
#### 1. posts.blade.phpの69行名お気に入りボタンのtdタグ内に以下をコピペ
```
<form action="{{ url('post/'.$post->id) }}" method="POST">
{{ csrf_field() }}
<button type="submit" class="btn btn-danger">
お気に入り
</button>
</form>
```
#### 2.web.phpにルーティングを追加
`Route::post('post/{post_id}', 'PostsController@favo');`
#### 3. postコントローラーに新規でメソッドを作成
```
public function favo($post_id)
{
}
```
#### 4. favoメソッドに以下に処理を追記
```
public function favo($post_id)
{
//ログイン中のユーザーを取得
$user = Auth::user();
//お気に入りする記事
$post = Post::find($post_id);
//リレーションの登録
$post->favo_user()->attach($user);
return redirect('/');
}
```
### 【お気に入り表示リストを作成】
#### 1. post.blade.phpの@endsectionのすぐ上にログインユーザーのみの表示エリアを設定
```
@if( Auth::check() )
=== ここに表示処理を作成 ===
@endif
```
#### 2. 作成したエリアの間に以下をコピペ
```
@if (count($favo_posts) > 0)
<div class="card-body">
<div class="card-body">
<table class="table table-striped task-table">
<!-- テーブルヘッダ -->
<thead>
<th>お気に入り一覧</th>
<th> </th>
</thead>
<!-- テーブル本体 -->
<tbody>
@foreach ($favo_posts as $favo_post)
<tr>
<!-- 投稿タイトル -->
<td class="table-text">
<div>{{ $favo_post->post_title }}</div>
</td>
<!-- 投稿詳細 -->
<td class="table-text">
<div>{{ $favo_post->post_desc }}</div>
</td>
<!-- 投稿者名の表示 -->
<td class="table-text">
<div>{{ $favo_post->user->name }}</div>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
@endif
```
#### 3. postコントローラーのindexメソッドを以下のように変更
```
public function index()
{
// 全ての投稿を取得
$posts = Post::get();
if (Auth::check()) {
//ログインユーザーのお気に入りを取得
$favo_posts = Auth::user()->favo_posts()->get();
return view('posts',[
'posts'=> $posts,
'favo_posts'=>$favo_posts
]);
}else{
return view('posts',[
'posts'=> $posts
]);
}
}
```
#### 4. お気に入りボタンの表示を切り分けたいのでposts.blade.phpのボタンエリアを以下のように変更
```
@if(Auth::check())
@if(Auth::id() != $post->user_id && $post->favo_user()->where('user_id',Auth::id())->exists() !== true)
<form action="{{ url('post/'.$post->id) }}" method="POST">
{{ csrf_field() }}
<button type="submit" class="btn btn-danger">
お気に入り
</button>
</form>
@endif
@endif
```
## テストデータ自動生成 seederの使い方
### 【ユーザーのテストデータを自動生成】
#### 1. seederファイルをartisanコマンドで生成
`php artisan make:seeder UserTableSeeder`
#### 2. database/seeds/UserTableSeederのrunメソッドの中を以下のように追記
```
public function run()
{
\DB::table('users')->insert([
[
'name' => 'テスト1',
'email' => 'test1@test.jp',
'password' => Hash::make('testtest')
],
[
'name' => 'テスト2',
'email' => 'test2@test.jp',
'password' => Hash::make('testtest')
],
[
'name' => 'テスト3',
'email' => 'test3@test.jp',
'password' => Hash::make('testtest')
],
]);
}
```
#### 3. database/seeds/DatabaseSeeder.phpのrunメソッドに以下を追記
`$this->call(UserTableSeeder::class);`
#### 4. cms階層でartisanコマンドを以下の順番で実行
`php artisan migrate:refresh`
`php artisan db:seed`
### 【投稿(post)のテストデータを自動生成】
#### 1. spostテーブル用のeederファイルをartisanコマンドで生成
`php artisan make:seeder PostTableSeeder`
#### 2. artisanコマンドでファクトリーを生成
`php artisan make:factory PostFactory`
#### 3. databases/factories/Postfactory.phpの中身を以下に変更
```
<?php
/** @var \Illuminate\Database\Eloquent\Factory $factory */
use App\Model;
use Faker\Generator as Faker;
use App\User; //追記
$factory->define(App\Post::class, function (Faker $faker) {
return [
'post_title' => $faker->realText(100),
'post_desc' => $faker->realText(100),
'user_id' => function() {
return User::all()->random();
}
];
});
```
#### 4. database/seeds/PostTableSeederのrunメソッドの中を以下のように追記
` $posts = factory(App\Post::class, 15)->create();`
#### 5. database/seeds/DatabaseSeeder.phpのrunメソッドに以下を追記
`$this->call(PostTableSeeder::class);`
#### 6. artisanコマンドを以下の順番で実行
`php artisan migrate:refresh`
`php artisan db:seed`
##### *自動生成されるテキストを日本語にしたい場合は以下を変更
config/app.phpの109行名を以下に変更
```
'faker_locale' => 'ja_JP',
```
##### *ログイン後のリダイレクト先を変更したい場合はapp/Providers/RouteServiceProvider.phpの24行目を以下のように変更
```
public const HOME = '/home'; //変更前(home.blade.php)
public const HOME = '/'; //変更後(トップページに遷移)
```