初めてのLaravel9 ~jetstreamを添えて~

# はじめに

本記事は初めてLaravelを扱ってのプロトタイプのアプリ開発の概要になります。
Laravelを初めて触ってアプリ開発をする方向けです。

### バージョン
PHP 8.0.3
Laravel Installer 4.2.8
Composer version 2.1.6
Node v16.13.0
Laravel v9.17.0
OS Windows

※最低条件
SMS送信受信ができないとアプリパスワードが発行できません。

# 目次
[1.プロジェクト作成](#1-プロジェクト作成)
[2.jetstreamのインストール](#2-jetstreamのインストール)
[3.sanctumのインストール](#3-sanctumのインストール)
[4.日本語化](#4-日本語化)
[5.新規登録時のメール認証](#5-新規登録時のメール認証)
[6.プロフィールにアイコン画像を追加](#6-プロフィールにアイコン画像を追加)

# 1 プロジェクト作成

※sample-projectの部分は任意のアプリ名

```diff_ruby:コマンドプロンプト
C:\xampp\htdocs> composer create-project laravel/laravel sample-project
```

# 2 jetstreamのインストール
※今回は自作でグループ機能を作成するのでjetstreamのチーム機能は使わない

```diff_ruby:コマンドプロンプト
C:\xampp\htdocs> cd .\sample-project
C:\xampp\htdocs\sample-project> composer require laravel/jetstream
C:\xampp\htdocs\sample-project> php artisan jetstream:install livewire
```
.envファイルのDB_DATABASEの名前を任意のデータベース名を記載 ※ここではlaravel-sample-projectという名前にしている
```diff_ruby:.env
- DB_DATABASE=laravel
+ DB_DATABASE=laravel-sample-project
```

phpmyadmin (http://localhost/phpmyadmin/index.php) にて.envファイルで付けた名前と同じデータベースを作成する
![スクリーンショット 2022-06-14 145459.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2706288/bd6ce8f8-1829-e14b-b569-7a6f8ec6f9d6.png)

css,jsのビルド
```diff_ruby:コマンドプロンプト
C:\xampp\htdocs\sample-project> npm install
C:\xampp\htdocs\sample-project> npm run dev
```

作成したデータベースとlaravelを繋げる
```diff_ruby:コマンドプロンプト
C:\xampp\htdocs\sample-project> php artisan migrate
```

jetstreamで作成された隠しフォルダの中にメールなどのUIの設定が書かれているため後で変更するように表示させておく。
#resources/views/vendor/jetstream ディレクトリが出現する。
```diff_ruby:コマンドプロンプト
C:\xampp\htdocs\sample-project> php artisan vendor:publish --tag=jetstream-views 
```

# 3 sanctumのインストール
```diff_ruby:コマンドプロンプト
C:\xampp\htdocs\sample-project> composer require laravel/sanctum
```

# 4 日本語化
[https://github.com/Laravel-Lang/lang](https://github.com/Laravel-Lang/lang) からzipファイルとしてダウンロードする。
![スクリーンショット 2022-06-14 152153.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2706288/ab7f9240-dbad-2f99-4ceb-350ef90c6609.png)
解凍したらlang-main\locales\jaフォルダをコピーしてsample-project\resources\langの下に貼りつける。
jaフォルダを開き、中にあるja.jsonをlangフォルダ直下に移動させる。
※langフォルダがない場合は作ってください。
![スクリーンショット 2022-06-14 153111.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2706288/c66c9a7c-b2e5-9f72-701f-17538830ec3a.png)

sample-project\config\app.phpの中身を日本形式に変更
```diff_ruby:app.php
- 'timezone' => 'UTC',
+ 'timezone' => 'Asia/Tokyo',

- 'locale' => 'en',
+ 'locale' => 'ja',

- 'fallback_locale' => 'en',
+ 'fallback_locale' => 'ja',

- 'faker_locale' => 'en_US',
+ 'faker_locale' => 'ja_JP',
```

# 5 新規登録時のメール認証

config\fortify.phpの中身を変更

```diff_ruby:fortify.php
<?php

use App\Providers\RouteServiceProvider;
use Laravel\Fortify\Features;

return [

    // 省略

    'features' => [
        Features::registration(),
        Features::resetPasswords(),
+        Features::emailVerification(), // 👈 ここのコメントアウトを外す
        Features::updateProfileInformation(),
        Features::updatePasswords(),
        Features::twoFactorAuthentication(),
    ],

];
```

app\Models\User.phpの中身を変更
```diff_ruby:User.php
<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Jetstream\HasProfilePhoto;
use Laravel\Jetstream\HasTeams;
use Laravel\Sanctum\HasApiTokens;

- class User extends Authenticatable
+ class User extends Authenticatable implements MustVerifyEmail
{
    // 省略
```

フォームや送信される認証メールは全て英語で書かれているため、日本語に書き換える。
resources/views/auth/verify-email.blade.phpを変更
下のコードを全コピペOK。
```diff_ruby:verify-email.blade.php
<x-guest-layout>
    <x-jet-authentication-card>
        <x-slot name="logo">
            <x-jet-authentication-card-logo />
        </x-slot>

        <div class="mb-4 text-sm text-gray-600">
            ご登録ありがとうございます！<br>
            ご入力いただいたメールアドレスへ認証リンクを送信しましたので、クリックして認証を完了させてください。<br>
            もし、認証メールが届かない場合は再送させていただきます。
        </div>

        @if (session('status') == 'verification-link-sent')
            <div class="mb-4 font-medium text-sm text-green-600">
                新しい認証メールが送信されました。
            </div>
        @endif

        <div class="mt-4 flex items-center justify-between">
            <form method="POST" action="/email/verification-notification">
                @csrf

                <div>
                    <x-jet-button type="submit">
                        認証メールを再送する
                    </x-jet-button>
                </div>
            </form>

            <form method="POST" action="/logout">
                @csrf

                <button type="submit" class="underline text-sm text-gray-600 hover:text-gray-900">
                    ログアウト
                </button>
            </form>
        </div>
    </x-jet-authentication-card>
</x-guest-layout>
```
認証メールを日本語化するには、専用のNotificationをつくって実装します。
```diff_ruby:コマンドプロンプト
C:\xampp\htdocs\sample-project> php artisan make:notification VerifyEmailJapanese
```

すると、ファイルが作成されるので中身を次のように変更してください。
app/Notifications/VerifyEmailJapanese.phpの中を変更
下のコードを全コピペOK。
```diff_ruby:VerifyEmailJapanese.php
<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Lang;
use Illuminate\Support\Facades\URL;

class VerifyEmailJapanese extends Notification
{
    /**
     * The callback that should be used to build the mail message.
     *
     * @var \Closure|null
     */
    public static $toMailCallback;

    /**
     * Get the notification's channels.
     *
     * @param  mixed  $notifiable
     * @return array|string
     */
    public function via($notifiable)
    {
        return ['mail'];
    }

    /**
     * Build the mail representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return \Illuminate\Notifications\Messages\MailMessage
     */
    public function toMail($notifiable)
    {
        $verificationUrl = $this->verificationUrl($notifiable);

        if (static::$toMailCallback) {
            return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
        }

        return (new MailMessage)
            ->subject(Lang::get('メールアドレスを認証してください'))
            ->line(Lang::get('以下のボタンをクリックしてメールアドレスを認証してください'))
            ->action(Lang::get('認証する'), $verificationUrl)
            ->line(Lang::get('（もしこのメールに覚えがない場合は放置して問題ございません）'));
    }

    /**
     * Get the verification URL for the given notifiable.
     *
     * @param  mixed  $notifiable
     * @return string
     */
    protected function verificationUrl($notifiable)
    {
        return URL::temporarySignedRoute(
            'verification.verify',
            Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
            [
                'id' => $notifiable->getKey(),
                'hash' => sha1($notifiable->getEmailForVerification()),
            ]
        );
    }

    /**
     * Set a callback that should be used when building the notification mail message.
     *
     * @param  \Closure  $callback
     * @return void
     */
    public static function toMailUsing($callback)
    {
        static::$toMailCallback = $callback;
    }
}
```

app/Models/User.phpを変更
```diff_ruby:User.php
// 省略

class User extends Authenticatable implements MustVerifyEmail
{
    // 省略

    // 👇 ここを追加しました
+    public function sendEmailVerificationNotification()
+    {
+        $this->notify(new \App\Notifications\VerifyEmailJapanese);
+    }
}
```
ただし、実はこれだけで以下のように中途半端な日本語化になります。
これはEmail Verificationの問題ではなく、Notification本体での設定になります。
では、パッケージからこの部分のビューをLaravel本体へコピーして日本語化していきましょう。
以下のコマンドを実行してください。
```diff_ruby:コマンドプロンプト
C:\xampp\htdocs\sample-project> php artisan vendor:publish
```

すると、コピーできるリストが表示されますので、「laravel-notifications」と書かれている番号を入力してEnterキーを押してください（番号は環境によって違うと思います）
![スクリーンショット 2022-06-14 223628.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2706288/ba27f5a0-02ac-43f8-5fd3-821196ecb8ee.png)

これで、ファイルのコピーが完了したので実際に日本語化していきましょう。
resources/views/vendor/notifications/email.blade.phpを変更
下のコードを全コピペOK。
```diff_ruby:email.blade.php
@component('mail::message')
{{-- Greeting --}}
@if (! empty($greeting))
# {{ $greeting }}
@else
@if ($level === 'error')
# @lang('エラー発生')
@else
# @lang('こんにちは!')
@endif
@endif

{{-- Intro Lines --}}
@foreach ($introLines as $line)
{{ $line }}

@endforeach

{{-- Action Button --}}
@isset($actionText)
<?php
    switch ($level) {
        case 'success':
        case 'error':
            $color = $level;
            break;
        default:
            $color = 'primary';
    }
?>
@component('mail::button', ['url' => $actionUrl, 'color' => $color])
{{ $actionText }}
@endcomponent
@endisset

{{-- Outro Lines --}}
@foreach ($outroLines as $line)
{{ $line }}

@endforeach

{{-- Salutation --}}
@if (! empty($salutation))
{{ $salutation }}
@else
ご利用ありがとうございました！<br>
{{ config('app.name') }}
@endif

{{-- Subcopy --}}
@isset($actionText)
@slot('subcopy')
@lang(
    "もし「:actionText」ボタンをクリックしてもうまく移動できない場合は、以下のURLを直接ブラウザにコピー＆ペーストしてください。\n",
    [
        'actionText' => $actionText,
    ]
) <span class="break-all">[{{ $displayableActionUrl }}]({{ $actionUrl }})</span>
@endslot
@endisset
@endcomponent
```
.envを変更
```diff_ruby:.env
- MAIL_HOST=mailhog
+ MAIL_HOST=smtp.gmail.com

- MAIL_PORT=1025
+ MAIL_PORT=587

- MAIL_USERNAME=null
+ MAIL_USERNAME=管理者のメアド

- MAIL_PASSWORD=null
+ MAIL_PASSWORD=管理者のメアドの16桁のアプリパスワード

- MAIL_ENCRYPTION=null
+ MAIL_ENCRYPTION=tls

- MAIL_FROM_ADDRESS="hello@example.com"
+ MAIL_FROM_ADDRESS=管理者のメアド
```

ここら辺で一度エラーが出ないことを確認することを推奨します。
下のコマンドでサーバを開き新規登録、認証、ログインまでを確認しましょう。
```diff_ruby:コマンドプロンプト
C:\xampp\htdocs\sample-project> php artisan serve
```

下の画像のようにメール認証メールが届けばOK。
![スクリーンショット 2022-06-14 230632.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2706288/568b399d-d792-bbb9-ed5f-208b5b95d172.png)

jetstream導入時にリダイレクト先がdashboardに変更されるのでrootページに変更する。
app\providers\RouteServiceProvider.phpを変更。
```diff_ruby:RouteServiceProvider.php
- public const HOME = '/dashboard';
+ public const HOME = '/';
```
# 6 プロフィールにアイコン画像を追加
config\jetstream.phpを変更
```diff_ruby:jetstream.php
//省略

    'features' => [
        // Features::termsAndPrivacyPolicy(),
+        Features::profilePhotos(),  // 👈 ここのコメントアウトを外す
        // Features::api(),
        Features::teams(['invitations' => true]),
        Features::accountDeletion(),
    ],

//省略
```
保存場所へシンボリックリンクを貼る
```diff_ruby:コマンドプロンプト
C:\xampp\htdocs\sample-project> php artisan storage:link
```

環境に合わせてURLも変更する
```diff_ruby:.env
- APP_URL=http://localhost
+ APP_URL=http://127.0.0.1:8000
```
storage\app\public\profile-photosの中に画像は保存されます。

# おわりに
今回はここまでで次回以降ではニックネームの追加、チーム機能の拡張、UI、デザインなども含めて記載していく予定。