---
# System prepended metadata

title: Laravel EXP講座（講義2）

---

# Laravel EXP講座（講義2）
## 環境構築
### 【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.  パッケージをビルド(１回目)
`npm run dev`
#### 6.  パッケージをビルド(２回目)
`npm run dev`
＊なぜかビルド２回必要です！

## メール送信機能実装
### 【Mailtrap】
#### 1. アカウント作成
https://mailtrap.io/

#### 2. メール情報を確認
Inboxes>Demo inbox>SMTP Setting>Integrations>Laravel
を選択するとLaravelの.envに記述する内容が表示される。

#### 3. メールアドレスの確認
Inboxes>Demo inbox>Email Adressから自分のメールアドレスが確認できる

### 【Mail送信処理を作成】
#### 1. .envファイルに設定情報を記述
```
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=*************** //自分のmailtrapのユーザーネーム
MAIL_PASSWORD=***************　//自分のmailtrapのパスワード
MAIL_ENCRYPTION=tls
```

#### 2. サーバー再起動（cms階層で）
`Ctrl　＋　C`
`php artisan serve --port=8080`

#### 3. mail.blade.phpを作成して以下をコピペ
```
@extends('layouts.app')
@section('content')

<form action="{{ url('/mail/send') }}" method="post" enctype="multipart/form-data">
    {{ csrf_field() }}
        <div class="form-group">
            <label for="exampleInputEmail1">Eメールアドレス</label>
            <input type="email" class="form-control" name="email" id="exampleInputEmail1" placeholder="Eメールアドレス">
            <small class="text-muted">あなたのメールは他の誰とも共有しません。</small>
        </div>
        <div class="form-group">
            <label for="exampleInputEmail1">サンプルテキスト</label>
            <input type="text" class="form-control" name="text" id="exampleInputEmail1" placeholder="送りたい文字列">
        </div>
    <button type="submit" class="btn btn-primary">送信する</button>
</form>

@endsection
```

#### 4. web.phpにuseを記述後にルーティングを二つ追加
```
use App\Http\Controllers\MailController;//追記

//メール送信フォームを表示
Route::get('/mail', [MailController::class, 'index']);

//メール送信処理
Route::post('/mail/send',  [MailController::class, 'send']);
```

#### 5. MailControllerを作成
`php artisan make:controller MailController`

#### 6. MailController内に以下を追記
`use Mail;`

#### 7. MailController内にindex処理を追記
```
//メールフォーム表示
public function index(){

    return view('mail');

}
```

#### 8. MailController内にsend処理（送信処理）を追記
```
// メール送信処理
public function send(Request $request){

    $email = $request->email; //送信先アドレス取得
    $text = $request->text; //送信テキスト取得
    // dd($text);

    // メール送信処理（//view/emails/test_mail_text.blade.phpにデータを送る）
    Mail::send(['text' => 'emails.test_mail_text'], [
        'text'=>$text , //送りたい情報
    ]
    , function($message) use($email) {

        $message
            ->from('info@test.jp')
            ->to($email)
            ->subject("テストメールだよ！");
    });

    return redirect('mail');

}
```

#### 9. viewsフォルダの直下にemailsフォルダを作成してその中にtest_mail_text.blade.phpを作成して以下をコピペ
```
テストメールです

以下は入力した内容
==========================

{{$text}}

==========================
```

## 画像アップロード機能
### 【画像アップロード処理】
#### 1. userのマイグレーションファイルに以下を追加
`$table->string('img_url')->nullable();//追記！！！`
```
public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->string('name');
        $table->string('email')->unique();
        $table->timestamp('email_verified_at')->nullable();
        $table->string('password');
        $table->string('img_url')->nullable();//追記！！！
        $table->rememberToken();
        $table->timestamps();
    });
}
```
#### 2. migrate　refreshしてテーブルにカラム追加実行
`php artisan migrate:refresh`

#### 3. 画像処理をまとめるcontroller作成
`php artisan make:controller ImgController`

#### 4. web.phpにルーティングを2つ追加
```
use App\Http\Controllers\ImgController;//追記

//画像アップロード画面表示
Route::get('/img', [ImgController::class, 'index']);

//画像アップロード処理
Route::post('/img/upload',[ImgController::class, 'upload']);
```

#### 5. views直下にimg_upload.blade.phpファイルを作成して以下をコピペ
```
@extends('layouts.app')
@section('content')

@if ($errors->any())
<div class="errors">
     <ul>
        @foreach ($errors->all() as $error)
            <li>{{ $error }}</li>
        @endforeach
     </ul>
</div>
@endif

<form action="{{ url('/img/upload') }}" method="post" enctype="multipart/form-data">
    {{ csrf_field() }}
    <div class="form-group">
        <input id="fileUploader" type="file" name="img" accept='image/' enctype="multipart/form-data" multiple="multiple" required autofocus>
    </div>
    <button type="submit" class="btn btn-primary">送信する</button>
</form>

@endsection
```

#### 6. ImgControllerに以下4行を追記
```
use Validator;
use Auth;
use Illuminate\Support\Str;
```

#### 7. ImgControllerに表示処理作成
```
//画像アップローダー表示
public function index(){

    return view('img_upload');

}
```
#### 8. ImgControllerに画像アップロード処理作成
```
// 画像アップロード処理
public function upload(Request $request){

   // バリデーション 
    $validator = $request->validate( [
        'img' => 'required|file|image|max:2048', 
    ]);

    // 画像ファイル取得
    $file = $request->img;

    // ログインユーザー取得
    $user = Auth::user();

    if ( !empty($file) ) {

        // ファイルの拡張子取得
        $ext = $file->guessExtension();

        //ファイル名を生成
        $fileName = Str::random(32).'.'.$ext;

        // 画像のファイル名を任意のDBに保存
        $user->img_url = $fileName;
        $user->save();

        //public/uploadフォルダを作成
        $target_path = public_path('/uploads/');

        //ファイルをpublic/uploadフォルダに移動
        $file->move($target_path,$fileName);

    }else{

        return redirect('/home');
    }

    return redirect('/img');

}
```
### 【画像表示処理】
#### 1. img_upload.blade.phpのフォームの直下に以下を追記
```
@if($user->img_url)
    <img src="/uploads/{{ $user->img_url }}">
@endif
```

#### 2. ImgControllerのindex処理を以下に変更
```
//画像アップローダー表示
public function index(){

     $user = Auth::user();

    return view('img_upload',[
        'user'=>$user
        ]);

}
```

#### 3. 最後にImgControllerにログインユーザーのみの指定をする
```
//ログインユーザーのみ使える機能にする　これを追加する！順番重要です！最初にログイン確認です。
public function __construct()
{
    $this->middleware('auth');
}

//画像アップローダー表示
public function index(){
省略
}

//画像アップロード処理
public function upload(Request $request){
省略
}
```
## Gateを使ったログイン認証切り分け
> 今回は一番簡単な０と１のflagを使った直接管理
> 0の時は無料会員
> 1の時は有料会員
### 【Userテーブルにflag管理カラム追加】
#### 1.userテーブルにflagを追加する為にマイグレーションファイルに下記追加

`$table->integer('flag')->default(0);`

#### 2.migrate　refreshしてテーブルにカラム追加実行
`php artisan migrate:refresh`

### 【Gate処理の作成】
#### 1.AuthServiceProvider.phpのboot()メソットの中に処理を追記
```
//プレミア会員用のみ許可（flagが1の人のみ許可）
Gate::define('premier-only',function($user){

    return($user->flag == 1);
});
```

#### 2.web.phpに認可した場合のGroupを作成しその中にプレミア会員向けルーティングを入れる
```
// プレミア会員用のルーティング
Route::group(['middleware' => ['auth', 'can:premier-only']], function () {

    //メール送信フォームを表示
    Route::get('/mail', [MailController::class, 'index']);
    
    //メール送信処理
    Route::post('/mail/send',  [MailController::class, 'send']);
    
});
```


## ページ毎にCSSを実装したい場合
#### 1. views/layout/app.phpのheadタグ内に以下を追記
` @stack('css')`
#### 2. publicのcssフォルダの中にオリジナルCSSファイル（〇〇.css）を作成
#### 3.呼び出したいbladeの＠extends()の直下に記述
```
@push('css')
    <!-- 場所はpublicフォルダ内のcssフォルダの中です -->
    <link href="{{ asset('css/〇〇.css') }}" rel="stylesheet">
@endpush
```
## ページ毎にjsを実装したい場合
#### 1. views/layout/app.phpのbody終了タグ直前に以下を追記
` @stack('js')`

#### 2. publicのjsフォルダの中にオリジナルJSファイル（〇〇.js）を作成
#### 3.呼び出したいbladeの@endsectionの直上に記述
```
@push('js')
    <!-- 場所はpublicフォルダ内のjsフォルダの中です -->
    <script src="{{ asset('js/〇〇.js') }}"></script>
@endpush
```
##### レイアウトの組み方などの参考記事
https://nodoame.net/archives/10756

https://qiita.com/yktk435/items/cc606f915859872eec9a

https://engineering.mobalab.net/2019/03/08/laravel%E3%81%AE%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%81%A7%E3%81%AEinclude-yield-section%E3%81%AE%E9%81%95%E3%81%84/

## CRUD構築ショートver
### 【データベースにbooksテーブルを作成して対応するモデル、コントローラ、マイグレーションファイルを一括作成】
#### 1. artisanコマンド（Bookモデルを作成/migrationとcontrollerを作成/オプションで-r, --resourceつまりCRUD関数も作っとく）
```
Bookモデルの場合は

php artisan make:model Book -mc -r

```
#### 2. booksのマイグレーションファイルの中に以下を追記
```
public function up()
    {
        Schema::create('books', function (Blueprint $table) {
            $table->id();
            $table->string('title');//追記
            $table->text('body');//追記
            $table->timestamps();
        });
    }
```

#### 3. マイグレーション実行
`php artisan migrate`

#### 4. routes/web.phpにルーティングを記述
```
use App\Http\Controllers\BookController;//追記

// books用の一括ルーティング
Route::resource('books', BookController::class);
  
```

#### 5. App/Models/Book.phpにのClassの中に以下を追記
```
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
    use HasFactory;
    protected $fillable = ['title','body']; //これを追加！
}
```



### 【CRUD処理を作っていく】

#### 1. indexメソッド（一覧表示）
```
public function index()
    {
        $books = Book::all();
        return view('books',compact('books'));
    }
```

#### 2. storeメソッド（登録処理）
```
public function store(Request $request)
    {
         $storeData = $request->validate([
            'title' => 'required|max:255',
            'body' => 'required|max:255',
        ]);
        $books = Book::create($storeData);
        return redirect('/books')
    }
```

#### 3. editメソッド（更新画面表示）
```
public function edit(Book $book)
    {
        return view('booksedit',compact('book'));
    }
```

#### 4. updateメソッド（更新処理）
```
 public function update(Request $request, Book $book)
    {
        $updateData = $request->validate([
            'title' => 'required|max:255',
            'body' => 'required|max:255',
        ]);
        $book->update($updateData);
        return redirect('/books');
    }
```

#### 5. destroyメソッド（削除処理）
```
 public function destroy(Book $book)
    {
        $book->delete();
        return redirect('/books');
    }
```

### 【表示画面を作成】
#### 1.books.blade.php
```
<!-- resources/views/books.blade.php -->
 @extends('layouts.app')
 @section('content')
     <!-- Bootstrapの定形コード… -->
     <div class="card-body">
         <div class="card-title">
             本のタイトル
         </div>
         <!-- バリデーションエラーの表示に使用-->
         <!-- 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
         <!-- バリデーションエラーの表示に使用-->
         <!-- 本登録フォーム -->
         <form action="{{ url('books') }}" method="POST" class="form-horizontal">
             {{ csrf_field() }}
             <!-- 本のタイトル -->
             <div class="form-group">
                 <label for="title">Title</label>
                 <div class="col-sm-6">
                     <input type="text" name="title" class="form-control">
                 </div>
             </div>
             <!-- 本のタイトル -->
             <div class="form-group">
                 <label for="body">本文</label>
                 <div class="col-sm-6">
                     <input type="text" name="body" 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>
     <!-- Book: 既に登録されてる本のリスト -->
     <!-- 現在の本 -->
     @if (count($books) > 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 ($books as $book)
                             <tr>
                                 <!-- 本タイトル -->
                                 <td class="table-text">
                                     <div>{{ $book->title }}</div>
                                 </td>
                                 <!-- 本タイトル -->
                                 <td class="table-text">
                                     <div>{{ $book->body }}</div>
                                 </td>
 			                    <!-- 本: 削除ボタン -->
                                 <td>
                                    <form action="{{ url('books/'.$book->id) }}" method="POST">
                                         {{ csrf_field() }}
                                         {{ method_field('DELETE') }}
                                         <button type="submit" class="btn btn-danger">
                                             削除
                                         </button>
                                    </form>
                                 </td>
                                 <td>
                                	<form action="{{ url('books/'.$book->id.'/edit') }}" method="GET"> {{ csrf_field() }}
                                	    <button type="submit" class="btn btn-primary">更新 </button>
                                	</form>
                                 </td>
                             </tr>
                         @endforeach
                     </tbody>
                 </table>
             </div>
         </div>		
    @endif
 @endsection
 ```
 
#### 2.booksedit.blade.php
```
@extends('layouts.app')
@section('content')
<div class="row">
    <div class="col-md-12">
    <!-- 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
        <form action="{{ url('books/'.$book->id) }}" method="POST">
            @method('PATCH')
            <!-- item_name -->
            <div class="form-group">
                <label for="title">Title</label>
                <input type="text" name="title" class="form-control" value="{{$book->title}}">
            </div>
            <!-- item_name -->
            <div class="form-group">
                <label for="body">本文</label>
                <input type="text" name="body" class="form-control" value="{{$book->body}}">
            </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="{{$book->id}}" /> <!--/ id 値を送信 -->
            <!-- CSRF -->
            {{ csrf_field() }}
            <!--/ CSRF -->
        </form>
    </div>
</div>
@endsection
```
### 【Laravelプロジェクトのルーティング一覧を見るときのコマンド】
`php artisan route:list`
```
Failed loading /usr/lib64/php/modules/xdebug.so:  /usr/lib64/php/modules/xdebug.so: undefined symbol: gc_globals

  GET|HEAD        / ......................................................................................................................................... 
  POST            _ignition/execute-solution .................................. ignition.executeSolution › Spatie\LaravelIgnition › ExecuteSolutionController
  GET|HEAD        _ignition/health-check .............................................. ignition.healthCheck › Spatie\LaravelIgnition › HealthCheckController
  POST            _ignition/update-config ........................................... ignition.updateConfig › Spatie\LaravelIgnition › UpdateConfigController
  GET|HEAD        api/user .................................................................................................................................. 
  GET|HEAD        books .................................................................................................. books.index › BookController@index
  POST            books .................................................................................................. books.store › BookController@store
  GET|HEAD        books/create ......................................................................................... books.create › BookController@create
  GET|HEAD        books/{book} ............................................................................................. books.show › BookController@show
  PUT|PATCH       books/{book} ......................................................................................... books.update › BookController@update
  DELETE          books/{book} ....................................................................................... books.destroy › BookController@destroy
  GET|HEAD        books/{book}/edit ........................................................................................ books.edit › BookController@edit
  GET|HEAD        home .......................................................................................................... home › HomeController@index
  GET|HEAD        login .......................................................................................... login › Auth\LoginController@showLoginForm
  POST            login .......................................................................................................... Auth\LoginController@login
  POST            logout ............................................................................................... logout › Auth\LoginController@logout
  GET|HEAD        password/confirm ........................................................ password.confirm › Auth\ConfirmPasswordController@showConfirmForm
  POST            password/confirm ................................................................................... Auth\ConfirmPasswordController@confirm
  POST            password/email .......................................................... password.email › Auth\ForgotPasswordController@sendResetLinkEmail
  GET|HEAD        password/reset ....................................................... password.request › Auth\ForgotPasswordController@showLinkRequestForm
  POST            password/reset ....................................................................... password.update › Auth\ResetPasswordController@reset
  GET|HEAD        password/reset/{token} ........................................................ password.reset › Auth\ResetPasswordController@showResetForm
  GET|HEAD        register .......................................................................... register › Auth\RegisterController@showRegistrationForm
  POST            register ................................................................................................. Auth\RegisterController@register
  GET|HEAD        sanctum/csrf-cookie ........................................................................... Laravel\Sanctum › CsrfCookieController@show

                                                                                                                                          Showing [25] routes
```