Laravel 10 入門トップページ


目次

  1. 全体の概要
  2. Laravel によるユーザ認証
  3. ユーザ認証を備えたコメント掲示板の開発
    1. 概要
    2. データベースのマイグレーション
    3. シーダによるコメントデータの登録
    4. モデルとコントローラの生成
    5. ルートの定義と確認
    6. 未検証ユーザの動作検証
    7. コメントの一覧表示
    8. ナビゲーションメニューの追加
    9. コメント一覧の Tailwind CSS によるスタイリング
    10. コメントの詳細ページ
    11. リレーションシップの設定と投稿者名の表示
    12. ページネーションの作成
    13. コメントの投稿
    14. コメントの編集
    15. コメントの削除
    16. ナビゲーションのハイライトを調整
  4. マルチ認証の実現

Laravel でユーザ認証とマルチ認証を実現する

ユーザ認証を備えたコメント掲示板の開発

コメントの投稿

次はコメントの投稿機能を実装します.以前に開発した(認証機能のない)コメント掲示板との大きな違いは投稿時に投稿者(ログイン中のユーザ)の user_id を格納することです.

まず,投稿画面と投稿処理(データベースへの保存処理)のための2つのルートを定義します.もちろん投稿処理は POST メソッドを利用することに注意してください.

routes/web.php(抜粋)
Route::middleware('auth', 'verified')->group(function () {
    Route::get('/comments', [CommentController::class, 'index'])->name('comments.index');
    Route::get('/comments/create', [CommentController::class, 'create'])->name('comments.create');
    Route::get('/comments/{comment_id}', [CommentController::class, 'show'])->name('comments.show');
    Route::post('/comments', [CommentController::class, 'store'])->name('comments.store');
});

コントローラに createstore 関数を定義します.33行目のようにログイン中のユーザを取得することができるので,そのユーザ情報を35行目でビューに渡します.また,store 関数はこれから作成するフォームから送信されたリクエストデータをそのまま表示するだけのコードにしておきます.

app/Http/Controllers/CommentController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Models\Comment;

class CommentController extends Controller
{
    public function index()
    {
        $comments = Comment::orderBy('updated_at','DESC')
                    ->paginate(3);
        // dd($comments);
        return view('comments.index')
                ->with('comments', $comments);
    }

    public function show($comment_id)
    {
        $comment = Comment::where('id', '=', $comment_id)
                ->first();
        if (!$comment) {
            return redirect('/comments');
        }
        return view('comments.show')
                ->with('comment', $comment);
    }

    public function create()
    {
        $user = Auth::user();
        return view('comments.create')
                ->with('user', $user);
    }

    public function store(Request $request)
    {
        dd($request);
    }
}

投稿ページのビューを作成します.この16行目には,「コメントの投稿」ボタンを押した時にはルート定義 (routes/web.php) の namecomments.store である /comments に,POST メソッドでデータが送信されることを指定しています.また,POST メソッド利用時には17行目のように CSRF トークンを仕込むことがセキュリティを確保する意味でも必須です.

resources/views/comments/create.blade.php
<x-app-layout>
    <x-slot name="header">
        <h2 class="font-semibold text-xl text-gray-800 leading-tight">
            {{ __('Create Comment') }}
        </h2>
    </x-slot>

    <div class="py-12">
        <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
            <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
                <div class="p-6 text-gray-900">
                    <div class="my-2 border border-gray-300 rounded-md p-3">
                        <div class="text-sm text-gray-700">投稿者:</div>
                        <div class="text-base text-gray-800 indent-4">{{ $user->name }}</div>

                        <form method="POST" action="{{ route('comments.store') }}">
                            @csrf

                            <div class="mt-2">
                                <x-input-label for="title" :value="__('タイトル')" />
                                <x-text-input id="title" class="block mt-1 w-full" type="text" name="title" value="{{ old('title') }}" placeholder="コメントのタイトルを入力してください" required autofocus />
                                <x-input-error :messages="$errors->get('title')" class="mt-2" />
                            </div>

                            <div class="mt-2">
                                <x-input-label for="body" :value="__('本文')" />
                                <textarea id="body"
                                class="block mt-1 mb-2 w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm"
                                type="text" name="body" rows="3" maxlength="250" placeholder="コメントの本文を入力してください">{{ old('body') }}</textarea>
                                <x-input-error :messages="$errors->get('body')" class="mt-2" />
                            </div>


                            <x-primary-button class="block w-full mt-2">
                                {{ __('コメントの投稿') }}
                            </x-primary-button>

                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
</x-app-layout>

一覧ページにコメント投稿ページへのリンクを作成します.慣れないうちは面倒ですが,Tailwind CSS のスタイルも確実に指定をしておきます.

resources/views/comments/index.blade.php
<x-app-layout>
    <x-slot name="header">
        <h2 class="font-semibold text-xl text-gray-800 leading-tight">
            {{ __('Comments') }}
        </h2>
    </x-slot>

    <div class="py-12">
        <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
            <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
                <div class="p-6 text-gray-900">
                    <div class="text-base">
                        <a href="{{ route('comments.create') }}" class="text-blue-500 hover:text-blue-800 hover:underline active:text-blue-900 active:bg-gray-200 transition ease-in-out duration-150">
                            コメントの投稿
                        </a>
                    </div>
                    @foreach ($comments as $comment)
                        <div class="my-2 border border-gray-300 rounded-md p-3">
                            <div class="text-sm text-gray-700">{{ $comment->user->name }}</div>
                            <div class="font-semibold">
                                <a href="{{ route('comments.show', $comment->id) }}" class="text-blue-500 hover:text-blue-800 hover:underline active:text-blue-900 active:bg-gray-200 transition ease-in-out duration-150">
                                    {{ $comment->title }}
                                </a>
                            </div>
                            <div class="text-sm text-gray-700">{{ $comment->body }}</div>
                        </div>
                    @endforeach
                    {{ $comments->links() }}
                </div>
            </div>
        </div>
    </div>
</x-app-layout>

コメント一覧ページを表示し,「コメントの投稿」リンクをクリックします.

laravel10-2023-auth-77.png

投稿ページのフォームにはプレースホルダーとして「コメントのタイトルを入力して下さい」というような説明があらかじめ表示されています.

laravel10-2023-auth-78.png

タイトルと本文に文字列を入力して「コメントの投稿」ボタンをクリックします.

laravel10-2023-auth-79.png

フォームから送信された内容を確認することができました.

laravel10-2023-auth-80.png

コントローラの store 関数に投稿内容をデータベースに保存する処理を記載します.保存する前にフォームに入力された内容を検証するコードも追加しています.手動でのテストを行いやすいように4行目でタイトルは最大10文字に設定しています.また,7行目でログイン中のユーザ情報を取得して,11行目でその ID を user_id にセットしています.

app/Http/Controllers/CommentController.php(抜粋)
    public function store(Request $request)
    {
        $this->validate($request, [
            'title' => 'required|max:10',
            'body'  => 'required|max:250'
        ]);
        $user = Auth::user();
        $comment = new Comment();
        $comment->title = $request->title;
        $comment->body = $request->body;
        $comment->user_id = $user->id;  // 投稿者のIDをセット
        $comment->save();
        return redirect('/comments');
    }

実際に投稿処理を行った結果,一覧表示が次のようになりました.

laravel10-2023-auth-81.png

詳細ページも確認します.

laravel10-2023-auth-82.png

さらに SQLite を操作して,データベースの内容を確認します.ログイン中のユーザの ID も正しく登録されているはずです.

sqlite> SELECT * FROM comments ORDER BY updated_at DESC LIMIT 5; ⏎
id|title|body|user_id|created_at|updated_at
101|タイトルです|コメントの本文を入力します|1|2023-11-05 09:40:34|2023-11-05 09:40:34
39|中島 修平|2245959  京都府若松市西区斉藤町井高2-8-7 ハイツ渚106号 / yamaguchi.minoru@example.com|3|2023-08-30 03:05:17|2023-09-30 22:27:52
64|中津川 七夏|2629310  愛知県加納市北区大垣町近藤7-1-10 / mtanabe@example.net|1|2023-08-30 06:00:30|2023-09-30 19:44:06
4|青山 和也|6606211  愛知県廣川市西区渚町桐山7-10-1 コーポ笹田110号 / nakajima.kazuya@example.net|1|2023-08-30 00:00:00|2023-09-30 17:40:27
99|加藤 翔太|3107803  山形県青山市南区村山町西之園2-2-9 ハイツ井高109号 / ryohei.ogaki@example.org|3|2023-08-30 09:05:47|2023-09-30 06:28:02
sqlite>

目次に戻る