Laravel版 YelpCampデモ

この記事にはプロモーションが含まれています。

以前の記事でご紹介した、PHP版のYelpCampというWEBアプリをLaravelで実装してみます。前回はフレームワークを使用せずに実装していたので、今回はもっと効率的に実装できると思われます。同時にLaravelを使用した開発手順を備忘録として残します。使用するLaravelのバージョンは12になっています。開発環境はWSL2とVSCodeを使用しています。

実際に試されたい方はこの記事やこちらの記事等を参考にして、WEBサーバー(Apache2)とデータベース(MySQL)とPHPおよびComposerをインストールしておいて下さい。あまり仮想環境を重ねたくないので今回もDockerを使用せずにWSL2に直接インストールします。そのため環境設定に少し手間がかかります。(データベースを手動で作成する必要があります。手間的にはWordPressのインストールより簡単と思われます。) 今回移植したアプリはこちらからダウンロードできます。

前回に引き続き記事を作成するにあたり、以下の講座で勉強させていただきました。Laravelは4.1の頃から使用されているらしく講師の方の知識がとても豊富です。通常はLaravelとDockerをセットで学習することが多いですが、この講座はLaravel自体の機能を体系的に学ぶことに特化した講座になっています。

Udemy

【Laravel 11】しっかり体系的に学ぶ Laravel 11 基礎講座

さらに今回は追加で以下の講座で勉強させていただきました。LaravelだけではなくDockerや周辺技術等の広範囲な知識が習得できます。

Udemy

【HTML,CSS,JS,PHP,Git,Docker】プログラミング初心者OK! ゼロからわかるWebシステム開発

アプリケーションのひな型を作成します

この記事では自分のホームディレクトリ(/home/user01等)に、「YelpCampLaravel」というアプリケーションを作成する前提でご説明しています。ご自身の環境に合わせて適宜ディレクトリ名を読み替えてください。基本的にこちらの記事でご紹介したアプリの移植作業となります。最終的にWEBサーバー(Apache2)の仮想ディレクトリで動作させることを目指します。

WSL2のターミナル画面で、自分のホームディレクトリに移動してユーザー権限で以下のコマンドを実行します。

composer create-project laravel/laravel YelpCampLaravel

作成されたプロジェクトディレクトリに移動して、「code .」と入力してVSCodeを起動します。

cd YelpCampLaravel
code .
データベースを設定します

起動したVSCodeに「Ctrl + @」と入力してターミナル画面を表示して、以下の様に入力してMySQLのプロンプトを表示させます。

sudo mysql

MySQLのプロンプトで、以下の様に入力してデータベースとユーザーを作成します。(データベース名やユーザー名、パスワードはご自身の環境に合わせて適宜変更してください。)

create database YelpCampLaravel;
grant all privileges on YelpCampLaravel.* to laravel@'localhost' identified by 'password'; 
exit;

VSCodeでアプリフォルダ(YelpCampLaravel)内にある「.env」ファイルを開いて、23行目あたりから始まる項目のコメントをはずして以下の様に修正します。(データベース名やユーザー名、パスワードはご自身の環境に合わせて適宜変更してください。)

DB_CONNECTION=sqlite
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_DATABASE=laravel
# DB_USERNAME=root
# DB_PASSWORD=
↓
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=YelpCampLaravel
DB_USERNAME=laravel
DB_PASSWORD=password

VSCodeのターミナル画面に以下のコマンドを入力して先ほど作成したデータベースにアクセスできるか確認します。

php artisan migrate

VSCodeのターミナル画面に「php artisan serve」と入力してLaravelの開発用サーバーを起動します。ブラウザを起動して、URL欄に「localhost:8000」と入力して以下の様な画面が表示されれば正常に動作しています。

以上でひな型のセットアップは終了です。次のセクションから実装して行きます。

ビューを作成します

まずはメイン画面から作成してきます。LaravelはMVC形式でWEBアプリを作成できる様になっていて、それぞれの役割毎にファイルが作成される場所も決まっている様です。VSCodeのターミナル画面に以下のコマンドを入力してメイン画面を作成します。(この例ではhomeにしましたが、任意の名称が使用できます。)

php artisan make:view home

ビュー画面は、アプリフォルダ内の「resources/views」フォルダ内に「home.blade.php」というファイル名で作成されます。このファイルはブレードファイルと呼ばれていて、Node.jsのejsファイルの様にテンプレート的に使用できる様です。コマンドを使わずに手動でファイルを作成してもいい様です。(拡張子は「.blade.php」にします。)

resources
└─views
    └─home.blade.php

階層化(サブフォルダを作成)したい場合は以下の様に入力する様です。

php artisan make:view layouts/boilerplate

作成された「home.blade.php」ファイルにとりあえずYelpCampのメイン画面のHTMLソースをすべて張り付けて保存します。表示テスト用なのでブラウザで表示できれば何でも構いません。ひな型で作成された「welcome.blade.php」ファイルはもう使用しないので削除しておきます。

ドキュメントルート(localhost:8000)にアクセスするとこのファイルが表示されるように修正します。アプリフォルダ内の「routes/web.php」ファイルの5行目辺りにある項目を以下の様に修正します。

Route::get('/', function () {
    return view('welcome');
});
↓
Route::get('/', function () {
    return view('home');
});

開発用サーバーが起動していない場合は、VSCodeのターミナル画面に「php artisan serve」と入力してLaravelの開発用サーバーを起動します。ブラウザのURL欄に「localhost:8000」と入力して作成した画面が表示されるか確認します。まだスタイルを作成していないので表示が乱れていますが、以下の様な画面が表示されれば正常に動作しています。

テンプレートを作成します

残りの画面を作成して行きます。同じような画面がいくつもあるのでブレードファイルのテンプレート機能を使用して実装して行きます。ひな型となる親テンプレートは以下の様になっています。「@yield」というキーワードを使用して子テンプレートの要素を取り込みます。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@yield('title')</title>
</head>
<body>
    @yield('content')
</body>
</html>

子テンプレートは以下の様になっています。1行目で親となるテンプレートを指定しています。サブフォルダ内にある場合は「/」では無くてドット(.)で区切る様です。特に拡張子等は必要ない様です。2行目と6行目以降で親テンプレートに表示する項目を「@section」というキーワードで指定しています。この項目の第一引数で指定された文字列が親テンプレートの表示位置に対応しています。最後は「@endsection」というキーワードで終了します。

@extends('layouts.boilerplate')
@section('title', 'Not Found')

@section('content')
<div class="text-center my-5">
    <h1>お探しのページが見つかりませんでした。</h1>
</div>
@endsection

テンプレートを表示するには「view」関数の引数に「子テンプレート」名を指定します。web.phpファイルに以下の様な文字列を書き込んでアクセスすると、作成したテンプレート画面が表示されます。

Route::get('404', function () {
    return view('404');
});

ビューにデータを渡したい場合は、view関数の第2引数に連想配列形式で渡すようです。

view('campgrounds.index', ['data' => 'データ']);

残りの画面も同じ様な要領で実装して行きます。とりあえずファイルのみ作成しておきます。

コントローラーを作成します

コントローラーはビューから入力を受け取ってデータベースに保存したり、データベース内容を取得してビューに表示したりなどの、ユーザー(フロントエンド)とデータベース等(バックエンド)を仲介する役目を受け持ちます。コントローラーを作成するには、VSCodeのターミナル画面で以下の様に入力します。ファイル名の最後を「Controller」にするのが慣例(命名規約)になっている様です。

php artisan make:controller CampgroundsController

コントローラーファイルは、アプリフォルダ内の「app/Http/Controllers」フォルダ内に作成されます。

app
└─Http
    └─Controllers
        └─CampgroundsController.php

階層化(サブフォルダを作成)したい場合は以下の様に入力する様です。手動でファイルを作成してもいい様です。

php artisan make:controller Admin/HelloController

コントローラーと通信するにはweb.phpファイルに以下の様な文字列を書き込んでルーティングします。(例ではCampgroundsControllerクラスの「index」というメソッドを呼び出しています。)

use App\Http\Controllers\CampgroundsController;

Route::get('campgrounds', [CampgroundsController::class, 'index']);
または
Route::get('campgrounds', 'App\Http\Controllers\CampgroundsController@index');

CampgroundsControllerクラスは以下の様になっています。ユーザーから入力(送信)されたデータは、「Request」型の引数に格納された状態で渡されます。この引数はLaravelが自動で作成してくれる様です。必要に応じてRequestクラスの各種メソッドで入力データを取得します。英語のサイトになりますがこちらに使用できるメソッドの説明があります。

class CampgroundsController extends Controller
{
    public function index(Request $request)
    {
        $names = ['キャンプ場1', 'キャンプ場2', 'キャンプ場3'];

        return view('campgrounds.index', ['names' => $names]);
    }
}
モデルを作成します

モデルはデータベースにデータを保存したり、ビューに渡すデータ等を管理するクラスになっています。モデルを作成するにはVSCodeのターミナル画面に以下の様に入力します。

php artisan make:model Campground -m

モデルファイルは、アプリフォルダ内の「app/Models」フォルダ内に作成されます。

app
└─Models
    └─Campground.php

モデル作成時に「-m」オプションを付けたので、「マイグレーションファイル」と呼ばれるデータベースの構造(スキーマ)定義用のファイルも作成されます。マイグレーションファイルは以下の場所に「2025_04_24_023123_create_campgrounds_table.php」などの名称で作成されます。

database
└─migrations
    └─2025_04_24_023123_create_campgrounds_table.php

マイグレーションファイルの中身は以下の様になっていて、コードでデータベースの構造を定義します。マイグレーションファイルの構成や使用可能なメソッドはこちらのサイト様をご参照ください。

    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('campgrounds', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('location');
            $table->timestamps();
        });
    }

データベースの構造を修正した場合は、VSCodeのターミナル画面に以下のコマンドを入力するとデータテーブルを再構築してくれます。(使用しているデータベース内のすべてのテーブルを削除してから再構築するので実行するには注意が必要です。)

php artisan migrate:fresh

またモデルとマイグレーションはLaravelの「Eloquent」という機能で暗黙的に紐付けられています。この機能によりモデルに新たにプロパティ等を追加することなく、マイグレーションファイルで定義された項目名をモデルでそのまま使用できます。

上の例ではマイグレーションファイルに「name」、「location」等の項目が定義されているので「Campground」モデルに1行も追加することなく以下の様に使用できます。

    public function regist($camp_name)
    {
        $camp = new Campground;
        $camp->name = $camp_name;
        $camp->save();
    }

手動で作成して暗黙的に紐付けするためには、モデル名は「単数形」でマイグレーション(データテーブル名)は「複数形」にする必要がある様です。詳しい命名規約に付きましてはこちらのサイト様等をご参照ください。規約に従っていなくても、以下の様にモデル内で明示的に使用するテーブル名を指定する事もできる様です。

class Campground extends Model
{
    protected $table = 'my_campgrounds';
}

以上で基本的な作成方法が分かりましたので移植作業を続けます。

メッセージを日本語化します

まず最初に各種メッセージを日本語化しておきます。VSCodeのターミナル画面に以下のコマンドを入力して、アプリフォルダ内に「lang/en」フォルダを作成します。

php artisan lang:publish

次にターミナル画面で以下のコマンドを実行します。メッセージが表示されますのでyesかnoを入力すると、「lang/ja」フォルダ内に日本語のリソースが追加されます。

composer require askdkc/breezejp --dev
php artisan breezejp
JavaScriptとcssファイルを作成します

Laravelのドキュメントルートは「pulic」というフォルダになっていますが、初期状態ではスクリプトやスタイルファイルが配置されていないので、「モジュールバンドラー」と呼ばれるアプリを使用して配置する必要があります。以前のLaravelでは「Webpack」が使用されていたようですが、現在は「Vite(ヴィート)」というバンドラー(ビルドツール)が使用されている様です。Webpack(Laravel Mix)に戻すことも可能な様です。Viteを使用するにはVSCodeのターミナル画面に以下の様に入力してnpmパッケージをインストールする必要があります。

npm install

ターミナル画面に以下の様に入力するとViteが実行されます。

npm run build

実行が完了すると「public」フォルダ内に以下の様なファイルが作成されます。

public
└─build
    └─assets
        ├─app-CeaRPtlx.css
        └─app-T1DpEqax.js

各ファイル名にはハッシュ文字列が付加されます。ファイルが変更されるたびにハッシュ値が変わるので、ブラウザにキャッシュされない(確実に読み込まれる)様になっています。

しかしこのままではHTML(Blade)ファイルから読み込めないので、これらのファイルを読み込む場合は「@vite」ディレクティブを使用して以下の様な形式に変更する必要があります。

<head>
    <link rel="stylesheet" href="dist/css/home.css">
</head>
↓
<head>
    @vite('resources/css/home.css')
</head>

スクリプトファイルにハッシュ文字列を付けたくない(linkタグ等で読み込みたい)場合は、アプリフォルダ内にある「vite.config.js」というViteの設定ファイルに以下の様な設定を追加すると、生成ファイルにハッシュが追加されなくなる様です。

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import tailwindcss from '@tailwindcss/vite';

export default defineConfig({
    plugins: [
        laravel({
            input: ['resources/css/app.css', 'resources/js/app.js'],
            refresh: true,
        }),
        tailwindcss(),
    ],
    build: {
        outDir: 'public/dist',
        rollupOptions: {
            output: {
                assetFileNames: (assetInfo) => {
                    let extType = assetInfo.name.split('.').at(1);
                    if (/\.css$/.test(assetInfo.name)) {
                        return 'css/[name].[ext]';
                    }
                    return `assets/[name][extname]`;
                },
                chunkFileNames: 'js/[name].js',
                entryFileNames: 'js/[name].js',
            },
        },
    },
});

上記の設定でViteを実行(npm run build)すると以下の様なディレクトリとファイルが生成されます。(しかしこのスクリプトでは「bootstrap.min.css」というファイルも「bootstrap.css」というファイルに変換されてしまうので、もう少し工夫が必要です。または読み込み側の修正も必要と思われます。)

public
└─dist
    ├─css
    │   └─app.css
    └─js
        └─app.js

スタイルシートやスクリプトファイルを追加したい場合は、Webpackなどの様にワイルドカードは使用できない様なので、Laravelの「input」設定項目に直接追加する必要がある様です。(設定ファイル内に直接関数を書けば設定を動的に生成することも可能な様です。)

    plugins: [
        laravel({
            input: [
                'resources/css/app.css',
                'resources/css/bootstrap.min.css',
                'resources/css/home.css',
                'resources/css/stars.css',
                'resources/js/app.js',
                'resources/js/bootstrap.bundle.min.js',
                'resources/js/bootstrap.js',
                'resources/js/clusterMap.js',
                'resources/js/showPageMap.js',
                'resources/js/validateForms.js',
            ],
            refresh: true,
        }),
        tailwindcss(),
    ],
認証機能の追加

Laravelは豊富な認証機能を持っていて、ひな型にも最初からユーザーモデルが追加されています。少しのコードを追加するだけで簡単に認証機能が追加できます。「composer require laravel/breeze」というコマンドを実行すれば1行もコードを書かなくても認証機能が実装できます。しかし機能が豊富すぎて仕組みが良く分からないので、最低限何があれば認証してもらえるのか調べるために0から認証機能を実装して行きます。

ひな型で作られたモデルとマイグレーションファイル等を修正していくのは大変なので、以下のファイルをすべて削除します。

app
└─Models
    └─User.php

database
├─factories
│   └─UserFactory.php
└─migrations
    ├─0001_01_01_000000_create_users_table.php
    ├─0001_01_01_000001_create_cache_table.php
    └─0001_01_01_000002_create_jobs_table.php

VSCodeのターミナル画面に以下の様に入力してモデル、マイグレーションファイルとファクトリーファイルを新たに作成します。

php artisan make:model User -mf

作成されたマイグレーションファイルの「up」関数を以下の様に修正します。ひな型では「email」がユニーク(非重複)項目でしたが、今回はユーザー名(username)をユニークに設定しました。「id」項目は認証モデルでは必ず必要な様です。この項目が無いと認証時にエラーになる様です。

    public function up(): void
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('username')->unique();
            $table->string('email', 100);
            $table->string('password', 100);
        });
    }

「database/seeders/DatabaseSeeder.php」ファイルを開いて「run」関数を以下の様に修正して初期ユーザーを作成します。(ユーザー名等は任意の名称に変更してください。)

use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;

class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        User::factory()->create([
            'username' => 'test',
            'email' => 'test@test.com',
            'password' => Hash::make('test'),
        ]);
    }
}

モデルファイル「app/Models/User.php」を開いて、こちらのサイト様を参考にして以下の様に修正します。認証モデルは「Authenticatable」クラスを継承する必要がある様です。9行目の宣言はデータテーブルにタイムスタンプ(timestamps)項目が無い場合に必要です。またデータテーブルに「rememberToken」項目が定義されていない場合は、11~14行目の「getRememberTokenName」という空文字を返す関数を定義しておかないとログアウト時にエラーになる様です。

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class User extends Authenticatable
{
    /** @use HasFactory<\Database\Factories\UserFactory> */
    use HasFactory;

    public $timestamps = false;

    public function getRememberTokenName()
    {
        return '';
    }
}

VSCodeのターミナル画面に以下の様に入力してダミーデータを作成します。

php artisan migrate:fresh --seed

「.env」ファイルの23行目あたりにあるセッション設定を以下の様に変更します。

SESSION_DRIVER=database
↓
SESSION_DRIVER=cookie

以上で認証機能の実装は完了です。あとはコントローラーに以下の様なコードを記述すると認証される(セッションに保存される)様です。

    public function login(Request $request)
    {
        $data = $request->validate([
            'username' => ['required', 'string'],
            'password' => ['required', 'string'],
        ]);

        if (!User::where('username', $data['username'])->first()) {
            return back()->withErrors('ユーザー名が見つかりません')->onlyInput('username');
        }

        if (Auth::attempt($data)) {
            $request->session()->regenerate();
            return to_route('campgrounds')->with('message', 'おかえりなさい!!');
        }

        return back()->withErrors('パスワードが間違っています')->onlyInput('username');
    }

認証に成功するとブレードファイル内で「@auth」等のディレクティブが有効になるので、以下の様にユーザーとゲストを切り分けて表示することが可能です。

    <header class="mb-auto">
        <div>
            <h3 class="float-md-start mb-0">YelpCamp</h3>
            <nav class="nav nav-masthead justify-content-center float-md-end">
                <a href="#" class="nav-link active">ホーム</a>
                <a href="campgrounds" class="nav-link">キャンプ場</a>
                @auth
                <a href="logout" class="nav-link">ログアウト</a>
                @else
                <a href="login" class="nav-link">ログイン</a>
                <a href="register" class="nav-link">ユーザー登録</a>
                @endauth
            </nav>
        </div>
    </header>
ブレード(Blade)ファイルをデバッグするには

この記事等を参考にしてWSL2で「Xdebug」を使用できる様にしておきます。VSCodeには「PHP Debug」というプラグインをインストールしておきます。その後VSCodeでデバッガーを起動するために作業フォルダ内に「.vscode/launch.json」ファイルを作成して、以下の様な設定を書き込みます。

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen for Xdebug",
            "type": "php",
            "request": "launch",
            "port": 9003
        },
    ]
}

あとは「F5」キーを押してデバッグを開始すれば、コントローラーなどの純粋なPHPファイルでは設定されたブレークポイントで停止します。仮想環境のコンテナー等を使用していないので、追加のデバッグ設定は必要ありません。

ブレードファイル(user.blade.php等)はブレークポイントで停止しないので、こちらのサイト様の記事を参考に、停止したい場所に以下の文字列を追加します。

@php xdebug_break(); @phpend
または
<?php xdebug_break(); ?>

この状態でデバッグを行うと追加した文字列の次の行で停止しますので、後はブレードファイル内でもステップ実行や変数の参照等が可能になります。

ブレードファイルのデバッグは「storage/framework/views」フォルダ内に作成された一時ファイルが使用される様です。デバッグを行わなくてもLaravelを起動(ブレードファイルを修正)するたびに蓄積されていくので、適当なタイミングで一時ファイルを削除したほうがいいかもしれません。VSCodeのターミナル画面に以下のコマンドを入力すると一時ファイルを削除してくれる様です。

php artisan view:clear
Laravelを仮想ディレクトリで動作させるには

Apache2の設定ファイル「/etc/apache2/apache2.conf」を開き、ファイルの一番最後に以下の設定を追加します。仮想ディレクトリ名や実際に配置しているフォルダ名等はご自身の環境に合わせて適宜修正してください。

Alias /YelpCampLaravel /home/user01/YelpCampLaravel/public

<Directory /home/user01/YelpCampLaravel/public>
    Options Indexes FollowSymLinks
    AllowOverride All
    Require all granted
</Directory>

以降の設定はユーザー権限で行っていきます。現在のユーザー(user01)のグループに「www-data」ユーザーを追加します。この設定でブラウザからホームディレクトリ(/home/user01/YelpCampLaravel)内のファイルにアクセスできる様になります。ユーザー名はご自身の環境に合わせて適宜修正してください。

sudo usermod -a -G user01 www-data

グループが無いというエラーが出た場合は、以下の様に入力してグループを作成してから再度実行してください。

sudo addgroup user01
sudo adduser user01 user01

Apache2を再起動します。

sudo systemctl restart apache2

Laravelは表示(読み取り)だけでなく書き込みも行うので、以下のコマンドを入力して、所属しているグループに書き込み権限を付与します。この設定を行わないと「storage」フォルダへの書き込みができない様です。(WEBサーバーのドキュメントルート(/var/www/html)に配置する場合はこの設定の代わりに、所有者の変更(sudo chown -R www-data:www-data storage/)を行ってください。)

# /home/user01/YelpCampLaravel フォルダ内で実行してください。

sudo chmod -R 775 storage/

後はブレードファイル内のそれぞれのリンク個所に「asset」や「url」関数を追加しておけばLaravelが自動でアドレスを書き換えてくれる様です

<a href="{{ url('/campgrounds') }}">一覧に戻る</a>
<form action="{{ url('campgrounds') }}" method="POST" novalidate class="validated-form" enctype="multipart/form-data">
<form action="{{ asset('/') }}campgrounds/{{ $campground->id; }}" method="POST" novalidate class="validated-form"
移植作業メモ

移植作業中に躓いたことや、学習できたLaravelの機能等をメモとして残します。

・419 | Page Expired

ユーザー登録等でフォームデータを送信すると「419 | Page Expired」と表示されてサーバー(コントローラー)にデータが送信されません。Laravelではformタグブロック内に「@csrf」という文字列を追加する必要がある様です。なりすましによる不正なコードを実行させない様にするために必要な様です。

<form action="" method="POST">
    @csrf
    <label class="form-label" for="username">ユーザー名</label>
    <input class="form-control" type="text" name="username" id="username" autofocus required>
    <label class="form-label" for="email">メールアドレス</label>
    <input class="form-control" type="email" name="email" id="email" required>
    <button class="btn btn-success">登録する</button>
</form>
・送信データの検証

フォーム等から送信されたデータは、Request型にあるvalidate関数で以下の様に記述できる様です。Request引数はLaravelが自動的に作成してくれます。(検証(バリデーション)の詳細につきましてはこちらのサイト様をご参照ください。) validate関数の戻り値は検証済みの入力データの連想配列になっています。

class UsersController extends Controller
{
    function register(Request $request): void
    {
        $validated = $request->validate([
            'username' => ['required', 'string', 'max:255'],
            'email' => ['required', 'string', 'email', 'max:100'],
            'password' => ['required', 'string', 'max:100'],
        ]);
    }
}

バリデーションが失敗すると例外が発生して、ブラウザにエラーメッセージが送信されます。エラーメッセージは(日本語化した場合は)以下の場所にあるファイル内にある、検証したプロパティ名('required', 'string'等)に対応したメッセージが送信される様です。独自のメッセージを表示したい場合はvalidate関数の第2引数に設定できる様です。

lang
  └─ja
    └─validation.php
・エラーメッセージの表示

エラーメッセージはブラウザ側(ブレードファイル内)で以下の様に記述すると表示できる様です。

@if($errors->any())
    @foreach($errors->all() as $error)
    <div>{{ $error }}</div>
    @endforeach
@endif
・自分でエラーメッセージを作成するには

メソッド内で以下の様に記述すればいい様です。配列や連想配列も指定できる様です。(backは元のページに戻る関数になっています。redirect系の関数にも指定できる様です。)

return back()->withErrors('エラーが発生しました。');

「route」関数を使用したい場合は「withErrors」メソッドを持っていないので、以下の様にエラーメッセージをあらかじめ作成しておいてセッションに保存しておくと表示される様です。

    $messages = new Illuminate\Support\MessageBag;
    $messages->add('errors', 'ログイン済みです');
    Session::flash('errors', $messages);
    return route('campgrounds');
・正常(フラッシュ)メッセージの表示

処理の成功時に1回だけ表示する(フラッシュ)メッセージは、ブレードファイル内で以下の様に書くと表示できる様です。

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

コントローラーで以下の様にメッセージをセットしておけば表示される様です。

use Illuminate\Support\Facades\Session;

class UsersController extends Controller
{
    function register(Request $request)
    {
        Session::flash('message', '登録できました。');
    }
}

リダイレクト処理に追加する方法もある様です。

return redirect('campgrounds')->with('message','Yelp Campへようこそ!');
・データ保存時に「Column not found...」エラーがでる場合

データ保存時に「SQLSTATE[42S22]: Column not found: 1054 Unknown column 'updated_at' in 'INSERT INTO'...」の様なエラーが出るので検索してみたところ、こちらのサイト様に説明がありました。Eloquentモデルはデータ保存時に「created_at」と「updated_at」という項目を自動的に更新する様です。マイグレーションファイルのひな型にある「$table->timestamps()」というメソッドでこれらの項目が作成されている様です。もしこのメソッドを削除している場合はこのエラーが発生する様です。

    public function up(): void
    {
        Schema::create('tests', function (Blueprint $table) {
            $table->id();
            $table->timestamps();
        });
    }

このエラーを解消するにはマイグレーションファイルに「$table->timestamps()」メソッドを追加するか、もしくはタイムスタンプ機能が必要ない場合はモデルファイルに以下の項目を追加するとエラーが出なくなる様です。

class Test extends Model
{
    public $timestamps = false;
}
・ダミーデータの作成

Laravelにはダミーデータを作成する機能がある様です。VSCodeのターミナル画面に以下の様に入力すると作成されます。

php artisan migrate:fresh --seed

自分で追加したモデル(データテーブル)にダミーデータを作成したい場合は、以下の作業が必要な様です。

  1. ファクトリーファイルの作成
  2. DatabaseSeeder.phpファイル内に自分のモデル用の「create」関数を追加
  3. 自分のモデルに「use HasFactory」宣言を追加

1.まず以下のコマンドを実行してファクトリーファイルと呼ばれるファイルを作成します。

php artisan make:factory Campground

ファクトリーファイルはモデル作成時に「f」オプションで、マイグレーションファイルと同時に作成することもできる様です。

php artisan make:model Campground-mf

作成されたファクトリーファイルの「definition」関数内で「fake」等の関数を使用して項目名とダミーデータを連想配列形式で返す様です。この関数はダミーデータの個数分呼ばれます。

<?php
namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;

class CampgroundFactory extends Factory
{
    public function definition(): array
    {
        return [
            'title' => fake()->realText(100),
            'author' => 'test',
        ];
    }
}

2.「database/seeders/DatabaseSeeder.php」ファイル内ある「run」関数内に以下の設定を追加します。「create」関数の引数に項目名とデータの連想配列を渡すと、指定項目のダミーデータを上書きできます。(例では「author」項目のデータを’test’に固定しています。) 複数のダミーデータを作成したい場合は「factory(10)」などの様にfactory関数の引数に作成個数を指定します。

<?php

namespace Database\Seeders;

use App\Models\User;
use App\Models\Campground;
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        User::factory()->create([
            'username' => 'test',
            'email' => 'test@test.com',
            'password' => 'test',
        ]);
        Campground::factory(10)->create([
            'author' => 'test',
        ]);
    }
}

3.モデルファイルに「use HasFactory」宣言を追加します。

<?php

namespace App\Models;

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

class Campground extends Model
{
    use HasFactory;
}
・Laravelプロジェクトに自作のヘルパー関数を追加するには

プロジェクト全体でいつでも呼び出せるヘルパー関数を追加したい場合は、こちらのサイト様を参考に以下の様にすると登録できるようです。

「app」フォルダー以下に「helpers.php」というファイルを作成してヘルパー関数を作成します。

<?php

function myHelperFunc()
{
    // 何かの処理を行います;
}

プロジェクトフォルダ内にある「composer.json」ファイルの「autoload」セクションに以下の設定を追加します。

    "autoload": {
        "files": [
            "app/helpers.php"
        ],
        "psr-4": {
            "App\\": "app/",
            "Database\\Factories\\": "database/factories/",
            "Database\\Seeders\\": "database/seeders/"
        }
    },

最後にVSCodeのターミナル画面で以下のコマンド実行すると、プロジェクト全体で使用できる様になります。

composer dump-autoload -o
・ログイン時に認証エラーが発生する場合

デフォルトで作成されたユーザーモデル(User)を使用する場合は問題ありませんが、自分でUserモデルを作成した場合は以下の様なエラーが発生する場合があります。

エラー内容で検索してたところ、こちらのサイト様に説明がありました。認証に使用するモデルは「Model」クラスではなく「Authenticatable」クラスから継承する必要がある様です。

use Illuminate\Database\Eloquent\Model;
class User extends Model {
↓
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable {
・認証ミドルウェアをカスタマイズするには

Laravelではログインが必要なページのルーティングは以下の様に記述する様です。

Route::get('campgrounds/new', [CampgroundsController::class, 'new'])->middleware('auth');

まだ認証されていないユーザーがこのページにアクセスするとデフォルトでは「login」ページにリダイレクトされます。リダイレクトの際に何かメッセージを表示するなどデフォルトの動作を変更したい場合は、Laravel 11 以上をお使いであれば「bootstrap/app.php」ファイルを以下の様に修正してリダイレクト処理をカスタマイズできる様です。(このメモはこちらのサイト様を参考にさせて頂きました。)

use Illuminate\Http\Request;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__ . '/../routes/web.php',
        commands: __DIR__ . '/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->redirectGuestsTo(function (Request $request) {
            redirect('login')->withErrors('ログインしてください');
        });
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })->create();

逆に認証されているユーザーをリダイレクトするには以下の様に記述する様です。

    ->withMiddleware(function (Middleware $middleware) {
        $middleware->redirectUsersTo('campgrounds');
        // または
        $middleware->redirectUsersTo(fn(Request $request) => route('campgrounds'));
    })

リダイレクト時にメッセージ表示したい場合は、route関数以外の戻り値を受け付けないので以下の様にすると良いかもしれません。(もっといい方法がありそうな気がしますが...)

    ->withMiddleware(function (Middleware $middleware) {
        $middleware->redirectUsersTo(function (Request $request) {
            $messages = new Illuminate\Support\MessageBag;
            $messages->add('errors', 'ログイン済みです');
            Session::flash('errors', $messages);
            return route('campgrounds');
        });
    })

エラーではなくて単なるメッセージにしたい場合はもう少し簡潔に記述できます。

    ->withMiddleware(function (Middleware $middleware) {
        $middleware->redirectUsersTo(function (Request $request) {
            Session::flash('message', 'ログイン済みです');
            return route('campgrounds');
        });
    })

認証されているユーザーをリダイレクトするには、ルーティングに以下のミドルウェアを追加する必要がある様です。

Route::get('login', [UsersController::class, 'index'])->middleware('guest');
・URLパラメータのタイプを制限するには

URLの一部がパラメータになっていて、なおかつパラメータのタイプを制限したい場合は以下の様にする様です。(以下の例では「id」を数値に限定しています。)

Route::get('campgrounds/{id}', [CampgroundsController::class, 'show'])->where('id', '[0-9]+');
または
Route::get('campgrounds/{id}', [CampgroundsController::class, 'show'])->whereNumber('id');

同様なルーティングが増えた場合は毎回指定するのは大変なので、「app/Providers/AppServiceProvider.php」ファイル内の「boot」関数に以下の様な文字列を追加しておくとパラメータ文字列のタイプを固定できる様です。

    public function boot(): void
    {
        Route::pattern('id', '[0-9]+');
    }
その他

こちらから今回作成したアプリをダウンロードできます。(実際に動作させるにはMySQL、Composerのセットアップが必要です。開発するにはnpm(Node.js)のセットアップも必要です。記事の最初の部分を参考にしてセットアップしてください。) 圧縮ファイルを展開してできたフォルダ「YelpCampLaravel」をVSCodeで開いて、「Ctrl + @」と入力してターミナル画面を表示します。ターミナル画面に以下の様に入力してMySQLのプロンプトを表示させます。

sudo mysql

MySQLのプロンプトで、以下の様に入力してデータベースとユーザーを作成してプロンプトを終了します。

create database YelpCampLaravel;
grant all privileges on YelpCampLaravel.* to laravel@'localhost' identified by 'password'; 
exit;

続いて以下の様にターミナル画面に入力すればセットアップは完了です。

composer install
php artisan migrate:fresh --seed
php artisan storage:link
php artisan serve

実際に画像をアップロードする場合は以下の設定も必要です。

sudo usermod -a -G user01 www-data
sudo chmod -R 775 storage/

または
sudo chmod -R 777 storage/

後はブラウザのURL欄に「localhost:8000」と入力するとYelpCampLaravelアプリが表示されます。10件程度の架空のキャンプ場とユーザー名「test」、パスワード「test」というユーザーが初期状態で登録されています。

サムネイル画像の作成と地図を表示するには、こちらの記事を参考にして「Imagick」というソフトのインストールと、「Mapbox」のユーザー登録が必要です。どちらも無料で使用できますが、Mapboxは25,000回/月まで無料という制限があります。MapboxのAPIキー(アクセストークン)は「.env」ファイル最後の方にある以下の場所に設定します。

#ここにアクセストークンをコピーしてください。
MAPBOX_TOKEN="pk.xxxx..." 

MAMPでも動作する様です。MAMPで実行したい場合はこちらの記事を参考にデータベースを作成してください。

以上です。よろしかったらお試しください。