### 授業資料ダウンロードリンク
[Googleドライブ](https://drive.google.com/drive/folders/1PVyoulX1_TY-mPQaN4SEnNGUpzpRvagu?usp=sharing)
## 環境構築
### 【AWSコンソールにログイン】
#### 1. まずはAWSAcademyにログイン
#### 2. 左側のリストからコースを選択
#### 3. モジュールをクリックして画面中央の「Learner Lab」を開く
#### 4. 「Start Lab」ボタンをクリック
#### 5. 「AWS」の横のランプがグリーンになったら「AWS」のリンクをクリック
#### 6. AWSマネジメントコンソールへログインできます。
#### 7. 上部検索窓からAWSCloud9と検索してクリック
#### 8. AWSCloud9の管理画面に入れます。
### 【AWSCloud9でプロジェクト作成】
#### 1. Create environmentをクリック
環境設定情報
```
Name: 自由
Description: 自由
Environment type:New EC2 instance
Instance type: Additional instance types t2.micro
Connection: Secure Shell (SSH)
その他は変更なし
```
#### 2. 入力できたらCreateをクリック
#### 3. 管理画面のプロジェクト一覧からopenをクリック
*Cloud9のエディターか立ち上がります。
### 【Laravelを動かす為に必要なものを導入していく】
基本的にLaravelを動かす為にはPHPとComposerが必要です。
AWSCloud9はクラウド上に空っぽのサーバーを借りてくるので必要なものは自分でインストールする必要があります。
今回は中身の詳細は軽く説明だけにして簡単にインストールできるようにパッケージにしたシェルスクリプトを実行することで準備します。
#### 1.Fileタブから今日の授業資料からsetup.shをアップロードします。
#### 2. セットアップのシェルスクリプトを実行
`sh setup.sh`
## Laravelのプロジェクト立ち上げ
### 【Laravelの起動】
#### 1. サーバーの起動とLaravelプロジェクトの起動チェック
#ディレクトリ移動
`cd cms`
#BuiltInサーバーを起動:動作確認
`php artisan serve --port=8080`
*Cloud9の画面上部の緑の起動ボタンの左側Previewボタン>Preview Running Applicationをクリック
右下に画面が起動してLaravelの文字が確認できたらOK
#### 3.コンポーザーをアップデートしておく
`sudo composer update`
### 【データベースの作成】
ターミナルの上に緑プラスボタンからNewterminalを起動
`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\URL; //この行を追加
//bootメソッドを以下に変更
public function boot()
{
URL::forceScheme('https'); //この行を追加
}
```
#### 4. 表示の仕組みをチェックしてみる!
#4-1 /resouces/views/welcome.blade.php を編集して見よう!
#4-2 ブラウザ・更新で確認 → 変更確認できればOK
## ログイン認証
### 【ログイン認証実装】
#### 0.cms階層に移動
`cd cms`
#### 1. Laravel 9.x の場合
`sudo composer require laravel/breeze --dev`
質問が来たらyesでOK
#### 2. artisan コマンドを実行
`php artisan breeze:install`
インストールするバージョンはblade(0)を選択
他の質問はyesでOK
#### 3. npmパッケージをインストール
`npm install`
#### 4. パッケージをビルド
`npm run build`
#### 5.テーブル作成
`php artisan migrate`
#### 6. ログイン画面へのリンクを追加する以下2ページ
/resources/views/auth/register.blade.php
/resources/views/auth/login.blade.php
```
#<x-guest-layout>
省略
#</x-guest-layout>...以下...
<!-- 以下を追加 -->
@if (Route::has('login'))
<div class="hidden fixed top-0 right-0 px-6 py-4 sm:block">
@auth
<a href="{{ url('/dashboard') }}" class="text-sm text-gray-700 dark:text-gray-500 underline">Dashboard</a>
@else
<a href="{{ route('login') }}" class="text-sm text-gray-700 dark:text-gray-500 underline">Log in</a>
@if (Route::has('register'))
<a href="{{ route('register') }}" class="ml-4 text-sm text-gray-700 dark:text-gray-500 underline">Register</a>
@endif
@endauth
</div>
@endif
```
## 本管理アプリ実装(簡単なCRUDの実装)
### 【データベースにbooksテーブルを作成する為にマイグレーションを作成】
#### 1. artisanコマンドでモデル作成する(モデル&コントローラー&マイグレーションファイルも一緒に作成)
`php artisan make:model Book -mcr`
#### 2. database/migrationsの直下のbooks_table.phpに以下追記
```
public function up()
{
Schema::create('books', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('item_name');
$table->integer('item_number');
$table->integer('item_amount');
$table->datetime('published');
$table->timestamps();
});
}
```
#### 3. マイグレーション実行(テーブルの作成)
`php artisan migrate`
#### 2./routes/web.phpに以下二行を追記してモデルを呼び出す
```
use App\Http\Controllers\BookController; //追加
use App\Models\Book; //追加
```
### 【ルーティングとviewの準備】
#### 1. /routes/web.phpに以下の記述を追加
```
<?php
use App\Http\Controllers\ProfileController;//9.43.x~
use Illuminate\Support\Facades\Route;
use Illuminate\Http\Request;
use App\Http\Controllers\BookController; //追加
use App\Models\Book; //追加
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
//本:ダッシュボード表示(books.blade.php)
Route::get('/', [BookController::class,'index'])->middleware(['auth']);
//本:追加
Route::post('/books',[BookController::class,"store"]);
//本:削除
Route::delete('/book/{book}', [BookController::class,"destroy"]);
//本:更新画面表示
Route::post('/booksedit/{book}',[BookController::class,"edit"]); //通常
//本:更新処理
Route::post('/books/update',[BookController::class,"update"]);
//*****ここから下はデフォルトで入ってます*****
Route::get('/dashboard', function () {
return view('dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');
```
#### 2. /resources/views/components/collection.blade.php を作成し以下の内容をコピー
collection.blade.php
```
<div class="flex justify-between p-4 items-center bg-blue-500 text-white rounded-lg border-2 border-white">
<div>{{ $slot }}</div>
<button>×</button>
</div>
```
#### 3. /resources/views/components/errors.blade.php を作成し以下の内容コピー
```
<!-- resources/views/components/errors.blade.php -->
@if (count($errors) > 0)
<!-- Form Error List -->
<div class="flex justify-between p-4 items-center bg-red-500 text-white rounded-lg border-2 border-white">
<div><strong>入力した文字を修正してくた?さい。</strong></div>
<div>
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
</div>
@endif
```
#### 4. resources/views/components/button.blade.phpを作成し以下の内容をコピー
```
<button {{ $attributes->merge(['type' => 'submit', 'class' => 'inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 active:bg-gray-900 focus:outline-none focus:border-gray-900 focus:ring ring-gray-300 disabled:opacity-25 transition ease-in-out duration-150']) }}>
{{ $slot }}
</button>
```
#### 5. resources/views/books.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">
</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('books') }}" method="POST" class="w-full max-w-lg">
@csrf
<div class="flex flex-col px-2 py-2">
<!-- カラム1 -->
<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">
Book Name
</label>
<input name="item_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>
<!-- カラム2 -->
<div class="w-full md:w-1/1 px-3">
<label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2">
金額
</label>
<input name="item_amount" class="appearance-none block w-full text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500" type="text" placeholder="">
</div>
<!-- カラム3 -->
<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="item_number" class="appearance-none block w-full text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500" type="text" placeholder="">
</div>
<!-- カラム4 -->
<div class="w-full md:w-1/1 px-3 mb-6 md:mb-0">
<label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2">
発売日
</label>
<input name="published" type="date" class="appearance-none block w-full text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500" type="text" placeholder="">
</div>
</div>
<!-- カラム5 -->
<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 bg-blue-100 px-4 py-2 m-2">
<x-collection>テスト1</x-collection>
<x-collection>テスト2</x-collection>
<x-collection>テスト3</x-collection>
</div>
<!--右側エリア[[END]-->
</div>
<!--全エリア[END]-->
</x-app-layout>
```
#### 6. コンポートネントをビルド
`npm run build`
### 【登録処理実装】
#### 1. /app/Http/Controllers/BookController.phpを開いて以下1行追加!!
```
BookController.phpの上部
# use App\Models\Book;
# use Illuminate\Http\Request;
use Validator; //この1行だけ追加!
```
#### 2. BookController.phpのstoreメソッドに以下を以下に変更
```
public function store(Request $request) {
//** ↓ 下をコピー ↓ **
//バリデーション
$validator = Validator::make($request->all(), [
'item_name' => 'required|min:3|max:255',
'item_number' => 'required | min:1 | max:3',
'item_amount' => 'required | max:6',
'published' => 'required',
]);
//バリデーション:エラー
if ($validator->fails()) {
return redirect('/')
->withInput()
->withErrors($validator);
}
//以下に登録処理を記述(Eloquentモデル)
// Eloquentモデル
$books = new Book;
$books->item_name = $request->item_name;
$books->item_number = $request->item_number;
$books->item_amount = $request->item_amount;
$books->published = $request->published;
$books->save();
return redirect('/');
//** ↑ 上をコピー ↑ **
}
```
### 【一覧表示処理実装】
#### 1. BookController.phpのindexメソッドを以下に変更
```
public function index() {
//** ↓ 下をコピー ↓ **
$books = Book::orderBy('created_at', 'asc')->get();
return view('books', [
'books' => $books
]);
//** ↑ 上をコピー ↑ **
}
```
#### 2. resources/views/books.blade.phpに表示領域を作成
books.blade.phpの 右側エリアを全て上書き!!
```
<!--右側エリア[START]-->
<div class="flex-1 text-gray-700 text-left bg-blue-100 px-4 py-2 m-2">
<!-- 現在の本 -->
@if (count($books) > 0)
@foreach ($books as $book)
<x-collection id="{{ $book->id }}">{{ $book->item_name }}</x-collection>
@endforeach
@endif
</div>
<!--右側エリア[[END]-->
```
#### 3. /resources/views/components/collection.blade.php を更新!!
```
<!-- 本: 削除ボタン -->
<div class="flex justify-between p-4 items-center bg-blue-500 text-white rounded-lg border-2 border-white">
<div>{{ $slot }}</div>
<div>
<form action="{{ url('booksedit/'.$id) }}" method="POST">
@csrf
<button type="submit" class="btn bg-blue-500 rounded-lg">
更新
</button>
</form>
</div>
<div>
<form action="{{ url('book/'.$id) }}" method="POST">
@csrf
@method('DELETE')
<button type="submit" class="btn bg-blue-500 rounded-lg">
削除
</button>
</form>
</div>
</div>
```
### 【削除処理の実装】
#### 1. BookController.phpのdestroyメソッドを以下に変更
```
public function destroy(Book $book) {
//** ↓ 下をコピー ↓ **
$book->delete(); //追加
return redirect('/'); //追加
//** ↑ 上をコピー ↑ **
});
```
### 【更新画面表示の処理を作成】
#### 1.更新画面を作成 /resources/views/booksedit.blade.php を作成
```
<!-- resources/views/booksedit.blade.php -->
<x-app-layout>
<!-- バリデーションエラーの表示に使用-->
<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('books/update') }}" method="POST" class="w-full max-w-lg">
@csrf
<div class="flex flex-col px-2 py-2">
<!-- カラム1 -->
<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">
Book Name
</label>
<input name="item_name" value="{{$book->item_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>
<!-- カラム2 -->
<div class="w-full md:w-1/1 px-3">
<label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2">
金額
</label>
<input name="item_amount" value="{{$book->item_amount}}" class="appearance-none block w-full text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500" type="text" placeholder="">
</div>
<!-- カラム3 -->
<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="item_number" value="{{$book->item_number}}" class="appearance-none block w-full text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500" type="text" placeholder="">
</div>
<!-- カラム4 -->
<div class="w-full md:w-1/1 px-3 mb-6 md:mb-0">
<label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2">
発売日
</label>
<input name="published" type="datetime-local" value="{{$book->published}}" class="appearance-none block w-full text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500" placeholder="">
</div>
</div>
<!-- カラム5 -->
<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>
<!-- id値を送信 -->
<input type="hidden" name="id" value="{{$book->id}}">
<!--/ id値を送信 -->
</form>
</div>
<!--左エリア[END]-->
<!--右側エリア[START]-->
<div class="flex-1 text-gray-700 text-left bg-blue-100 px-4 py-2 m-2">
</div>
<!--右側エリア[[END]-->
</div>
<!--全エリア[END]-->
</x-app-layout>
```
#### 2. BookController.phpのeditメソッドを以下に変更
```
public function edit(Book $book)
{
//** ↓ 下をコピー ↓ **
//{books}id 値を取得 => Book $books id 値の1レコード取得
return view('booksedit', ['book' => $book]);
//** ↑ 上をコピー ↑ **!
}
```
### 【更新処理の実装】
#### 1. BookController.phpのupdateメソッドを以下に変更
```
public function update(Request $request, Book $book)
{
//** ↓ 下をコピー ↓ **
//バリデーション
$validator = Validator::make($request->all(), [
'id' => 'required',
'item_name' => 'required|min:3|max:255',
'item_number' => 'required|min:1|max:3',
'item_amount' => 'required|max:6',
'published' => 'required',
]);
//バリデーション:エラー
if ($validator->fails()) {
return redirect('/booksedit/'.$request->id)
->withInput()
->withErrors($validator);
}
//データ更新
$books = Book::find($request->id);
$books->item_name = $request->item_name;
$books->item_number = $request->item_number;
$books->item_amount = $request->item_amount;
$books->published = $request->published;
$books->save();
return redirect('/');
//** ↑ 上をコピー ↑ **!
}
```
### 【ページネーション実装】
#### 1. BooksControllerのindexの処理を以下に変更
```
public function index()
{
$books = Book::orderBy('created_at', 'asc')->paginate(3);
return view('books', [
'books' => $books
]);
}
```
#### 2. books.blade.phpの右側エリアの下に追加
```
<div>
{{ $books->links()}}
</div>
```