# Laravel授業4回目
## 環境構築(先週の復習)
### 【環境構築(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. サーバーの再起動
サーバー起動後のターミナル上で
`Ctrl + C`
#### 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`
## リレーション(1対多)
### 1人のログインユーザーは複数のチームを作成してオーナーになることができる機能
#### 1 artisanコマンドでマイグレーション 作成
`php artisan make:migration create_teams_table --create=teams`
#### 2 database/migrationsの直下のteams_table.phpに以下追記
```
public function up()
{
Schema::create('teams', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('team_name');
$table->integer('user_id');
$table->timestamps();
});
}
```
#### 3 マイグレーション実行(テーブルの作成)
`php artisan migrate`
### モデルの作成(リレーションの設定)
#### 1: artisanコマンドでモデル作成
`php artisan make:model Team`
#### 1 App/User.phpの中の39行目を改行して以下の内容をコピー
```
// Teamsテーブルとのリレーション (主テーブル側)
public function o_teams() {
return $this->hasMany('App\Models\Team');
}
```
#### 2 App/Team.phpの中の9行目を改行して以下の内容をコピー
```
// Userテーブルとのリレーション (従テーブル側)
public function user() {
return $this->belongsTo('App\Models\User');
}
```
### チーム作成画面の作成
#### 1 viewsの直下にteams.blade.phpを作成して以下の内容をコピペ
```
<!-- resources/views/teams.blade.php -->
@extends('layouts.app')
@section('content')
<!-- Bootstrapの定形コード… -->
<div class="card-body">
<div class="card-title">
投稿フォーム
</div>
<!-- バリデーションエラーの表示に使用-->
@include('common.errors')
<!-- バリデーションエラーの表示に使用-->
<!-- 投稿フォーム -->
@if( Auth::check() )
<form action="{{ url('teams') }}" method="POST" class="form-horizontal">
{{ csrf_field() }}
<!-- チーム名 -->
<div class="form-group">
チーム名
<div class="col-sm-6">
<input type="text" name="team_name" 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>
@endif
</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 teamsコントローラーを作成
`php artisan make:controller TeamsController`
#### 2 teamsコントローラー内にモデルの呼び出しをした上でindexメソッドに投稿表示処理を記述
```
use App\Models\Team; //この行を上に追加
use App\Models\User;//この行を上に追加
use Auth;//この行を上に追加
use Validator;//この行を上に追加
public function index()
{
//
return view('teams');
}
```
#### 3 web.phpにルーティングを追記
```
use App\Http\Controllers\TeamsController;//追記
Route::get('/', [TeamsController::class, 'index']);
```
### チーム登録処理の実装
#### 1 web.phpにルーティングを追記
`Route::post('teams', 'TeamsController@store');`
#### 2 teamsコントローラー内のstoreメソッドに登録処理を記述
```
public function store(Request $request)
{
//バリデーション
$validator = Validator::make($request->all(), [
'team_name' => 'required|max:255'
]);
//バリデーション:エラー
if ($validator->fails()) {
return redirect('/')
->withInput()
->withErrors($validator);
}
//以下に登録処理を記述(Eloquentモデル)
$teams = new Team;
$teams->team_name = $request->team_name;
$teams->user_id = Auth::id();//ここでログインしているユーザidを登録しています
$teams->save();
return redirect('/');
}
```
### チームの一覧表示処理を実装
#### 1 teams.blade.php内42行目に以下を記述して表示エリア作成
```
@if (count($teams) > 0)
<div class="card-body">
<div class="card-body">
<table class="table table-striped task-table">
<!-- テーブルヘッダ -->
<thead>
<th>チーム一覧</th>
<th>オーナー</th>
<th>参加人数</th>
<th>詳細</th>
<th>参加</th>
<th>編集</th>
</thead>
<!-- テーブル本体 -->
<tbody>
@foreach ($teams as $team)
<tr>
<!-- チーム名 -->
<td class="table-text">
<div>{{ $team->team_name }}</div>
</td>
<!-- チームオーナー -->
<td class="table-text">
<div>{{ $team->user->name }}</div>
</td>
<!-- 所属人数 -->
<td class="table-text">
<div></div>
</td>
<!-- 詳細ボタン -->
<td class="table-text">
</td>
<!-- チーム参加ボタン -->
<td class="table-text">
</td>
<!-- チーム編集ボタン-->
<td class="table-text">
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
@endif
```
#### 2 teamsコントローラー内のindexメソッドを以下のように変更してログインユーザーと紐付く投稿を取得する
```
public function index()
{
//チーム 全件取得
$teams = Team::get();
return view('teams',[
'teams'=> $teams
]);
}
```
#### 3 temas.blade.php内63行目を以下のように変更して投稿したユーザー名を表示
```
<!-- チームオーナー -->
<td class="table-text">
<div>{{ $team->user->name }}</div>
</td>
```
## リレーション(多対多)チーム参加機能
### データベースに中間テーブルを作成する為にマイグレーションを作成
#### 1 artisanコマンドでマイグレーション 作成
`php artisan make:migration create_team_user_table --create=team_user`
#### 2 database/migrationsの直下のpost_user_table.phpに以下追記
```
public function up()
{
Schema::create('team_user', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id');
$table->unsignedBigInteger('team_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); //外部キー参照
$table->foreign('team_id')->references('id')->on('teams')->onDelete('cascade'); //外部キー参照
$table->unique(['user_id', 'team_id'],'uq_roles'); //Laravelは複合主キーが扱いにくいのでユニークで代用
$table->timestamps();
});
}
```
#### 3 マイグレーション実行(テーブルの作成)
`php artisan migrate`
### モデルにリレーション設定
#### 1 App/User.phpに以下の内容を追記
```
// Teamsテーブルとの多対多リレーション
public function my_teams() {
return $this->belongsToMany('App\Models\Team');
}
```
#### 2 App/Team.phpに以下の内容を追記
```
// Userテーブルとの多対多リレーション
public function members() {
return $this->belongsToMany('App\Models\User');
}
```
### チーム参加ボタン&参加処理実装
#### 1 teams.blade.phpの69行名チーム参加ボタンのtdタグ内に以下をコピペ
```
<form action="{{ url('team/'.$team->id) }}" method="GET">
{{ csrf_field() }}
<button type="submit" class="btn btn-danger">
参加
</button>
</form>
```
#### 2 web.phpにルーティングを追加
`Route::get('team/{team_id}', [TeamsController::class, 'join']);`
#### 3 teamsコントローラーに新規でメソッドを作成
```
public function join($team_id)
{
}
```
#### 4 joinメソッドに以下に処理を追記
```
public function join($team_id)
{
//ログイン中のユーザーを取得
$user = Auth::user();
//お気に入りする記事
$team = Team::find($team_id);
//リレーションの登録
$team->members()->attach($user);
return redirect('/');
}
```
#### 5 teams.blade.phpの所属人数の部分に以下のように記述
```
<!-- 所属人数 -->
<td class="table-text">
<div>{{ $team->members()->count() }}人参加中</div>
</td>
```
#### 6 参加ボタンの表示を切り分けたいのでteams.blade.phpのボタンエリアを以下のように変更
```
@if(Auth::check())
@if(Auth::id() != $team->user_id && $team->members()->where('user_id',Auth::id())->exists() !== true)
<form action="{{ url('team/'.$team->id) }}" method="GET">
{{ csrf_field() }}
<button type="submit" class="btn btn-danger">
参加
</button>
</form>
@endif
@endif
```
#### 7 teamsコントローラーのstoreメソッドのリダイレクト処理の直前に以下の処理を追記
```
//多対多のリレーションもここで登録
$teams->members()->attach( Auth::user() );
```
## チーム編集機能
#### 1 teams.blade.phpのチーム編集ボタンのtd内に以下を記述
```
@if(Auth::check()&& Auth::id() == $team->user_id )
<form action="{{ url('teamedit/'.$team->id) }}" method="GET">
{{ csrf_field() }}
<button type="submit" class="btn btn-danger">
編集
</button>
</form>
@endif
```
#### 2 web.phpにルーティングを作成
`Route::get('teamedit/{team}', [TeamsController::class, 'edit']);
`
#### 3 teamsコントローラーにeditメソッドを作成して以下の処理を作成
```
//チーム編集画面表示
public function edit (Team $team) {
return view('teamsedit', ['team' => $team]);
}
```
#### 4 teamsedit.blade.phpを作成して編集画面を作成
```
@extends('layouts.app')
@section('content')
<div class="row">
<div class="col-md-12">
@include('common.errors')
<form action="{{ url('teams/update') }}" method="POST">
<!-- item_name -->
<div class="form-group">
<label for="item_name">チーム名</label>
<input type="text" name="team_name" class="form-control" value="{{$team->team_name}}">
</div>
<!--/ item_name -->
<!-- Save ボタン/Back ボタン -->
<div class="well well-sm">
<button type="submit" class="btn btn-primary">Save</button>
<a class="btn btn-link pull-right" href="{{ url('/') }}"> Back</a>
</div>
<!--/ Save ボタン/Back ボタン -->
<!-- id 値を送信 -->
<input type="hidden" name="id" value="{{$team->id}}" /> <!--/ id 値を送信 -->
<!-- CSRF -->
{{ csrf_field() }}
<!--/ CSRF -->
</form>
</div>
</div>
@endsection
```
#### 5 ルーティングをweb.phpに記述
```
//チーム更新処理
Route::post('teams/update', [TeamsController::class, 'update']);
```
#### 6 更新処理をteamsコントローラーに作成
```
//更新処理
public function update (Request $request) {
//バリデーション
$validator = Validator::make($request->all(), [
'team_name' => 'required|max:255',
]);
//バリデーション:エラー
if ($validator->fails()) {
return redirect('/')
->withInput()
->withErrors($validator);
}
//対象のチームを取得
$team = Team::find($request->id);
$team->team_name = $request->team_name;
$team->save();
return redirect('/');
}
```
### チーム詳細機能
#### 1 web.phpにルーティングを作成
```
// チーム詳細表示
Route::get('teams/{team}', [TeamsController::class, 'show']);
```
#### 2 コントローラーに処理を追記
```
//詳細表示
public function show(Team $team)
{
return view('teamsdetail',[
'team'=> $team
]);
}
```
#### 3 teamsdetail.blade.phpを作成して以下をコピペ
```
@extends('layouts.app')
@section('content')
<div class="row">
<div class="col-md-12">
<h1>チーム名: {{ $team->team_name}}</h1>
<h2>オーナー: {{ $team->user->name}}</h2>
<h3>メンバー</h3>
@foreach($team->members as $member)
<p>{{ $member->name}}</p>
@endforeach
</div>
</div>
@endsection
```
#### 4 詳細ボタンをteams.blade.phpのtdタグないに追加
```
<a href="{{ url('teams/'.$team->id) }}" class="btn btn-danger">詳細</a>
```