### 授業資料ダウンロードリンク [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> ```