# Laravel授業2回目(Laravel9版) ## 環境構築(先週の復習) ## 環境構築 ### 【PHPセットアップ】 #### 1.パッケージのアップデート `sudo yum update -y` #### 2.PHPのパッケージをすべてアンインストール `sudo yum -y remove php-*` #### 3.amazon-linux-extrasをアップデート `sudo yum update -y amazon-linux-extras` #### 4.amazon-linux-extrasで使用中のパッケージと使えるパッケージを確認 `amazon-linux-extras` #### 5.lamp-mariadb10.2-php7.2を使用停止 `sudo amazon-linux-extras disable lamp-mariadb10.2-php7.2` #### 6.PHP8.0を有効化 `sudo amazon-linux-extras enable php8.0` #### 7-1.インストールするパッケージの案内があったので、表示されたコマンドを実行 `sudo yum clean metadata && sudo yum install php-cli php-pdo php-fpm php-mysqlnd` #### 7-2.インストールするパッケージの案内があったので、表示されたコマンドを実行 `sudo yum install php-cli php-common php-devel php-fpm php-gd php-mysqlnd php-mbstring php-pdo php-xml` #### 8-1.apacheなどを再起動 `sudo systemctl restart httpd.service` #### 8-2.apacheなどを再起動 `sudo systemctl restart php-fpm.service` ### 【データベースの準備】 #### 1.MariaDBデフォルト確認 `sudo yum list installed | grep mariadb` #### 2.MariaDBのインストール `sudo amazon-linux-extras install mariadb10.5 -y` #### 3-1.Apache, MariaDBの起動 `sudo systemctl start mariadb` #### 3-2.Apache, MariaDB初期設定 `sudo mysql_secure_installation` ``` 初回設定の入力項目 Enter current password for root (enter for none): [Enterキー] Switch to unix_socket authentication [Y/n] y 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 ``` #### 4-1.MaridaDBの自動起動を有効化 `sudo systemctl enable mariadb` #### 4-2.MaridaDBの自動起動確認 `sudo systemctl is-enabled mariadb` #### 5-1. Composerインストール `curl -sS https://getcomposer.org/installer | php -- --version=2.3.5` #### 5-2. Composerパスを通す `sudo mv composer.phar /usr/bin/composer` #### 5-3. Composer確認 `composer` #### 6. Laravelインストール(最新バージョン) `composer create-project "laravel/laravel=9.1.8" cms` #### 7. サーバーの起動と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\Routing\UrlGenerator;//この行を追加 //bootメソッドを以下に変更 public function boot(UrlGenerator $url) { $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/5.1.2/phpMyAdmin-5.1.2-all-languages.zip` #### 3. zipファイルを解凍 `unzip phpMyAdmin-5.1.2-all-languages.zip` #### 4. cms階層に戻る `cd ..` > <手順解説> > 1 publicフォルダ内に「phpMyAdmin-5.1.2-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 パッケージをインストール(Laravel 9.x の場合) `composer require laravel/ui` #### 3. artisan コマンドを実行 `php artisan ui vue --auth` #### 4. npmパッケージをインストール `npm install` #### 5. パッケージをビルド(1回目) `npm run dev` #### 6. パッケージをビルド(2回目) `npm run dev` *なぜかビルド2回必要です! ## リレーション(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/Models/User.phpの中の39行目を改行して以下の内容をコピー ``` // Postsテーブルとのリレーション (主テーブル側) public function posts() { return $this->hasMany('App\Models\Post'); } ``` #### 2. App/Models/Post.phpの中の9行目を改行して以下の内容をコピー ``` // Userテーブルとのリレーション (従テーブル側) public function user() { return $this->belongsTo('App\Models\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\Models\Post; //この行を上に追加 use App\Models\User;//この行を上に追加 use Auth;//この行を上に追加 use Validator;//この行を上に追加 public function index() { // return view('posts'); } ``` #### 3. web.phpにルーティングを追記 ``` use App\Http\Controllers\PostsController;//追記 Route::get('/', [PostsController::class, '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::class, '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>&nbsp;</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/Models/User.phpに以下の内容を追記 ``` // Postsテーブルとの多対多リレーション public function favo_posts() { return $this->belongsToMany('App\Models\Post'); } ``` #### 2. App/Models/Post.phpに以下の内容を追記 ``` // Userテーブルとの多対多リレーション public function favo_user() { return $this->belongsToMany('App\Models\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::class, '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>&nbsp;</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メソッドの中を以下のように追記 ``` use Illuminate\Support\Facades\Hash;追記 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 = '/'; //変更後(トップページに遷移) ```