---
# System prepended metadata

title: Laravel_02

---

# Laravel_02
### 授業資料ダウンロードリンク
[Googleドライブ](https://drive.google.com/drive/folders/1PVyoulX1_TY-mPQaN4SEnNGUpzpRvagu?usp=sharing)

## 環境構築
過去資料確認

## Laravelのプロジェクト立ち上げ
### 【Laravelの起動】

#### 1. サーバーの起動とLaravelプロジェクトの起動チェック
#ディレクトリ移動
`cd cms`

#BuiltInサーバーを起動：動作確認
`php artisan serve --port=8080`

＊Cloud9の画面上部の緑の起動ボタンの左側Previewボタン＞Preview Running Applicationをクリック
右下に画面が起動してLaravelの文字が確認できたらOK

## リレーション(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/books.blade.php -->
<x-app-layout>

    <!--ヘッダー[START]-->
    <x-slot name="header">
        <h2 class="font-semibold text-xl text-gray-800 leading-tight">
            <form action="" method="GET" class="w-full max-w-lg">
                <x-button class="bg-gray-100 text-gray-900">{{ __('Dashboard') }}</x-button>
            </form>
        </h2>
    </x-slot>
    <!--ヘッダー[END]-->
            
        <!-- バリデーションエラーの表示に使用-->
       <x-errors id="errors" class="bg-blue-500 rounded-lg">{{$errors}}</x-errors>
        <!-- バリデーションエラーの表示に使用-->
    
    <!--全エリア[START]-->
    <div class="flex bg-gray-100">

        <!--左エリア[START]--> 
        <div class="text-gray-700 text-left px-4 py-4 m-2">
            
            <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
                <div class="p-6 bg-white border-b border-gray-500 font-bold">
                    チームを管理する
                </div>
            </div>


            <!-- チームのフォーム -->
            <form action="{{ url('teamadd') }}" method="POST" class="w-full max-w-lg">
                @csrf
                  <div class="flex flex-col px-2 py-2">
                   <!-- カラム１ -->
                    <div class="w-full md:w-1/1 px-3 mb-2 md:mb-0">
                      <label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2">
                       チーム名
                      </label>
                      <input name="team_name" class="appearance-none block w-full text-gray-700 border border-red-500 rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white" type="text" placeholder="">
                    </div>
                  </div>
                  <!-- カラム５ -->
                  <div class="flex flex-col">
                      <div class="text-gray-700 text-center px-4 py-2 m-2">
                             <x-button class="bg-blue-500 rounded-lg">送信</x-button>
                      </div>
                   </div>
            </form>
        </div>
        <!--左エリア[END]--> 
    
        <!--右側エリア[START]-->
        <div class="flex-1 text-gray-700 text-left px-4 py-2 m-2">
             <!-- チームの一覧 -->
            <div class="flex flex-col">
              <div class="-m-1.5 overflow-x-auto">
                <div class="p-1.5 min-w-full inline-block align-middle">
                  <div class="border rounded-lg shadow overflow-hidden dark:border-gray-700 dark:shadow-gray-900">
                    <table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
                      <thead class="bg-gray-50 dark:bg-gray-700">
                        <tr>
                          <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase dark:text-gray-400">チーム名</th>
                          <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase dark:text-gray-400">オーナー</th>
                          <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase dark:text-gray-400">参加人数</th>
                          <th scope="col" class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase dark:text-gray-400">詳細</th>
                          <th scope="col" class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase dark:text-gray-400">参加</th>
                        　<th scope="col" class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase dark:text-gray-400">編集</th>
                        </tr>
                      </thead>
                      <tbody class="divide-y divide-gray-200 dark:divide-gray-700">
                          <x-content></x-content>
                      </tbody>
                    </table>
                  </div>
                </div>
              </div>
            </div>
        </div>
        <!--右側エリア[[END]-->  
      

</div>
 <!--全エリア[END]-->

</x-app-layout>

```
#### 2. /resources/views/components/content.blade.php を作成し以下の内容をコピー
content.blade.php
```
<tr>
  <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-200"></td>
  <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-200"></td>
  <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-gray-200">人参加中</td>
  <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
    <a class="text-blue-500 hover:text-blue-700" href="#">詳細</a>
  </td>
   <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
            <a class="text-blue-500 hover:text-blue-700" href="#">参加</a>
  </td>
   <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
            <a class="text-blue-500 hover:text-blue-700" href="#">編集</a>
  </td>
</tr
```

#### 5. コンポートネントをビルド
`npm run build`

### 投稿画面表示処理の実装
#### 1 teamsコントローラーを作成
`php artisan make:controller TeamController`

#### 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\TeamController;//追記

//チーム一覧表示
Route::get('teams', [TeamController::class, 'index'])->middleware(['auth']);
```


### チーム登録処理の実装
#### 1 web.phpにルーティングを追記
`Route::post('teamadd', [TeamController::class, 'store']);`


#### 2 teamsコントローラー内のstoreメソッドに登録処理を記述
```

 public function store(Request $request)
    {
        //バリデーション 
        $validator = Validator::make($request->all(), [
            'team_name' => 'required|max:255'
        ]);
        
        //バリデーション:エラー
        if ($validator->fails()) {
            return redirect('teams')
                ->withInput()
                ->withErrors($validator);
        }
        
        //以下に登録処理を記述（Eloquentモデル）
        $teams = new Team;
        $teams->team_name = $request->team_name;
        $teams->user_id = Auth::id();//ここでログインしているユーザidを登録しています
        $teams->save();
        
        return redirect('teams');
        
    }
```
### チームの一覧表示処理を実装
#### 1 teams.blade.php内72~73行目に以下を記述して表示エリア作成
 ```
 <!-- チームの一覧 -->
＝＝省略＝＝
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
  @if (count($teams) > 0)
      @foreach ($teams as $team)
      <x-content :team="$team"></x-content>
      @endforeach
  @endif
</tbody>
```


#### 2 teamコントローラー内のindexメソッドを以下のように変更して投稿を取得する
```

 public function index()
    {
        //チーム 全件取得
        $teams = Team::get();
    
        
        return view('teams',[
            'teams'=> $teams
            ]);
    }
```

#### 3 content.blade.php内2~3行目を以下のように変更してチームメ名とオーナー名を表示
```
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-200">{{ $team->team_name }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-200">{{ $team->user->name }}</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 collection.blade.phpの9行目チーム参加ボタンのtdタグ内に以下をコピペ
```
<a class="text-blue-500 hover:text-blue-700" href="{{ url('team/'.$team->id) }}">参加</a>
```
#### 2 web.phpにルーティングを追加
`Route::get('team/{team_id}', [TeamController::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('teams');
        
    }
```
#### 5 content.blade.phpの所属人数の部分に以下のように記述
```
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-gray-200">{{ $team->members()->count() }}人参加中</td>
```

#### 6 参加ボタンの表示を切り分けたいのでcollection.blade.phpのボタンエリアを以下のように変更
```
@if(Auth::check())
    @if(Auth::id() != $team->user_id && $team->members()->where('user_id',Auth::id())->exists() !== true)
        <a class="text-blue-500 hover:text-blue-700" href="{{ url('team/'.$team->id) }}">参加</a>
    @endif
@endif
```

#### 7 teamコントローラーのstoreメソッドのリダイレクト処理の直前に以下の処理を追記
```
//多対多のリレーションもここで登録
$teams->members()->attach( Auth::user() );
```

## チーム編集機能
#### 1 contact.blade.phpのチーム編集ボタンのtd内に以下を記述
```
@if(Auth::check()&& Auth::id() == $team->user_id )
    <a class="text-blue-500 hover:text-blue-700" href="{{ url('teamedit/'.$team->id) }}">編集</a>
@endif
```
#### 2 web.phpにルーティングを作成
`Route::get('teamedit/{team}',  [TeamController::class, 'edit']);
`

#### 3 teamsコントローラーにeditメソッドを作成して以下の処理を作成
```
//チーム編集画面表示
public function edit (Team $team) {
        
   return view('teamedit', ['team' => $team]);
        
}
```
#### 4 teamedit.blade.phpを作成して編集画面を作成
```
<!-- resources/views/teamedit.blade.php -->
<x-app-layout>

    <!--ヘッダー[START]-->
    <x-slot name="header">
        <h2 class="font-semibold text-xl text-gray-800 leading-tight">
            <form action="" method="GET" class="w-full max-w-lg">
                <x-button class="bg-gray-100 text-gray-900">{{ __('Dashboard') }}</x-button>
            </form>
        </h2>
    </x-slot>
    <!--ヘッダー[END]-->
            
        <!-- バリデーションエラーの表示に使用-->
       <x-errors id="errors" class="bg-blue-500 rounded-lg">{{$errors}}</x-errors>
        <!-- バリデーションエラーの表示に使用-->
    
    <!--全エリア[START]-->
    <div class="flex bg-gray-100">

        <!--左エリア[START]--> 
        <div class="text-gray-700 text-left px-4 py-4 m-2">
            
            <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
                <div class="p-6 bg-white border-b border-gray-500 font-bold">
                    チームを管理する
                </div>
            </div>


            <!-- 本のタイトル -->
            <form action="{{ url('team/update') }}" method="POST" class="w-full max-w-lg">
                @csrf
                  <div class="flex flex-col px-2 py-2">
                   <!-- カラム１ -->
                    <div class="w-full md:w-1/1 px-3 mb-2 md:mb-0">
                      <label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2">
                       チーム名
                      </label>
                      <input name="team_name" class="appearance-none block w-full text-gray-700 border border-red-500 rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white" type="text" placeholder="" value="{{$team->team_name}}">
                    </div>
                  </div>
                  <!-- id 値を送信 -->
                <input type="hidden" name="id" value="{{$team->id}}" /> <!--/ id 値を送信 -->
                  <!-- カラム５ -->
                  <div class="flex flex-col">
                      <div class="text-gray-700 text-center px-4 py-2 m-2">
                             <x-button class="bg-blue-500 rounded-lg">送信</x-button>
                      </div>
                   </div>
            </form>
        </div>
        <!--左エリア[END]--> 
    
       
      

</div>
 <!--全エリア[END]-->

</x-app-layout>
```
#### 5 ルーティングをweb.phpに記述
```
//チーム更新処理
Route::post('team/update',  [TeamController::class, 'update']);
```

#### 6 更新処理をteamコントローラーに作成
```
//更新処理
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}', [TeamController::class, 'show']);
```

#### 2 コントローラーに処理を追記
```
//詳細表示
public function show(Team $team)
{
    return view('teamdetail',[
        'team'=> $team
        ]);
}
```

#### 3 teamdetail.blade.phpを作成して以下をコピペ
```
<!-- resources/views/books.blade.php -->
<x-app-layout>
  
<!-- Team -->
<div class="max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 mx-auto">
  <!-- Title -->
  <div class="max-w-2xl mx-auto text-center mb-10 lg:mb-14">
    <h2 class="text-2xl font-bold md:text-4xl md:leading-tight dark:text-white">{{ $team->team_name}}メンバー一覧</h2>
    <p class="mt-1 text-gray-600 dark:text-gray-400">Creative people</p>
  </div>
  <!-- End Title -->

  <!-- Grid -->
  <div class="grid grid-cols-2 lg:grid-cols-3 gap-8 md:gap-12">
    
    @if ($team)
     @foreach ($team->members as $member)
      <div class="grid sm:flex sm:items-center gap-y-3 gap-x-4">
        <img class="rounded-lg w-20 h-20" src="https://images.unsplash.com/photo-1568602471122-7832951cc4c5?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=facearea&facepad=2&w=900&h=900&q=80" alt="Image Description">
  
        <div class="sm:flex sm:flex-col sm:h-full">
          <div>
            <h3 class="font-medium text-gray-800 dark:text-gray-200">
             {{ $member->name }}
            </h3>
            <p class="mt-1 text-xs uppercase text-gray-500">
              メンバー
            </p>
          </div>
  
          <!-- Social Brands -->
          <div class="mt-2 sm:mt-auto space-x-2.5">
            <a class="inline-flex justify-center items-center text-gray-500 hover:text-gray-800 dark:hover:text-gray-200" href="#">
              <svg class="w-3.5 h-3.5" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
                <path d="M5.026 15c6.038 0 9.341-5.003 9.341-9.334 0-.14 0-.282-.006-.422A6.685 6.685 0 0 0 16 3.542a6.658 6.658 0 0 1-1.889.518 3.301 3.301 0 0 0 1.447-1.817 6.533 6.533 0 0 1-2.087.793A3.286 3.286 0 0 0 7.875 6.03a9.325 9.325 0 0 1-6.767-3.429 3.289 3.289 0 0 0 1.018 4.382A3.323 3.323 0 0 1 .64 6.575v.045a3.288 3.288 0 0 0 2.632 3.218 3.203 3.203 0 0 1-.865.115 3.23 3.23 0 0 1-.614-.057 3.283 3.283 0 0 0 3.067 2.277A6.588 6.588 0 0 1 .78 13.58a6.32 6.32 0 0 1-.78-.045A9.344 9.344 0 0 0 5.026 15z"/>
              </svg>
            </a>
            <a class="inline-flex justify-center items-center text-gray-500 hover:text-gray-800 dark:hover:text-gray-200" href="#">
              <svg class="w-3.5 h-3.5" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
                <path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z"/>
              </svg>
            </a>
            <a class="inline-flex justify-center items-center text-gray-500 hover:text-gray-800 dark:hover:text-gray-200" href="#">
              <svg class="w-3.5 h-3.5" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
                <path d="M3.362 10.11c0 .926-.756 1.681-1.681 1.681S0 11.036 0 10.111C0 9.186.756 8.43 1.68 8.43h1.682v1.68zm.846 0c0-.924.756-1.68 1.681-1.68s1.681.756 1.681 1.68v4.21c0 .924-.756 1.68-1.68 1.68a1.685 1.685 0 0 1-1.682-1.68v-4.21zM5.89 3.362c-.926 0-1.682-.756-1.682-1.681S4.964 0 5.89 0s1.68.756 1.68 1.68v1.682H5.89zm0 .846c.924 0 1.68.756 1.68 1.681S6.814 7.57 5.89 7.57H1.68C.757 7.57 0 6.814 0 5.89c0-.926.756-1.682 1.68-1.682h4.21zm6.749 1.682c0-.926.755-1.682 1.68-1.682.925 0 1.681.756 1.681 1.681s-.756 1.681-1.68 1.681h-1.681V5.89zm-.848 0c0 .924-.755 1.68-1.68 1.68A1.685 1.685 0 0 1 8.43 5.89V1.68C8.43.757 9.186 0 10.11 0c.926 0 1.681.756 1.681 1.68v4.21zm-1.681 6.748c.926 0 1.682.756 1.682 1.681S11.036 16 10.11 16s-1.681-.756-1.681-1.68v-1.682h1.68zm0-.847c-.924 0-1.68-.755-1.68-1.68 0-.925.756-1.681 1.68-1.681h4.21c.924 0 1.68.756 1.68 1.68 0 .926-.756 1.681-1.68 1.681h-4.21z"/>
              </svg>
            </a>
          </div>
          <!-- End Social Brands -->
        </div>
      </div>
      <!-- End Col -->
      @endforeach
    @endif
    

  </div>
  <!-- End Grid -->
</div>
<!-- End Team -->

</x-app-layout>
```

#### 4　詳細ボタンをcollection.blade.phpのtdタグ内に追加
```
<a class="text-blue-500 hover:text-blue-700" href="{{ url('teams/'.$team->id) }}">詳細</a>
```

## 複数オーナー対応（中間テーブルにデータを持たせるWithPivot）
#### 1 カラム追加用のマイグレーションを作成
`php artisan make:migration add_role_to_team_user_table --table=team_user`
#### 1 中間テーブルにカラムを追加
```
public function up()
    {
        Schema::table('team_user', function (Blueprint $table) {
            
            $table->string('role')->default('member');//<-これを追加しています！！！
            
        });
    }
```

#### 2 migration refresh（テーブル再構築：データ全部一回消えます）
`php artisan migrate`

#### 3 TeamControllerのstoreメソッドの部分のアタッチを変更
```
   上は省略
   //以下に登録処理を記述（Eloquentモデル）
        $teams = new Team;
        $teams->team_name = $request->team_name;
        $teams->user_id = Auth::id();//ここでログインしているユーザidを登録しています
        $teams->save();
        
        //多対多のリレーションもここで登録
        $teams->members()->attach( Auth::user(),['role'=>'owner'] );//<-ここが変わってるよ！！
        
        return redirect('/');
```

#### 4 モデルの中でwithPivotの設定をする
##### App/Models/User.phpの多対多リレーションを変更
`->withPivot('カラム名');`をつけてあげる
```
 // Teamsテーブルとの多対多リレーション
     public function my_teams() {
        return $this->belongsToMany('App\Models\Team')->withPivot('role');
    }
```

##### 　App/Models/Team.phpの多対多リレーションを変更
```
 // Userテーブルとの多対多リレーション
     public function members() {
        return $this->belongsToMany('App\Models\User')->withPivot('role');
    }
```

#### 5 teamdetail.blade.phpの26～28行目の表示部分を変更！
```
<h3 class="font-medium text-gray-800 dark:text-gray-200">
 {{ $member->name }}
</h3>
<p class="mt-1 text-xs uppercase text-gray-500">
  {{ $member->pivot->role}}//ここが変更
</p>
```