1️⃣

【Laravel】CRUD機能を作成する①登録機能(Create)

2023/07/11に公開

はじめに

こちらで構築した環境を使用し、
https://zenn.dev/nenenemo/articles/46d43854cd01c5

この記事のレイアウトの共通化までは済んでいるものとします。
https://zenn.dev/nenenemo/articles/e09fd01c0a3a47

登録した内容が表示されるようにしたいと思います。

CRUD操作とは

データベースなどの基本的な操作を指す、Create(作成)、Read(読み取り)、Update(更新)、Delete(削除)の頭文字を並べた用語です。

登録機能(Create)の作成

今回は名前、メールアドレス、パスワードをデータベースに登録できるようにしてみます。

users/create.blade.phpという登録のためのページを作成してください。

php artisan make:view users/create
create.blade.php
@extends('layouts.app')

@section('title', '新規作成')

@section('content')
    <form method="POST" action="{{ route('users.store') }}">
        @csrf
        <div>
            <h1 class='text-center font-bold '>新規作成</h1>
            <!-- 名前フィールド -->
            <div class="mt-4">
                <label for="name">名前</label>
                <input id="name" type="text"
                    class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
                    name="name" value="{{ old('name') }}" required placeholder="">
            </div>

            <!-- メールアドレスフィールド -->
            <div class="mt-4">
                <label for="email">メールアドレス</label>
                <input id="email" type="email"
                    class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
                    name="email" value="{{ old('email') }}" required placeholder="">
            </div>

            <!-- パスワードフィールド -->
            <div class="mt-4">
                <label for="password">パスワード</label>
                <input id="password" type="password"
                    class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
                    name="password" required placeholder="">
            </div>

            <!-- 登録ボタン -->
            <div class="flex items-center justify-center my-4">
                <button type="submit">
                    登録を完了する
                </button>
            </div>
        </div>
    </form>
@endsection

method="POST"

フォームデータを送信するHTTPメソッドを指定しています。

action="{{route('users.store')}}"

フォームデータの送信先のURLを指定します。route('users.store')は、名前付きルートを使用してusers.storeというルートのURLを生成します。このusers.stoeというURLは、データの処理を担当するコントローラーのアクションに対応しています。

@csrf

CSRF攻撃対策のための記述で、、LaravelのCSRFミドルウェアがトークンを生成し、フォーム送信時にそのトークンを要求することで保護が行われます。

Laravelでフォームを作るときは、必ず入力する必要があります。
https://readouble.com/laravel/11.x/ja/csrf.html

CSRF攻撃とは

CSRF(Cross-Site Request Forgery)攻撃は、Webページなどのセッション情報を利用して、被害者の代わりにサーバーに不正なリクエストを送信する攻撃です。

old

直前のリクエストで入力された値を取得するために使用されます。
ユーザーが再送信した場合に、以前に入力された値がフォームに表示されます。
https://laravel.com/docs/11.x/requests#old-input

パスワードフィールドに関して、oldを記述していない理由は、セキュリティ上の理由から関数が機能しないためです。パスワードフィールドには過去に入力された値を再表示する必要はなく、新しいパスワードを入力する必要があるため、セキュリティ上のリスクを回避するために、過去のパスワードは表示されません。

Model作成

既にUser.phpが作成されていると思うので、今回はこちらを使用します。
Laravelではデータベースのテーブルをモデルと呼ばれるクラスとして扱かっています。

app/models/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;

class User extends Authenticatable
{
    use HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * Get the attributes that should be cast.
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'password' => 'hashed',
        ];
    }
}

$hidden

モデルのインスタンスを配列や JSON 形式に変換する際に、隠したい属性を指定します。通常、パスワードやリメンバートークンなどの機密情報を隠すために使用されます。

上記の例では、passwordremember_tokenの2つの属性が隠されています。

casts()

モデルの属性をデータベースから取得する際に変換する方法を指定します。
例えば、email_verified_atフィールドはデータベースには文字列として格納されますが、Eloquentはこれを取得するときに自動的に日付と時刻のCarbonインスタンスに変換します。

passwordフィールドはデータベースにはハッシュ化された形式で格納されますが、Eloquentはこの値をそのまま取得します。これにより、モデルの取得時にパスワードが自動的にハッシュ化され、データベース内のパスワードを直接見ても元のパスワードを特定することは困難になるのでセキュリティが向上します。

Eloquent

LaravelのORMであり、データベースとPHPオブジェクトをマッピングするための便利な方法を提供しています。つまり、データベースのテーブルをPHPのクラスとして表現し、テーブルの行をPHPオブジェクトとして操作できます。

ORM

ORM(Object-Relational Mapping)は、データベースとオブジェクト指向プログラミング言語間でデータをやり取りする手法です。

ORMを使用すると、SQLクエリを直接書かずにオブジェクトを操作できます。例えば、データベースのテーブルに新しい行を挿入する場合、SQL INSERT文を書く代わりに、オブジェクトを作成して保存するだけで済みます。ORMは、データベースのテーブルとオブジェクトの間でデータを自動的に変換し、処理を行います。

Carbon

DateTimeクラスの拡張で、日付と時刻を操作するための便利なツールです。

Eloquentは、データベースから取得した日付と時刻の値を自動的にCarbonインスタンスに変換します。これにより、取得した日付や時刻を直感的かつ簡単に操作できるようになります。例えば、データベースに格納された日付を加算したり、フォーマットしたりする際に便利です。

ちなみに、モデルは以下のコマンドで作成することができます。

php artisan make:model <モデル名>
// 引数にオプションを指定可能 マイグレーションやコントローラーを同時作成
php artisan make:model <モデル名> --migration
php artisan make:model <モデル名> --controller

Controller作成

UsersControllerというファイルを作成してください。

php artisan make:controller UsersController --resource --model=User

リソースコントローラー

CRUD操作に関連するアクションが定義されたコントローラーです。

--resourceオプション

このコントローラーはリソースコントローラーとして作成され、CRUD操作に関連するアクションが一括で生成されるのでコントローラーの作成が簡素化されます。

--modelオプション

指定したモデルに対するリソースコントローラーが生成されます。

app/Http/Controllers/UsersController
<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;

class UsersController
{
    /**
     * Display a listing of the resource.
     */
    public function index()
    {
        //
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        //
    }

    /**
     * Display the specified resource.
     */
    public function show(User $user)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(User $user)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, User $user)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(User $user)
    {
        //
    }
}

次にControllerにcreatestoreメゾットに下記を追記します。

app/Http/Controllers/UsersController
<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;

class UsersController
{
    public function create()
    {
        return view('users.create'); // ここで 'create.blade.php' ビューを返します
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        try {
            // $userインスタンスを作成する
            $user = new User();

            // 投稿フォームから送信されたデータを取得し、インスタンスの属性に代入する
            $user->name = $request->input('name');
            $user->email = $request->input('email');
            $user->password = $request->input('password');

            // データベースに保存
            $user->save();

            return back();
        } catch (\Exception $e) {
            return redirect()->route('users.create')->with('message', '登録に失敗しました。' . $e->getMessage());
        }
    }
}

withメソッド

任意のデータをセッションにフラッシュ(一時保存)するために使用されます。セッションにデータを保存すると、次のリクエストまでの間だけそのデータがセッションに存在し、その後は自動的に消去されます。

リダイレクトを使用して次のリクエストに渡す場合に使用されるため、redirectメソッドまたはbackメソッドと一緒に使用する必要があります。
https://laravel.com/docs/11.x/responses#redirecting-with-flashed-session-data

基本的な構文

->with('key', 'value')

リダイレクト先のページに以下を記述することでセッションからメッセージを取得し、その値が表示されます。

   @if (session('message'))
       <div>{{ session('message') }}</div>
   @endif

withを使用しセッションにデータを保存する

app/Http/Controllers/UsersController.php
redirect()->route('users.create')->with(compact('user'));

リダイレクト後のビューファイル内で、次のようにしてセッションからデータを取り出すことができます。

create.blade.php
@if (session('user'))
    {{ session('user')->name }}
@endif

redirectメソッド

新しいHTTPリクエストを伴うリダイレクトを行います。

// ルート名を指定
redirect()->route('route.name')

// URLを指定
return redirect('/redirect');

backメソッド

元のページに戻ります。
https://laravel.com/docs/11.x/helpers#method-back

session(セッション)

ウェブアプリケーションにおいて、クライアントとサーバー間で状態を維持するための仕組みです。

$e->getMessage()

エラーの場合に詳しいエラー内容が表示されるようになります。

ルート設定

routes/web.phpは、Webルートを定義するためのファイルです。
このファイルでは、HTTPリクエストがどのコントローラーのアクションにルーティングされるかを定義します。

routes/web.php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UsersController;

Route::get('/', function () {
    return view('welcome');
});
Route::get('/users/create', [UsersController::class, 'create'])->name('users.create');
Route::post('/users/store', [UsersController::class, 'store'])->name('users.store');

require __DIR__ . '/auth.php';

require DIR .

ルートファイルに別のファイルを含めることができます。
今回はroutes/auth.phpという認証関連のルートが定義されたファイルをルートファイルに含めています。

nameメソッド

ルートに名前を付けることができます。これにより、ビューなどからルートに簡単にアクセスできるようになります。

これで登録機能は完成しているので、データベースにフォームで入力した内容が登録されているか確認してください。下記ではMySQL WorkbenchというGUIツールを使用して接続しています。

GUIツールでの接続設定
GUIツールを使用してDockerコンテナ内のMySQLに接続する場合、以下のように設定します:

ホスト: localhost(ホストマシンからアクセスするため)
ポート: 3306(または docker-compose.yml で設定したフォワードされたポート)
ユーザー名: sail(あなたが .env ファイルで設定したユーザー名)
パスワード: password(あなたが設定したパスワード)

Docker内のサービスには内部的な名前解決(DB_HOST=mysql)が適用され、ホストマシンからはlocalhostを経由してアクセスするため、GUIツールで接続する際には、ホスト名をlocalhostと指定して接続する必要があります。

Webルートを定義は下記の記述方法もあります。

Route::resource

Route::resourceを使うとリソースコントローラーを定義することができます。
UserControllerがリソースコントローラーなので、以下のような各アクションに対応するURLパターン、ルート名、およびHTTPメソッドを提供しています。

メソッド URL ルート名 HTTPメソッド
index /users users.index GET
create /users/create users.create GET
store /users users.store POST
show /users/{id} users.show GET
edit /users/{id}/edit users.edit GET
update /users/{id} users.update PUT/PATCH
destroy /users/{id} users.destroy DELETE

onlyメソッド

指定したアクションのみを含むルートを生成します。この場合、'create'と'store'のみが含まれます。

routes/web.php
Route::resource('users', UsersController::class)->only([
    'create', 'store'
]);

Route::prefix

ルートのURIにプレフィックス(特定の文字列やパターンが他の文字列の先頭に付加されること)を追加するために使用されます。

Route::prefix('user')を使用すると、そのグループ内のすべてのルートに/adminプレフィックスが自動的に追加されます。

routes/web.php
Route::group(['prefix' => 'users', 'as' => 'users.', 'middleware' => 'auth'], function () {
    Route::get('/create', [UsersController::class, 'create'])->name('create');
    Route::post('/store', [UsersController::class, 'store'])->name('store');
});

'as' => 'users.'

このグループ内のすべてのルートに対して名前付きルートを定義します。
今回であれば名前付きルートは、users.で始まる接頭辞を持つので、name('create')users.createとなります。

'middleware' => 'auth'

このグループ内のすべてのルートに、authミドルウェアが適用され、これらのルートにアクセスするためには、ユーザーが認証されている必要があります。

Route::group

関連するルートをグループ化して、共通の属性を適用するために使用されます。
これにより、同じグループ内のルートに対して共通のミドルウェア、名前空間、プレフィックスなどを設定できます。

routes/web.php
Route::group(['prefix' => 'users'], function () {
Route::get('/create', [UsersController::class, 'create'])->name('users.create');
Route::post('/store', [UsersController::class, 'store'])->name('users.store');
});

トランザクション管理

storeの内容を変更してください。

app/Http/Controllers/UsersController
 public function store(Request $request)
    {
        try {
            // トランザクションを開始
            DB::beginTransaction();

            // $userインスタンスを作成する
            $user = new User();

            // 投稿フォームから送信されたデータを取得し、インスタンスの属性に代入する
            $user->name = $request->input('name');
            $user->email = $request->input('email');
            $user->password = $request->input('password');

            // データベースに保存
            $user->save();

            // トランザクションをコミット
            DB::commit();

            return back();
        } catch (\Exception $e) {
            // トランザクションをロールバック
            DB::rollBack();

             return redirect()->route('users.create')->with('message', '登録に失敗しました。' . $e->getMessage());
        }
    }

登録が完了した内容を表示する

return back()は、直前のリクエストに戻るだけで、リクエスト間でデータを保持する機能がないのでviewメソッドの記述に変更しています。

app/Http/Controllers/UsersController
    public function store(Request $request)
    {
        try {
            // トランザクションを開始
            DB::beginTransaction();

            // $userインスタンスを作成する
            $user = new User();

            // 投稿フォームから送信されたデータを取得し、インスタンスの属性に代入する
            $user->name = $request->input('name');
            $user->email = $request->input('email');
            $user->password = $request->input('password');

            // データベースに保存
            $user->save();

            // トランザクションをコミット
            DB::commit();

            return view('users.create', compact('user'))
        } catch (\Exception $e) {
            // トランザクションをロールバック
            DB::rollBack();

            return redirect()->route('users.create')with('message', '登録に失敗しました。' . $e->getMessage());
        }
    }

viewメソッド

ビューファイルの名前を受け取り、それに対応するビューを表示するHTTPレスポンスを生成します。
第二引数には連想配列を指定でき、これによりビューにデータを渡すことができます。このデータはビューファイル内で変数としてアクセスできます。
https://laravel.com/docs/11.x/views#nested-view-directories

responseメソッド

return view('users.create', compact('user'))return response()->view('users.create', compact('user'));のように記述することが可能です。

responseを使うことで、HTTPレスポンスにHTTPステータスコードを設定、レスポンスヘッダーの追加、Cookieの設定などができる点が大きなメリットです。
https://laravel.com/docs/11.x/responses#response-objects

HTTPステータスコードを設定

return response()->view('users.create', compact('user'), 201);

レスポンスヘッダーの追加

return response()
    ->view('users.create', compact('user'))
    ->header('Cache-Control', 'no-cache, no-store, must-revalidate')
    ->header('Pragma', 'no-cache')
    ->header('Expires', '0');

Cookieの設定

return response()
    ->view('users.create', compact('user'))
    ->cookie('language', 'ja', 60); // 60分間有効なCookie

compact('user')

変数の名前が直接キー名として使われます。compact('user', 'passwordChanged')のように複数記述することができます。
下記['user' => $user]のように記述しても同じ内容になります。

['user' => $user]

この記法は、明示的にキーと値を指定して配列を作成します。
左側の列のキーをを自由に指定できるので、['user' => $data]のように変数$dataをキーuserに関連付けることができます。

create.blade.php
@extends('layouts.app')

@section('title', '新規作成')

@section('content')
    <form method="POST" action="{{ route('users.store') }}">
        @csrf
        <div>
            <h1 class='text-center font-bold '>新規作成</h1>
            <div class="mt-4">
                <label for="name">名前</label>
                <input id="name" type="text"
                    class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
                    name="name" value="{{ old('name') }}" required>
            </div>

            <div class="mt-4">
                <label for="email">メールアドレス</label>
                <input id="email" type="email"
                    class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
                    name="email" value="{{ old('email') }}" required>
            </div>

            <div class="mt-4">
                <label for="password">パスワード</label>
                <input id="password" type="password"
                    class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
                    name="password" value="{{ old('password') }}" required>
            </div>

            @if (session('message'))
                <div>{{ session('message') }}</div>
            @endif

            @isset($user)
                <div>
                    <strong>ユーザー登録が完了しました。</strong>
                    <h2>登録したユーザーの情報</h2>
                    <p>名前: {{ $user->name }}</p>
                    <p>メールアドレス: {{ $user->email }}</p>
                    <p>パスワード: ********</p>
                </div>
            @endisset

            <div class="flex items-center justify-center my-4">
                <button type="submit">
                    登録を完了する
                </button>
            </div>
    </form>
@endsection

@isset

変数が定義されているかどうかをチェックするために使用されます。

http://localhost/users/create にアクセスして登録ができるか確認してください。
下記のように登録した内容が表示されると思います。

バリデーションの設定

現在でも問題なくデータは登録できていると思いますが、入力値が形式や条件を満たしているか確認したいのでフォームにバリデーションを追加します。

リクエストクラスの作成

php artisan make:request User/UserRequest

リクエストクラスが作成されます。

app/Http/Requests/UserRequest.php
<?php

namespace App\Http\Requests\User;

use Illuminate\Foundation\Http\FormRequest;

class UserRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     */
    public function authorize(): bool
    {
        return false;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
     */
    public function rules(): array
    {
        return [
            //
        ];
    }
}

namespace(名前空間)

クラス、関数、または定数などの名前が他の同名の要素と衝突することなく共存できるようにするための機能です。これは特に大規模なアプリケーションや多くのライブラリが組み込まれている場合に便利です。
https://laravel.com/docs/11.x/broadcasting#namespaces

今回UpdateUserRequestクラスはApp\Http\Requests\Userという名前空間に属しています。これにより、同じプロジェクト内の他の名前空間で`UpdateUserRequest`という名前を持つクラスが存在しても、名前の衝突を避けることができます。

連想配列の形で記述し、複数の条件を記述したい場合は|で区切ってください。

app/Http/Requests/UserRequest.php
<?php

namespace App\Http\Requests\User;

use Illuminate\Foundation\Http\FormRequest;

class UserRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     */
    public function authorize(): bool
    {
        return true; // すべてのユーザーがこのリクエストを実行できるように設定
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
     */
    public function rules(): array
    {
        return [
            'name' => 'required|max:255',
            'email' => 'required|email|unique:users,email',
            'password' => ['required', 'string', 'min:8', 'regex:/^(?=.*[a-zA-Z])(?=.*\d)(?=.*[@$!%*?&])/',],
        ];
    }
}

こちらの下の方にバリデーションの一覧が載っております!
https://readouble.com/laravel/11.x/ja/validation.html

正規表現のパイプ

Laravelのバリデーションルールでは、パイプ(|)で区切って複数のルールを指定するのが標準的な方法ですが、正規表現のパイプを含む正規表現パターンをルールに含める場合、そのような形式では正しく動作しません。

コントローラでカスタムリクエストを使用する

storeメソッドの引数の型を作成したUserRequestに変更してください。

app/Http/Controllers/UsersController
    public function store(UserRequest $request)
    {
        try {
            // トランザクションを開始
            DB::beginTransaction();

            // $userインスタンスを作成する
            $user = new User();

            // 投稿フォームから送信されたデータを取得し、インスタンスの属性に代入する
            $user->name = $request->input('name');
            $user->email = $request->input('email');
            $user->password = $request->input('password');

            // データベースに保存
            $user->save();

            // トランザクションをコミット
            DB::commit();

            return view('users.create', compact('user'))->with('message', '登録が完了しました!');
        } catch (\Exception $e) {
            // トランザクションをロールバック
            DB::rollBack();

            return back()->with('message', '登録に失敗しました。' . $e->getMessage());
        }
    }

エラーメッセージを表示する

Requestクラスを使用してフォームデータのバリデーションを行う場合、バリデーションエラーがあったときにそのエラー情報は自動的に$errorsというビューの変数に格納されます。

この変数は、ビュー内で簡単にアクセスしてエラーメッセージを表示することができる連想配列形式で提供されます。

全てのエラーメッセージを表示する場合

@foreach ($errors->all() as $error)で、$errors変数内のすべてのエラーメッセージに対して繰り返し処理を行います。

create.blade.php
@foreach ($errors->all() as $error)
  <li>{{$error}}</li>
@endforeach

特定のエラーメッセージを表示する場合

@errorを使用して項目を指定します。

create.blade.php
@error('name')
  <li>{{$message}}</li>
@enderror
create.blade.php
@extends('layouts.app')

@section('title', '新規作成')

@section('content')
    <form method="POST" action="{{ route('users.store') }}">
        @csrf
        <div>
            <h1 class='text-center font-bold '>新規作成</h1>
            <!-- 名前フィールド -->
            <div class="mt-4">
                <label for="name">名前</label>
                <input id="name" type="text"
                    class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
                    name="name" value="{{ old('name') }}" required>
                @error('name')
                    <div class="text-red-500">{{ $message }}</div>
                @enderror
            </div>

            <!-- メールアドレスフィールド -->
            <div class="mt-4">
                <label for="email">メールアドレス</label>
                <input id="email" type="email"
                    class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
                    name="email" value="{{ old('email') }}" required>
                @error('email')
                    <div class="text-red-500">{{ $message }}</div>
                @enderror
            </div>

            <!-- パスワードフィールド -->
            <div class="mt-4">
                <label for="password">パスワード</label>
                <input id="password" type="password"
                    class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
                    name="password" value="{{ old('password') }}" required>
                @error('password')
                    <div class="text-red-500">{{ $message }}</div>
                @enderror
            </div>

            <!-- セッションメッセージ -->
            @if (session('message'))
                <div>{{ session('message') }}</div>
            @endif

            <!-- ユーザー情報 -->
            @isset($user)
                <div>
                    <h2>登録したユーザーの情報</h2>
                    <p>名前: {{ $user->name }}</p>
                    <p>メールアドレス: {{ $user->email }}</p>
                    <p>パスワード: ********</p>
                </div>
            @endisset

            <!-- 登録ボタン -->
            <div class="flex items-center justify-center my-4">
                <button type="submit">
                    登録を完了する
                </button>
            </div>
        </div>
    </form>
@endsection

エラー文を日本語にする

現在の場合、エラー文が英語で表示されてしまいます。

タイムゾーンと言語設定の変更

config/app.phpの修正
68、80行目あたりの内容を修正してください。

下記では環境変数APP_LOCALEの値を取得し、その値を使用しています。もし環境変数が設定されていない場合、デフォルトとして'en'(英語)が使用されます。

'timezone' => env('APP_TIMEZONE', 'UTC'),

'locale' => env('APP_LOCALE', 'en'),

'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'),

'faker_locale' => env('APP_FAKER_LOCALE', 'en_US')

修正後

'timezone' => 'Asia/Tokyo',

'locale' => env('APP_LOCALE', 'ja'),

'fallback_locale' => env('APP_FALLBACK_LOCALE', 'ja'),

'faker_locale' => env('APP_FAKER_LOCALE', 'ja_JP')

.envの修正

APP_TIMEZONE=UTC
APP_LOCALE=en
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US

修正後

APP_TIMEZONE=Asia/Tokyo
APP_LOCALE=ja
APP_FALLBACK_LOCALE=ja
APP_FAKER_LOCALE=ja_JP

言語ファイルの作成

Laravelはデフォルトで言語ファイル(langディレクトリ)を用意していないので、作成してください。
ますはlangディレクトリを作成してください。

php artisan lang:publish

実行後、lang/enディレクトリが作成されており、以下にauth.phppagination.phppasswords.phpvalidation.phpの4つのファイルが作成されていると思います。

Laravel Breezeを日本語化するパッケージがあるのですが、そちらを使用して各種バリデーションメッセージが日本語化されたファイルを作成することが可能です。

composer require askdkc/breezejp --dev
php artisan breezejp

https://github.com/askdkc/breezejp

lang/jaディレクトリが作成され、日本語のバリデーションが設定されているのがわかると思います。

確認するとエラーメッセージが日本語になっていることがわかると思います。

バリデーションエラーメッセージのカスタマイズ

現在の場合は8文字以上の場合のエラー文は次のようになっており、どの正規表現が満たされていないかわかりません。

バリデーションエラーメッセージをカスタマイズして正規表現が満たされていないことがわかるようにします。

app/Http/Requests/UserRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UserRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     */
    public function authorize(): bool
    {
        return true; // すべてのユーザーがこのリクエストを実行できるように設定
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
     */
    public function rules(): array
    {
        return [
            'name' => 'required|max:255',
            'email' => 'required|email|unique:users,email',
            'password' => ['required', 'string', 'min:8', 'regex:/^(?=.*[a-zA-Z])(?=.*\d)(?=.*[@$!%*?&])/',],
        ];
    }

    /**
     * Get the error messages for the defined validation rules.
     *
     * @return array<string, string>
     */
    public function messages(): array
    {
        return [
            'password.regex' => 'パスワードは少なくとも1つの半角英字、数字、および記号(@$!%*?&)を含む必要があります。',
        ];
    }
}

エラー文が変更されているのを確認してください。

次はCRUDの②読み取り機能(Read)についての記事を書いています!
https://zenn.dev/nenenemo/articles/b9da36f99b58b2

終わりに

何かありましたらお気軽にコメント等いただけると助かります。
ここまでお読みいただきありがとうございます🎉

Discussion